#ifndef SERVER
#include "clientmap.h"
#include "localplayer.h"
+#include "mapblock_mesh.h"
#include "event.h"
#endif
#include "daynightratio.h"
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)
- {
+ for(std::vector<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
delete (*i);
}
}
{
DSTACK(__FUNCTION_NAME);
- for(std::list<Player*>::iterator i = m_players.begin();
+ for(std::vector<Player*>::iterator i = m_players.begin();
i != m_players.end();)
{
Player *player = *i;
void Environment::removePlayer(const char *name)
{
- for (std::list<Player*>::iterator it = m_players.begin();
+ for (std::vector<Player*>::iterator it = m_players.begin();
it != m_players.end(); ++it) {
if (strcmp((*it)->getName(), name) == 0) {
delete *it;
Player * Environment::getPlayer(u16 peer_id)
{
- for(std::list<Player*>::iterator i = m_players.begin();
- i != m_players.end(); ++i)
- {
+ for(std::vector<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
Player *player = *i;
if(player->peer_id == peer_id)
return player;
Player * Environment::getPlayer(const char *name)
{
- for(std::list<Player*>::iterator i = m_players.begin();
- i != m_players.end(); ++i)
- {
+ for(std::vector<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
Player *player = *i;
if(strcmp(player->getName(), name) == 0)
return player;
Player * Environment::getRandomConnectedPlayer()
{
- std::list<Player*> connected_players = getPlayers(true);
+ std::vector<Player*> connected_players = getPlayers(true);
u32 chosen_one = myrand() % connected_players.size();
u32 j = 0;
- for(std::list<Player*>::iterator
+ for(std::vector<Player*>::iterator
i = connected_players.begin();
- i != connected_players.end(); ++i)
- {
- if(j == chosen_one)
- {
+ i != connected_players.end(); ++i) {
+ if(j == chosen_one) {
Player *player = *i;
return player;
}
Player * Environment::getNearestConnectedPlayer(v3f pos)
{
- std::list<Player*> connected_players = getPlayers(true);
+ std::vector<Player*> connected_players = getPlayers(true);
f32 nearest_d = 0;
Player *nearest_player = NULL;
- for(std::list<Player*>::iterator
+ for(std::vector<Player*>::iterator
i = connected_players.begin();
- i != connected_players.end(); ++i)
- {
+ i != connected_players.end(); ++i) {
Player *player = *i;
f32 d = player->getPosition().getDistanceFrom(pos);
- if(d < nearest_d || nearest_player == NULL)
- {
+ if(d < nearest_d || nearest_player == NULL) {
nearest_d = d;
nearest_player = player;
}
return nearest_player;
}
-std::list<Player*> Environment::getPlayers()
+std::vector<Player*> Environment::getPlayers()
{
return m_players;
}
-std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
+std::vector<Player*> Environment::getPlayers(bool ignore_disconnected)
{
- std::list<Player*> newlist;
- for(std::list<Player*>::iterator
+ std::vector<Player*> newlist;
+ for(std::vector<Player*>::iterator
i = m_players.begin();
- i != m_players.end(); ++i)
- {
+ i != m_players.end(); ++i) {
Player *player = *i;
- if(ignore_disconnected)
- {
+ if(ignore_disconnected) {
// Ignore disconnected players
if(player->peer_id == 0)
continue;
{
if(m_enable_day_night_ratio_override)
return m_day_night_ratio_override;
- bool smooth = g_settings->getBool("enable_shaders");
- return time_to_daynight_ratio(m_time_of_day_f*24000, smooth);
+ return time_to_daynight_ratio(m_time_of_day_f*24000, m_cache_enable_shaders);
}
void Environment::setTimeOfDaySpeed(float speed)
}
}
-void ActiveBlockList::update(std::list<v3s16> &active_positions,
+void ActiveBlockList::update(std::vector<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();
+ for(std::vector<v3s16>::iterator i = active_positions.begin();
i != active_positions.end(); ++i)
{
fillRadiusBlock(*i, radius, newlist);
//calculate normalized direction vector
v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
- (pos2.Y - pos1.Y)/distance,
- (pos2.Z - pos1.Z)/distance);
+ (pos2.Y - pos1.Y)/distance,
+ (pos2.Z - pos1.Z)/distance);
//find out if there's a node on path between pos1 and pos2
for (float i = 1; i < distance; i += stepsize) {
std::string players_path = m_path_world + DIR_DELIM "players";
fs::CreateDir(players_path);
- for (std::list<Player*>::iterator it = m_players.begin();
+ for (std::vector<Player*>::iterator it = m_players.begin();
it != m_players.end();
++it) {
RemotePlayer *player = static_cast<RemotePlayer*>(*it);
Player *ServerEnvironment::loadPlayer(const std::string &playername)
{
- std::string players_path = m_path_world + DIR_DELIM "players";
+ std::string players_path = m_path_world + DIR_DELIM "players" DIR_DELIM;
RemotePlayer *player = static_cast<RemotePlayer*>(getPlayer(playername.c_str()));
bool newplayer = false;
- bool foundplayer = false;
+ bool found = false;
if (!player) {
- player = new RemotePlayer(m_gamedef);
+ player = new RemotePlayer(m_gamedef, playername.c_str());
newplayer = true;
}
- std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
- for (u32 i = 0; i < player_files.size(); i++) {
- if (player_files[i].dir)
- continue;
-
- // Full path to this file
- std::string path = players_path + "/" + player_files[i].name;
-
- // Load player to see what is its name
+ RemotePlayer testplayer(m_gamedef, "");
+ std::string path = players_path + playername;
+ for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
+ // Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
if (!is.good()) {
- infostream << "Failed to read " << path << std::endl;
- continue;
+ return NULL;
}
- player->deSerialize(is, player_files[i].name);
-
- if (!string_allowed(player->getName(), PLAYERNAME_ALLOWED_CHARS)) {
- infostream << "Not loading player with invalid name: "
- << player->getName() << std::endl;
- continue;
- }
-
- if (player->getName() == playername) {
- // We found our player
- foundplayer = true;
+ testplayer.deSerialize(is, path);
+ is.close();
+ if (testplayer.getName() == playername) {
+ *player = testplayer;
+ found = true;
break;
}
-
+ path = players_path + playername + itos(i);
}
- if (!foundplayer) {
+ if (!found) {
+ infostream << "Player file for player " << playername
+ << " not found" << std::endl;
return NULL;
}
if (newplayer) {
addPlayer(player);
}
+ player->setModified(false);
return player;
}
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
- if(is.good() == false)
- {
- infostream<<"ServerEnvironment::loadMeta(): Failed to open "
- <<path<<std::endl;
+ if (!is.good()) {
+ infostream << "ServerEnvironment::loadMeta(): Failed to open "
+ << path << std::endl;
throw SerializationError("Couldn't load env meta");
}
Settings args;
-
- for(;;)
- {
- if(is.eof())
- throw SerializationError
- ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
- std::string line;
- std::getline(is, line);
- std::string trimmedline = trim(line);
- if(trimmedline == "EnvArgsEnd")
- break;
- args.parseConfigLine(line);
+
+ if (!args.parseConfigLines(is, "EnvArgsEnd")) {
+ throw SerializationError("ServerEnvironment::loadMeta(): "
+ "EnvArgsEnd not found!");
}
-
- try{
+
+ try {
m_game_time = args.getU64("game_time");
- }catch(SettingNotFoundException &e){
+ } catch (SettingNotFoundException &e) {
// Getting this is crucial, otherwise timestamps are useless
throw SerializationError("Couldn't load env meta game_time");
}
- try{
+ try {
m_time_of_day = args.getU64("time_of_day");
- }catch(SettingNotFoundException &e){
+ } catch (SettingNotFoundException &e) {
// This is not as important
m_time_of_day = 9000;
}
{
private:
ServerEnvironment *m_env;
- std::map<content_t, std::list<ActiveABM> > m_aabms;
+ std::map<content_t, std::vector<ActiveABM> > m_aabms;
public:
ABMHandler(std::list<ABMWithState> &abms,
float dtime_s, ServerEnvironment *env,
k != ids.end(); k++)
{
content_t c = *k;
- std::map<content_t, std::list<ActiveABM> >::iterator j;
+ std::map<content_t, std::vector<ActiveABM> >::iterator j;
j = m_aabms.find(c);
if(j == m_aabms.end()){
- std::list<ActiveABM> aabmlist;
+ std::vector<ActiveABM> aabmlist;
m_aabms[c] = aabmlist;
j = m_aabms.find(c);
}
content_t c = n.getContent();
v3s16 p = p0 + block->getPosRelative();
- std::map<content_t, std::list<ActiveABM> >::iterator j;
+ std::map<content_t, std::vector<ActiveABM> >::iterator j;
j = m_aabms.find(c);
if(j == m_aabms.end())
continue;
- for(std::list<ActiveABM>::iterator
- i = j->second.begin(); i != j->second.end(); i++)
- {
+ for(std::vector<ActiveABM>::iterator
+ i = j->second.begin(); i != j->second.end(); i++) {
if(myrand() % i->chance != 0)
continue;
{
INodeDefManager *ndef = m_gamedef->ndef();
MapNode n_old = m_map->getNodeNoEx(p);
+
// Call destructor
- if(ndef->get(n_old).has_on_destruct)
+ if (ndef->get(n_old).has_on_destruct)
m_script->node_on_destruct(p, n_old);
+
// Replace node
- bool succeeded = m_map->addNodeWithEvent(p, n);
- if(!succeeded)
+ if (!m_map->addNodeWithEvent(p, n))
return false;
+
+ // Update active VoxelManipulator if a mapgen thread
+ m_map->updateVManip(p);
+
// Call post-destructor
- if(ndef->get(n_old).has_after_destruct)
+ if (ndef->get(n_old).has_after_destruct)
m_script->node_after_destruct(p, n_old);
+
// Call constructor
- if(ndef->get(n).has_on_construct)
+ if (ndef->get(n).has_on_construct)
m_script->node_on_construct(p, n);
+
return true;
}
{
INodeDefManager *ndef = m_gamedef->ndef();
MapNode n_old = m_map->getNodeNoEx(p);
+
// Call destructor
- if(ndef->get(n_old).has_on_destruct)
+ if (ndef->get(n_old).has_on_destruct)
m_script->node_on_destruct(p, n_old);
+
// Replace with air
// This is slightly optimized compared to addNodeWithEvent(air)
- bool succeeded = m_map->removeNodeWithEvent(p);
- if(!succeeded)
+ if (!m_map->removeNodeWithEvent(p))
return false;
+
+ // Update active VoxelManipulator if a mapgen thread
+ m_map->updateVManip(p);
+
// Call post-destructor
- if(ndef->get(n_old).has_after_destruct)
+ if (ndef->get(n_old).has_after_destruct)
m_script->node_after_destruct(p, n_old);
+
// Air doesn't require constructor
return true;
}
bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
{
- return m_map->addNodeWithEvent(p, n, false);
+ if (!m_map->addNodeWithEvent(p, n, false))
+ return false;
+
+ // Update active VoxelManipulator if a mapgen thread
+ m_map->updateVManip(p);
+
+ return true;
}
std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
{
infostream<<"ServerEnvironment::clearAllObjects(): "
<<"Removing all active objects"<<std::endl;
- std::list<u16> objects_to_remove;
+ std::vector<u16> objects_to_remove;
for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.begin();
- i != m_active_objects.end(); ++i)
- {
+ i != m_active_objects.end(); ++i) {
ServerActiveObject* obj = i->second;
if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue;
// Id to be removed from m_active_objects
objects_to_remove.push_back(id);
}
+
// Remove references from m_active_objects
- for(std::list<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i)
- {
+ for(std::vector<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i) {
m_active_objects.erase(*i);
}
// Get list of loaded blocks
- std::list<v3s16> loaded_blocks;
+ std::vector<v3s16> loaded_blocks;
infostream<<"ServerEnvironment::clearAllObjects(): "
<<"Listing all loaded blocks"<<std::endl;
m_map->listAllLoadedBlocks(loaded_blocks);
<<loaded_blocks.size()<<std::endl;
// Get list of loadable blocks
- std::list<v3s16> loadable_blocks;
+ std::vector<v3s16> loadable_blocks;
infostream<<"ServerEnvironment::clearAllObjects(): "
<<"Listing all loadable blocks"<<std::endl;
m_map->listAllLoadableBlocks(loadable_blocks);
<<", now clearing"<<std::endl;
// Grab a reference on each loaded block to avoid unloading it
- for(std::list<v3s16>::iterator i = loaded_blocks.begin();
- i != loaded_blocks.end(); ++i)
- {
+ for(std::vector<v3s16>::iterator i = loaded_blocks.begin();
+ i != loaded_blocks.end(); ++i) {
v3s16 p = *i;
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
assert(block);
u32 num_blocks_checked = 0;
u32 num_blocks_cleared = 0;
u32 num_objs_cleared = 0;
- for(std::list<v3s16>::iterator i = loadable_blocks.begin();
- i != loadable_blocks.end(); ++i)
- {
+ for(std::vector<v3s16>::iterator i = loadable_blocks.begin();
+ i != loadable_blocks.end(); ++i) {
v3s16 p = *i;
MapBlock *block = m_map->emergeBlock(p, false);
if(!block){
m_map->unloadUnreferencedBlocks();
// Drop references that were added above
- for(std::list<v3s16>::iterator i = loaded_blocks.begin();
- i != loaded_blocks.end(); ++i)
- {
+ for(std::vector<v3s16>::iterator i = loaded_blocks.begin();
+ i != loaded_blocks.end(); ++i) {
v3s16 p = *i;
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
assert(block);
*/
{
ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
- for(std::list<Player*>::iterator i = m_players.begin();
+ for(std::vector<Player*>::iterator i = m_players.begin();
i != m_players.end(); ++i)
{
Player *player = *i;
/*
Get player block positions
*/
- std::list<v3s16> players_blockpos;
- for(std::list<Player*>::iterator
+ std::vector<v3s16> players_blockpos;
+ for(std::vector<Player*>::iterator
i = m_players.begin();
- i != m_players.end(); ++i)
- {
+ i != m_players.end(); ++i) {
Player *player = *i;
// Ignore disconnected players
if(player->peer_id == 0)
continue;
+
v3s16 blockpos = getNodeBlockPos(
floatToInt(player->getPosition(), BS));
players_blockpos.push_back(blockpos);
i != m_active_objects.end(); ++i)
{
ServerActiveObject* obj = i->second;
- // Remove non-peaceful mobs on peaceful mode
- if(g_settings->getBool("only_peaceful_mobs")){
- if(!obj->isPeaceful())
- obj->m_removed = true;
- }
// Don't step if is to be removed or stored statically
if(obj->m_removed || obj->m_pending_deactivation)
continue;
inside a radius around a position
*/
void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
+ s16 player_radius,
std::set<u16> ¤t_objects,
std::set<u16> &added_objects)
{
v3f pos_f = intToFloat(pos, BS);
f32 radius_f = radius * BS;
+ f32 player_radius_f = player_radius * BS;
+
+ if (player_radius_f < 0)
+ player_radius_f = 0;
+
/*
Go through the object list,
- discard m_removed objects,
// Discard if removed or deactivating
if(object->m_removed || object->m_pending_deactivation)
continue;
- if(object->unlimitedTransferDistance() == false){
+
+ f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
+ if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
// Discard if too far
- f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
- if(distance_f > radius_f)
+ if (distance_f > player_radius_f && player_radius_f != 0)
continue;
- }
+ } else if (distance_f > radius_f)
+ continue;
+
// Discard if already on current_objects
std::set<u16>::iterator n;
n = current_objects.find(id);
inside a radius around a position
*/
void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
+ s16 player_radius,
std::set<u16> ¤t_objects,
std::set<u16> &removed_objects)
{
v3f pos_f = intToFloat(pos, BS);
f32 radius_f = radius * BS;
+ f32 player_radius_f = player_radius * BS;
+
+ if (player_radius_f < 0)
+ player_radius_f = 0;
+
/*
Go through current_objects; object is removed if:
- object is not found in m_active_objects (this is actually an
continue;
}
- // If transfer distance is unlimited, don't remove
- if(object->unlimitedTransferDistance())
- continue;
-
f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
-
- if(distance_f >= radius_f)
- {
- removed_objects.insert(id);
+ if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ if (distance_f <= player_radius_f || player_radius_f == 0)
+ continue;
+ } else if (distance_f <= radius_f)
continue;
- }
-
- // Not removed
+
+ // Object is no longer visible
+ removed_objects.insert(id);
}
}
*/
void ServerEnvironment::removeRemovedObjects()
{
- std::list<u16> objects_to_remove;
+ std::vector<u16> objects_to_remove;
for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.begin();
- i != m_active_objects.end(); ++i)
- {
+ i != m_active_objects.end(); ++i) {
u16 id = i->first;
ServerActiveObject* obj = i->second;
// This shouldn't happen but check it
// Delete
if(obj->environmentDeletes())
delete obj;
+
// Id to be removed from m_active_objects
objects_to_remove.push_back(id);
}
// Remove references from m_active_objects
- for(std::list<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i)
- {
+ for(std::vector<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i) {
m_active_objects.erase(*i);
}
}
*/
void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
{
- if(block==NULL)
+ if(block == NULL)
return;
+
// Ignore if no stored objects (to not set changed flag)
- if(block->m_static_objects.m_stored.size() == 0)
+ if(block->m_static_objects.m_stored.empty())
return;
verbosestream<<"ServerEnvironment::activateObjects(): "
<<"activating objects of block "<<PP(block->getPos())
}
// Activate stored objects
- std::list<StaticObject> new_stored;
+ std::vector<StaticObject> new_stored;
for(std::list<StaticObject>::iterator
i = block->m_static_objects.m_stored.begin();
- i != block->m_static_objects.m_stored.end(); ++i)
- {
- /*infostream<<"Server: Creating an active object from "
- <<"static data"<<std::endl;*/
+ i != block->m_static_objects.m_stored.end(); ++i) {
StaticObject &s_obj = *i;
+
// Create an active object from the data
ServerActiveObject *obj = ServerActiveObject::create
- (s_obj.type, this, 0, s_obj.pos, s_obj.data);
+ ((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data);
// If couldn't create object, store static data back.
- if(obj==NULL)
- {
+ if(obj == NULL) {
errorstream<<"ServerEnvironment::activateObjects(): "
<<"failed to create active object from static object "
<<"in block "<<PP(s_obj.pos/BS)
// Clear stored list
block->m_static_objects.m_stored.clear();
// Add leftover failed stuff to stored list
- for(std::list<StaticObject>::iterator
+ for(std::vector<StaticObject>::iterator
i = new_stored.begin();
- i != new_stored.end(); ++i)
- {
+ i != new_stored.end(); ++i) {
StaticObject &s_obj = *i;
block->m_static_objects.m_stored.push_back(s_obj);
}
*/
void ServerEnvironment::deactivateFarObjects(bool force_delete)
{
- std::list<u16> objects_to_remove;
+ std::vector<u16> objects_to_remove;
for(std::map<u16, ServerActiveObject*>::iterator
i = m_active_objects.begin();
- i != m_active_objects.end(); ++i)
- {
+ i != m_active_objects.end(); ++i) {
ServerActiveObject* obj = i->second;
assert(obj);
}
// Remove references from m_active_objects
- for(std::list<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i)
- {
+ for(std::vector<u16>::iterator i = objects_to_remove.begin();
+ i != objects_to_remove.end(); ++i) {
m_active_objects.erase(*i);
}
}
LocalPlayer * ClientEnvironment::getLocalPlayer()
{
- for(std::list<Player*>::iterator i = m_players.begin();
- i != m_players.end(); ++i)
- {
+ for(std::vector<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
Player *player = *i;
if(player->isLocal())
return (LocalPlayer*)player;
/*
Stuff that can be done in an arbitarily large dtime
*/
- for(std::list<Player*>::iterator i = m_players.begin();
- i != m_players.end(); ++i)
- {
+ for(std::vector<Player*>::iterator i = m_players.begin();
+ i != m_players.end(); ++i) {
Player *player = *i;
/*
Handle non-local players
*/
- if(player->isLocal() == false)
- {
+ if(player->isLocal() == false) {
// Move
player->move(dtime, this, 100*BS);
}
-
- // Update lighting on all players on client
- float light = 1.0;
- try{
- // Get node at head
- v3s16 p = player->getLightPosition();
- MapNode n = m_map->getNode(p);
- light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
- }
- catch(InvalidPositionException &e){
- light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
- }
- player->light = light;
}
-
+
+ // Update lighting on local player (used for wield item)
+ u32 day_night_ratio = getDayNightRatio();
+ {
+ // Get node at head
+
+ // On InvalidPositionException, use this as default
+ // (day: LIGHT_SUN, night: 0)
+ MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
+
+ v3s16 p = lplayer->getLightPosition();
+ node_at_lplayer = m_map->getNodeNoEx(p);
+
+ u16 light = getInteriorLight(node_at_lplayer, 0, m_gamedef->ndef());
+ u8 day = light & 0xff;
+ u8 night = (light >> 8) & 0xff;
+ finalColorBlend(lplayer->light_color, day, night, day_night_ratio);
+ }
+
/*
Step active objects and update lighting of them
*/
{
// Update lighting
u8 light = 0;
- try{
- // Get node at head
- v3s16 p = obj->getLightPosition();
- MapNode n = m_map->getNode(p);
- light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
- }
- catch(InvalidPositionException &e){
- light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
- }
+ bool pos_ok;
+
+ // Get node at head
+ v3s16 p = obj->getLightPosition();
+ MapNode n = m_map->getNodeNoEx(p, &pos_ok);
+ if (pos_ok)
+ light = n.getLightBlend(day_night_ratio, m_gamedef->ndef());
+ else
+ light = blend_light(day_night_ratio, LIGHT_SUN, 0);
+
obj->updateLight(light);
}
}
object->addToScene(m_smgr, m_texturesource, m_irr);
{ // Update lighting immediately
u8 light = 0;
- try{
- // Get node at head
- v3s16 p = object->getLightPosition();
- MapNode n = m_map->getNode(p);
+ bool pos_ok;
+
+ // Get node at head
+ v3s16 p = object->getLightPosition();
+ MapNode n = m_map->getNodeNoEx(p, &pos_ok);
+ if (pos_ok)
light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
- }
- catch(InvalidPositionException &e){
+ else
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
- }
+
object->updateLight(light);
}
return object->getId();
const std::string &init_data)
{
ClientActiveObject* obj =
- ClientActiveObject::create(type, m_gamedef, this);
+ ClientActiveObject::create((ActiveObjectType) type, m_gamedef, this);
if(obj == NULL)
{
infostream<<"ClientEnvironment::addActiveObject(): "
assert(lplayer);
if(handle_hp){
+ if (lplayer->hp == 0) // Don't damage a dead player
+ return;
if(lplayer->hp > damage)
lplayer->hp -= damage;
else