Node highlighting.
[oweals/minetest.git] / src / environment.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "environment.h"
21 #include "filesys.h"
22 #include "porting.h"
23 #include "collision.h"
24 #include "content_mapnode.h"
25 #include "mapblock.h"
26 #include "serverobject.h"
27 #include "content_sao.h"
28 #include "settings.h"
29 #include "log.h"
30 #include "profiler.h"
31 #include "scripting_game.h"
32 #include "nodedef.h"
33 #include "nodemetadata.h"
34 #include "main.h" // For g_settings, g_profiler
35 #include "gamedef.h"
36 #ifndef SERVER
37 #include "clientmap.h"
38 #include "localplayer.h"
39 #include "event.h"
40 #endif
41 #include "daynightratio.h"
42 #include "map.h"
43 #include "emerge.h"
44 #include "util/serialize.h"
45 #include "jthread/jmutexautolock.h"
46
47 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
48
49 Environment::Environment():
50         m_time_of_day(9000),
51         m_time_of_day_f(9000./24000),
52         m_time_of_day_speed(0),
53         m_time_counter(0),
54         m_enable_day_night_ratio_override(false),
55         m_day_night_ratio_override(0.0f)
56 {
57 }
58
59 Environment::~Environment()
60 {
61         // Deallocate players
62         for(std::list<Player*>::iterator i = m_players.begin();
63                         i != m_players.end(); ++i)
64         {
65                 delete (*i);
66         }
67 }
68
69 void Environment::addPlayer(Player *player)
70 {
71         DSTACK(__FUNCTION_NAME);
72         /*
73                 Check that peer_ids are unique.
74                 Also check that names are unique.
75                 Exception: there can be multiple players with peer_id=0
76         */
77         // If peer id is non-zero, it has to be unique.
78         if(player->peer_id != 0)
79                 assert(getPlayer(player->peer_id) == NULL);
80         // Name has to be unique.
81         assert(getPlayer(player->getName()) == NULL);
82         // Add.
83         m_players.push_back(player);
84 }
85
86 void Environment::removePlayer(u16 peer_id)
87 {
88         DSTACK(__FUNCTION_NAME);
89
90         for(std::list<Player*>::iterator i = m_players.begin();
91                         i != m_players.end();)
92         {
93                 Player *player = *i;
94                 if(player->peer_id == peer_id) {
95                         delete player;
96                         i = m_players.erase(i);
97                 } else {
98                         ++i;
99                 }
100         }
101 }
102
103 void Environment::removePlayer(const char *name)
104 {
105         for (std::list<Player*>::iterator it = m_players.begin();
106                         it != m_players.end(); ++it) {
107                 if (strcmp((*it)->getName(), name) == 0) {
108                         delete *it;
109                         m_players.erase(it);
110                         return;
111                 }
112         }
113 }
114
115 Player * Environment::getPlayer(u16 peer_id)
116 {
117         for(std::list<Player*>::iterator i = m_players.begin();
118                         i != m_players.end(); ++i)
119         {
120                 Player *player = *i;
121                 if(player->peer_id == peer_id)
122                         return player;
123         }
124         return NULL;
125 }
126
127 Player * Environment::getPlayer(const char *name)
128 {
129         for(std::list<Player*>::iterator i = m_players.begin();
130                         i != m_players.end(); ++i)
131         {
132                 Player *player = *i;
133                 if(strcmp(player->getName(), name) == 0)
134                         return player;
135         }
136         return NULL;
137 }
138
139 Player * Environment::getRandomConnectedPlayer()
140 {
141         std::list<Player*> connected_players = getPlayers(true);
142         u32 chosen_one = myrand() % connected_players.size();
143         u32 j = 0;
144         for(std::list<Player*>::iterator
145                         i = connected_players.begin();
146                         i != connected_players.end(); ++i)
147         {
148                 if(j == chosen_one)
149                 {
150                         Player *player = *i;
151                         return player;
152                 }
153                 j++;
154         }
155         return NULL;
156 }
157
158 Player * Environment::getNearestConnectedPlayer(v3f pos)
159 {
160         std::list<Player*> connected_players = getPlayers(true);
161         f32 nearest_d = 0;
162         Player *nearest_player = NULL;
163         for(std::list<Player*>::iterator
164                         i = connected_players.begin();
165                         i != connected_players.end(); ++i)
166         {
167                 Player *player = *i;
168                 f32 d = player->getPosition().getDistanceFrom(pos);
169                 if(d < nearest_d || nearest_player == NULL)
170                 {
171                         nearest_d = d;
172                         nearest_player = player;
173                 }
174         }
175         return nearest_player;
176 }
177
178 std::list<Player*> Environment::getPlayers()
179 {
180         return m_players;
181 }
182
183 std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
184 {
185         std::list<Player*> newlist;
186         for(std::list<Player*>::iterator
187                         i = m_players.begin();
188                         i != m_players.end(); ++i)
189         {
190                 Player *player = *i;
191                 
192                 if(ignore_disconnected)
193                 {
194                         // Ignore disconnected players
195                         if(player->peer_id == 0)
196                                 continue;
197                 }
198
199                 newlist.push_back(player);
200         }
201         return newlist;
202 }
203
204 u32 Environment::getDayNightRatio()
205 {
206         if(m_enable_day_night_ratio_override)
207                 return m_day_night_ratio_override;
208         bool smooth = g_settings->getBool("enable_shaders");
209         return time_to_daynight_ratio(m_time_of_day_f*24000, smooth);
210 }
211
212 void Environment::setTimeOfDaySpeed(float speed)
213 {
214         JMutexAutoLock(this->m_lock);
215         m_time_of_day_speed = speed;
216 }
217
218 float Environment::getTimeOfDaySpeed()
219 {
220         JMutexAutoLock(this->m_lock);
221         float retval = m_time_of_day_speed;
222         return retval;
223 }
224
225 void Environment::stepTimeOfDay(float dtime)
226 {
227         float day_speed = 0;
228         {
229                 JMutexAutoLock(this->m_lock);
230                 day_speed = m_time_of_day_speed;
231         }
232         
233         m_time_counter += dtime;
234         f32 speed = day_speed * 24000./(24.*3600);
235         u32 units = (u32)(m_time_counter*speed);
236         bool sync_f = false;
237         if(units > 0){
238                 // Sync at overflow
239                 if(m_time_of_day + units >= 24000)
240                         sync_f = true;
241                 m_time_of_day = (m_time_of_day + units) % 24000;
242                 if(sync_f)
243                         m_time_of_day_f = (float)m_time_of_day / 24000.0;
244         }
245         if (speed > 0) {
246                 m_time_counter -= (f32)units / speed;
247         }
248         if(!sync_f){
249                 m_time_of_day_f += day_speed/24/3600*dtime;
250                 if(m_time_of_day_f > 1.0)
251                         m_time_of_day_f -= 1.0;
252                 if(m_time_of_day_f < 0.0)
253                         m_time_of_day_f += 1.0;
254         }
255 }
256
257 /*
258         ABMWithState
259 */
260
261 ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
262         abm(abm_),
263         timer(0)
264 {
265         // Initialize timer to random value to spread processing
266         float itv = abm->getTriggerInterval();
267         itv = MYMAX(0.001, itv); // No less than 1ms
268         int minval = MYMAX(-0.51*itv, -60); // Clamp to
269         int maxval = MYMIN(0.51*itv, 60);   // +-60 seconds
270         timer = myrand_range(minval, maxval);
271 }
272
273 /*
274         ActiveBlockList
275 */
276
277 void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
278 {
279         v3s16 p;
280         for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
281         for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
282         for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
283         {
284                 // Set in list
285                 list.insert(p);
286         }
287 }
288
289 void ActiveBlockList::update(std::list<v3s16> &active_positions,
290                 s16 radius,
291                 std::set<v3s16> &blocks_removed,
292                 std::set<v3s16> &blocks_added)
293 {
294         /*
295                 Create the new list
296         */
297         std::set<v3s16> newlist = m_forceloaded_list;
298         for(std::list<v3s16>::iterator i = active_positions.begin();
299                         i != active_positions.end(); ++i)
300         {
301                 fillRadiusBlock(*i, radius, newlist);
302         }
303
304         /*
305                 Find out which blocks on the old list are not on the new list
306         */
307         // Go through old list
308         for(std::set<v3s16>::iterator i = m_list.begin();
309                         i != m_list.end(); ++i)
310         {
311                 v3s16 p = *i;
312                 // If not on new list, it's been removed
313                 if(newlist.find(p) == newlist.end())
314                         blocks_removed.insert(p);
315         }
316
317         /*
318                 Find out which blocks on the new list are not on the old list
319         */
320         // Go through new list
321         for(std::set<v3s16>::iterator i = newlist.begin();
322                         i != newlist.end(); ++i)
323         {
324                 v3s16 p = *i;
325                 // If not on old list, it's been added
326                 if(m_list.find(p) == m_list.end())
327                         blocks_added.insert(p);
328         }
329
330         /*
331                 Update m_list
332         */
333         m_list.clear();
334         for(std::set<v3s16>::iterator i = newlist.begin();
335                         i != newlist.end(); ++i)
336         {
337                 v3s16 p = *i;
338                 m_list.insert(p);
339         }
340 }
341
342 /*
343         ServerEnvironment
344 */
345
346 ServerEnvironment::ServerEnvironment(ServerMap *map,
347                 GameScripting *scriptIface, IGameDef *gamedef,
348                 const std::string &path_world) :
349         m_map(map),
350         m_script(scriptIface),
351         m_gamedef(gamedef),
352         m_path_world(path_world),
353         m_send_recommended_timer(0),
354         m_active_block_interval_overload_skip(0),
355         m_game_time(0),
356         m_game_time_fraction_counter(0),
357         m_recommended_send_interval(0.1),
358         m_max_lag_estimate(0.1)
359 {
360 }
361
362 ServerEnvironment::~ServerEnvironment()
363 {
364         // Clear active block list.
365         // This makes the next one delete all active objects.
366         m_active_blocks.clear();
367
368         // Convert all objects to static and delete the active objects
369         deactivateFarObjects(true);
370
371         // Drop/delete map
372         m_map->drop();
373
374         // Delete ActiveBlockModifiers
375         for(std::list<ABMWithState>::iterator
376                         i = m_abms.begin(); i != m_abms.end(); ++i){
377                 delete i->abm;
378         }
379 }
380
381 Map & ServerEnvironment::getMap()
382 {
383         return *m_map;
384 }
385
386 ServerMap & ServerEnvironment::getServerMap()
387 {
388         return *m_map;
389 }
390
391 bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16 *p)
392 {
393         float distance = pos1.getDistanceFrom(pos2);
394
395         //calculate normalized direction vector
396         v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
397                                                                 (pos2.Y - pos1.Y)/distance,
398                                                                 (pos2.Z - pos1.Z)/distance);
399
400         //find out if there's a node on path between pos1 and pos2
401         for (float i = 1; i < distance; i += stepsize) {
402                 v3s16 pos = floatToInt(v3f(normalized_vector.X * i,
403                                 normalized_vector.Y * i,
404                                 normalized_vector.Z * i) +pos1,BS);
405
406                 MapNode n = getMap().getNodeNoEx(pos);
407
408                 if(n.param0 != CONTENT_AIR) {
409                         if (p) {
410                                 *p = pos;
411                         }
412                         return false;
413                 }
414         }
415         return true;
416 }
417
418 void ServerEnvironment::saveLoadedPlayers()
419 {
420         std::string players_path = m_path_world + DIR_DELIM "players";
421         fs::CreateDir(players_path);
422
423         for (std::list<Player*>::iterator it = m_players.begin();
424                         it != m_players.end();
425                         ++it) {
426                 RemotePlayer *player = static_cast<RemotePlayer*>(*it);
427                 if (player->checkModified()) {
428                         player->save(players_path);
429                 }
430         }
431 }
432
433 void ServerEnvironment::savePlayer(const std::string &playername)
434 {
435         std::string players_path = m_path_world + DIR_DELIM "players";
436         fs::CreateDir(players_path);
437
438         RemotePlayer *player = static_cast<RemotePlayer*>(getPlayer(playername.c_str()));
439         if (player) {
440                 player->save(players_path);
441         }
442 }
443
444 Player *ServerEnvironment::loadPlayer(const std::string &playername)
445 {
446         std::string players_path = m_path_world + DIR_DELIM "players" DIR_DELIM;
447
448         RemotePlayer *player = static_cast<RemotePlayer*>(getPlayer(playername.c_str()));
449         bool newplayer = false;
450         bool found = false;
451         if (!player) {
452                 player = new RemotePlayer(m_gamedef);
453                 newplayer = true;
454         }
455
456         RemotePlayer testplayer(m_gamedef);
457         std::string path = players_path + playername;
458         for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
459                 // Open file and deserialize
460                 std::ifstream is(path.c_str(), std::ios_base::binary);
461                 if (!is.good()) {
462                         return NULL;
463                 }
464                 testplayer.deSerialize(is, path);
465                 is.close();
466                 if (testplayer.getName() == playername) {
467                         *player = testplayer;
468                         found = true;
469                         break;
470                 }
471                 path = players_path + playername + itos(i);
472         }
473         if (!found) {
474                 infostream << "Player file for player " << playername
475                                 << " not found" << std::endl;
476                 return NULL;
477         }
478         if (newplayer) {
479                 addPlayer(player);
480         }
481         return player;
482 }
483
484 void ServerEnvironment::saveMeta()
485 {
486         std::string path = m_path_world + DIR_DELIM "env_meta.txt";
487
488         // Open file and serialize
489         std::ostringstream ss(std::ios_base::binary);
490
491         Settings args;
492         args.setU64("game_time", m_game_time);
493         args.setU64("time_of_day", getTimeOfDay());
494         args.writeLines(ss);
495         ss<<"EnvArgsEnd\n";
496
497         if(!fs::safeWriteToFile(path, ss.str()))
498         {
499                 infostream<<"ServerEnvironment::saveMeta(): Failed to write "
500                                 <<path<<std::endl;
501                 throw SerializationError("Couldn't save env meta");
502         }
503 }
504
505 void ServerEnvironment::loadMeta()
506 {
507         std::string path = m_path_world + DIR_DELIM "env_meta.txt";
508
509         // Open file and deserialize
510         std::ifstream is(path.c_str(), std::ios_base::binary);
511         if(is.good() == false)
512         {
513                 infostream<<"ServerEnvironment::loadMeta(): Failed to open "
514                                 <<path<<std::endl;
515                 throw SerializationError("Couldn't load env meta");
516         }
517
518         Settings args;
519         
520         for(;;)
521         {
522                 if(is.eof())
523                         throw SerializationError
524                                         ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
525                 std::string line;
526                 std::getline(is, line);
527                 std::string trimmedline = trim(line);
528                 if(trimmedline == "EnvArgsEnd")
529                         break;
530                 args.parseConfigLine(line);
531         }
532         
533         try{
534                 m_game_time = args.getU64("game_time");
535         }catch(SettingNotFoundException &e){
536                 // Getting this is crucial, otherwise timestamps are useless
537                 throw SerializationError("Couldn't load env meta game_time");
538         }
539
540         try{
541                 m_time_of_day = args.getU64("time_of_day");
542         }catch(SettingNotFoundException &e){
543                 // This is not as important
544                 m_time_of_day = 9000;
545         }
546 }
547
548 struct ActiveABM
549 {
550         ActiveBlockModifier *abm;
551         int chance;
552         std::set<content_t> required_neighbors;
553 };
554
555 class ABMHandler
556 {
557 private:
558         ServerEnvironment *m_env;
559         std::map<content_t, std::list<ActiveABM> > m_aabms;
560 public:
561         ABMHandler(std::list<ABMWithState> &abms,
562                         float dtime_s, ServerEnvironment *env,
563                         bool use_timers):
564                 m_env(env)
565         {
566                 if(dtime_s < 0.001)
567                         return;
568                 INodeDefManager *ndef = env->getGameDef()->ndef();
569                 for(std::list<ABMWithState>::iterator
570                                 i = abms.begin(); i != abms.end(); ++i){
571                         ActiveBlockModifier *abm = i->abm;
572                         float trigger_interval = abm->getTriggerInterval();
573                         if(trigger_interval < 0.001)
574                                 trigger_interval = 0.001;
575                         float actual_interval = dtime_s;
576                         if(use_timers){
577                                 i->timer += dtime_s;
578                                 if(i->timer < trigger_interval)
579                                         continue;
580                                 i->timer -= trigger_interval;
581                                 actual_interval = trigger_interval;
582                         }
583                         float intervals = actual_interval / trigger_interval;
584                         if(intervals == 0)
585                                 continue;
586                         float chance = abm->getTriggerChance();
587                         if(chance == 0)
588                                 chance = 1;
589                         ActiveABM aabm;
590                         aabm.abm = abm;
591                         aabm.chance = chance / intervals;
592                         if(aabm.chance == 0)
593                                 aabm.chance = 1;
594                         // Trigger neighbors
595                         std::set<std::string> required_neighbors_s
596                                         = abm->getRequiredNeighbors();
597                         for(std::set<std::string>::iterator
598                                         i = required_neighbors_s.begin();
599                                         i != required_neighbors_s.end(); i++)
600                         {
601                                 ndef->getIds(*i, aabm.required_neighbors);
602                         }
603                         // Trigger contents
604                         std::set<std::string> contents_s = abm->getTriggerContents();
605                         for(std::set<std::string>::iterator
606                                         i = contents_s.begin(); i != contents_s.end(); i++)
607                         {
608                                 std::set<content_t> ids;
609                                 ndef->getIds(*i, ids);
610                                 for(std::set<content_t>::const_iterator k = ids.begin();
611                                                 k != ids.end(); k++)
612                                 {
613                                         content_t c = *k;
614                                         std::map<content_t, std::list<ActiveABM> >::iterator j;
615                                         j = m_aabms.find(c);
616                                         if(j == m_aabms.end()){
617                                                 std::list<ActiveABM> aabmlist;
618                                                 m_aabms[c] = aabmlist;
619                                                 j = m_aabms.find(c);
620                                         }
621                                         j->second.push_back(aabm);
622                                 }
623                         }
624                 }
625         }
626         // Find out how many objects the given block and its neighbours contain.
627         // Returns the number of objects in the block, and also in 'wider' the
628         // number of objects in the block and all its neighbours. The latter
629         // may an estimate if any neighbours are unloaded.
630         u32 countObjects(MapBlock *block, ServerMap * map, u32 &wider)
631         {
632                 wider = 0;
633                 u32 wider_unknown_count = 0;
634                 for(s16 x=-1; x<=1; x++)
635                 for(s16 y=-1; y<=1; y++)
636                 for(s16 z=-1; z<=1; z++)
637                 {
638                         MapBlock *block2 = map->getBlockNoCreateNoEx(
639                                         block->getPos() + v3s16(x,y,z));
640                         if(block2==NULL){
641                                 wider_unknown_count++;
642                                 continue;
643                         }
644                         wider += block2->m_static_objects.m_active.size()
645                                         + block2->m_static_objects.m_stored.size();
646                 }
647                 // Extrapolate
648                 u32 active_object_count = block->m_static_objects.m_active.size();
649                 u32 wider_known_count = 3*3*3 - wider_unknown_count;
650                 wider += wider_unknown_count * wider / wider_known_count;
651                 return active_object_count;
652
653         }
654         void apply(MapBlock *block)
655         {
656                 if(m_aabms.empty())
657                         return;
658
659                 ServerMap *map = &m_env->getServerMap();
660
661                 u32 active_object_count_wider;
662                 u32 active_object_count = this->countObjects(block, map, active_object_count_wider);
663                 m_env->m_added_objects = 0;
664
665                 v3s16 p0;
666                 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
667                 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
668                 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
669                 {
670                         MapNode n = block->getNodeNoEx(p0);
671                         content_t c = n.getContent();
672                         v3s16 p = p0 + block->getPosRelative();
673
674                         std::map<content_t, std::list<ActiveABM> >::iterator j;
675                         j = m_aabms.find(c);
676                         if(j == m_aabms.end())
677                                 continue;
678
679                         for(std::list<ActiveABM>::iterator
680                                         i = j->second.begin(); i != j->second.end(); i++)
681                         {
682                                 if(myrand() % i->chance != 0)
683                                         continue;
684
685                                 // Check neighbors
686                                 if(!i->required_neighbors.empty())
687                                 {
688                                         v3s16 p1;
689                                         for(p1.X = p.X-1; p1.X <= p.X+1; p1.X++)
690                                         for(p1.Y = p.Y-1; p1.Y <= p.Y+1; p1.Y++)
691                                         for(p1.Z = p.Z-1; p1.Z <= p.Z+1; p1.Z++)
692                                         {
693                                                 if(p1 == p)
694                                                         continue;
695                                                 MapNode n = map->getNodeNoEx(p1);
696                                                 content_t c = n.getContent();
697                                                 std::set<content_t>::const_iterator k;
698                                                 k = i->required_neighbors.find(c);
699                                                 if(k != i->required_neighbors.end()){
700                                                         goto neighbor_found;
701                                                 }
702                                         }
703                                         // No required neighbor found
704                                         continue;
705                                 }
706 neighbor_found:
707
708                                 // Call all the trigger variations
709                                 i->abm->trigger(m_env, p, n);
710                                 i->abm->trigger(m_env, p, n,
711                                                 active_object_count, active_object_count_wider);
712
713                                 // Count surrounding objects again if the abms added any
714                                 if(m_env->m_added_objects > 0) {
715                                         active_object_count = countObjects(block, map, active_object_count_wider);
716                                         m_env->m_added_objects = 0;
717                                 }
718                         }
719                 }
720         }
721 };
722
723 void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
724 {
725         // Reset usage timer immediately, otherwise a block that becomes active
726         // again at around the same time as it would normally be unloaded will
727         // get unloaded incorrectly. (I think this still leaves a small possibility
728         // of a race condition between this and server::AsyncRunStep, which only
729         // some kind of synchronisation will fix, but it at least reduces the window
730         // of opportunity for it to break from seconds to nanoseconds)
731         block->resetUsageTimer();
732
733         // Get time difference
734         u32 dtime_s = 0;
735         u32 stamp = block->getTimestamp();
736         if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
737                 dtime_s = m_game_time - block->getTimestamp();
738         dtime_s += additional_dtime;
739
740         /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
741                         <<stamp<<", game time: "<<m_game_time<<std::endl;*/
742
743         // Set current time as timestamp
744         block->setTimestampNoChangedFlag(m_game_time);
745
746         /*infostream<<"ServerEnvironment::activateBlock(): block is "
747                         <<dtime_s<<" seconds old."<<std::endl;*/
748         
749         // Activate stored objects
750         activateObjects(block, dtime_s);
751
752         // Run node timers
753         std::map<v3s16, NodeTimer> elapsed_timers =
754                 block->m_node_timers.step((float)dtime_s);
755         if(!elapsed_timers.empty()){
756                 MapNode n;
757                 for(std::map<v3s16, NodeTimer>::iterator
758                                 i = elapsed_timers.begin();
759                                 i != elapsed_timers.end(); i++){
760                         n = block->getNodeNoEx(i->first);
761                         v3s16 p = i->first + block->getPosRelative();
762                         if(m_script->node_on_timer(p,n,i->second.elapsed))
763                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
764                 }
765         }
766
767         /* Handle ActiveBlockModifiers */
768         ABMHandler abmhandler(m_abms, dtime_s, this, false);
769         abmhandler.apply(block);
770 }
771
772 void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
773 {
774         m_abms.push_back(ABMWithState(abm));
775 }
776
777 bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
778 {
779         INodeDefManager *ndef = m_gamedef->ndef();
780         MapNode n_old = m_map->getNodeNoEx(p);
781
782         // Call destructor
783         if (ndef->get(n_old).has_on_destruct)
784                 m_script->node_on_destruct(p, n_old);
785
786         // Replace node
787         if (!m_map->addNodeWithEvent(p, n))
788                 return false;
789
790         // Update active VoxelManipulator if a mapgen thread
791         m_map->updateVManip(p);
792
793         // Call post-destructor
794         if (ndef->get(n_old).has_after_destruct)
795                 m_script->node_after_destruct(p, n_old);
796
797         // Call constructor
798         if (ndef->get(n).has_on_construct)
799                 m_script->node_on_construct(p, n);
800
801         return true;
802 }
803
804 bool ServerEnvironment::removeNode(v3s16 p)
805 {
806         INodeDefManager *ndef = m_gamedef->ndef();
807         MapNode n_old = m_map->getNodeNoEx(p);
808
809         // Call destructor
810         if (ndef->get(n_old).has_on_destruct)
811                 m_script->node_on_destruct(p, n_old);
812
813         // Replace with air
814         // This is slightly optimized compared to addNodeWithEvent(air)
815         if (!m_map->removeNodeWithEvent(p))
816                 return false;
817
818         // Update active VoxelManipulator if a mapgen thread
819         m_map->updateVManip(p);
820
821         // Call post-destructor
822         if (ndef->get(n_old).has_after_destruct)
823                 m_script->node_after_destruct(p, n_old);
824
825         // Air doesn't require constructor
826         return true;
827 }
828
829 bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
830 {
831         if (!m_map->addNodeWithEvent(p, n, false))
832                 return false;
833
834         // Update active VoxelManipulator if a mapgen thread
835         m_map->updateVManip(p);
836
837         return true;
838 }
839
840 std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
841 {
842         std::set<u16> objects;
843         for(std::map<u16, ServerActiveObject*>::iterator
844                         i = m_active_objects.begin();
845                         i != m_active_objects.end(); ++i)
846         {
847                 ServerActiveObject* obj = i->second;
848                 u16 id = i->first;
849                 v3f objectpos = obj->getBasePosition();
850                 if(objectpos.getDistanceFrom(pos) > radius)
851                         continue;
852                 objects.insert(id);
853         }
854         return objects;
855 }
856
857 void ServerEnvironment::clearAllObjects()
858 {
859         infostream<<"ServerEnvironment::clearAllObjects(): "
860                         <<"Removing all active objects"<<std::endl;
861         std::list<u16> objects_to_remove;
862         for(std::map<u16, ServerActiveObject*>::iterator
863                         i = m_active_objects.begin();
864                         i != m_active_objects.end(); ++i)
865         {
866                 ServerActiveObject* obj = i->second;
867                 if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
868                         continue;
869                 u16 id = i->first;
870                 // Delete static object if block is loaded
871                 if(obj->m_static_exists){
872                         MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
873                         if(block){
874                                 block->m_static_objects.remove(id);
875                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
876                                                 "clearAllObjects");
877                                 obj->m_static_exists = false;
878                         }
879                 }
880                 // If known by some client, don't delete immediately
881                 if(obj->m_known_by_count > 0){
882                         obj->m_pending_deactivation = true;
883                         obj->m_removed = true;
884                         continue;
885                 }
886
887                 // Tell the object about removal
888                 obj->removingFromEnvironment();
889                 // Deregister in scripting api
890                 m_script->removeObjectReference(obj);
891
892                 // Delete active object
893                 if(obj->environmentDeletes())
894                         delete obj;
895                 // Id to be removed from m_active_objects
896                 objects_to_remove.push_back(id);
897         }
898         // Remove references from m_active_objects
899         for(std::list<u16>::iterator i = objects_to_remove.begin();
900                         i != objects_to_remove.end(); ++i)
901         {
902                 m_active_objects.erase(*i);
903         }
904
905         // Get list of loaded blocks
906         std::list<v3s16> loaded_blocks;
907         infostream<<"ServerEnvironment::clearAllObjects(): "
908                         <<"Listing all loaded blocks"<<std::endl;
909         m_map->listAllLoadedBlocks(loaded_blocks);
910         infostream<<"ServerEnvironment::clearAllObjects(): "
911                         <<"Done listing all loaded blocks: "
912                         <<loaded_blocks.size()<<std::endl;
913
914         // Get list of loadable blocks
915         std::list<v3s16> loadable_blocks;
916         infostream<<"ServerEnvironment::clearAllObjects(): "
917                         <<"Listing all loadable blocks"<<std::endl;
918         m_map->listAllLoadableBlocks(loadable_blocks);
919         infostream<<"ServerEnvironment::clearAllObjects(): "
920                         <<"Done listing all loadable blocks: "
921                         <<loadable_blocks.size()
922                         <<", now clearing"<<std::endl;
923
924         // Grab a reference on each loaded block to avoid unloading it
925         for(std::list<v3s16>::iterator i = loaded_blocks.begin();
926                         i != loaded_blocks.end(); ++i)
927         {
928                 v3s16 p = *i;
929                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
930                 assert(block);
931                 block->refGrab();
932         }
933
934         // Remove objects in all loadable blocks
935         u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
936         unload_interval = MYMAX(unload_interval, 1);
937         u32 report_interval = loadable_blocks.size() / 10;
938         u32 num_blocks_checked = 0;
939         u32 num_blocks_cleared = 0;
940         u32 num_objs_cleared = 0;
941         for(std::list<v3s16>::iterator i = loadable_blocks.begin();
942                         i != loadable_blocks.end(); ++i)
943         {
944                 v3s16 p = *i;
945                 MapBlock *block = m_map->emergeBlock(p, false);
946                 if(!block){
947                         errorstream<<"ServerEnvironment::clearAllObjects(): "
948                                         <<"Failed to emerge block "<<PP(p)<<std::endl;
949                         continue;
950                 }
951                 u32 num_stored = block->m_static_objects.m_stored.size();
952                 u32 num_active = block->m_static_objects.m_active.size();
953                 if(num_stored != 0 || num_active != 0){
954                         block->m_static_objects.m_stored.clear();
955                         block->m_static_objects.m_active.clear();
956                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
957                                         "clearAllObjects");
958                         num_objs_cleared += num_stored + num_active;
959                         num_blocks_cleared++;
960                 }
961                 num_blocks_checked++;
962
963                 if(report_interval != 0 &&
964                                 num_blocks_checked % report_interval == 0){
965                         float percent = 100.0 * (float)num_blocks_checked /
966                                         loadable_blocks.size();
967                         infostream<<"ServerEnvironment::clearAllObjects(): "
968                                         <<"Cleared "<<num_objs_cleared<<" objects"
969                                         <<" in "<<num_blocks_cleared<<" blocks ("
970                                         <<percent<<"%)"<<std::endl;
971                 }
972                 if(num_blocks_checked % unload_interval == 0){
973                         m_map->unloadUnreferencedBlocks();
974                 }
975         }
976         m_map->unloadUnreferencedBlocks();
977
978         // Drop references that were added above
979         for(std::list<v3s16>::iterator i = loaded_blocks.begin();
980                         i != loaded_blocks.end(); ++i)
981         {
982                 v3s16 p = *i;
983                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
984                 assert(block);
985                 block->refDrop();
986         }
987
988         infostream<<"ServerEnvironment::clearAllObjects(): "
989                         <<"Finished: Cleared "<<num_objs_cleared<<" objects"
990                         <<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
991 }
992
993 void ServerEnvironment::step(float dtime)
994 {
995         DSTACK(__FUNCTION_NAME);
996         
997         //TimeTaker timer("ServerEnv step");
998
999         /* Step time of day */
1000         stepTimeOfDay(dtime);
1001
1002         // Update this one
1003         // NOTE: This is kind of funny on a singleplayer game, but doesn't
1004         // really matter that much.
1005         m_recommended_send_interval = g_settings->getFloat("dedicated_server_step");
1006
1007         /*
1008                 Increment game time
1009         */
1010         {
1011                 m_game_time_fraction_counter += dtime;
1012                 u32 inc_i = (u32)m_game_time_fraction_counter;
1013                 m_game_time += inc_i;
1014                 m_game_time_fraction_counter -= (float)inc_i;
1015         }
1016         
1017         /*
1018                 Handle players
1019         */
1020         {
1021                 ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
1022                 for(std::list<Player*>::iterator i = m_players.begin();
1023                                 i != m_players.end(); ++i)
1024                 {
1025                         Player *player = *i;
1026                         
1027                         // Ignore disconnected players
1028                         if(player->peer_id == 0)
1029                                 continue;
1030                         
1031                         // Move
1032                         player->move(dtime, this, 100*BS);
1033                 }
1034         }
1035
1036         /*
1037                 Manage active block list
1038         */
1039         if(m_active_blocks_management_interval.step(dtime, 2.0))
1040         {
1041                 ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg /2s", SPT_AVG);
1042                 /*
1043                         Get player block positions
1044                 */
1045                 std::list<v3s16> players_blockpos;
1046                 for(std::list<Player*>::iterator
1047                                 i = m_players.begin();
1048                                 i != m_players.end(); ++i)
1049                 {
1050                         Player *player = *i;
1051                         // Ignore disconnected players
1052                         if(player->peer_id == 0)
1053                                 continue;
1054                         v3s16 blockpos = getNodeBlockPos(
1055                                         floatToInt(player->getPosition(), BS));
1056                         players_blockpos.push_back(blockpos);
1057                 }
1058                 
1059                 /*
1060                         Update list of active blocks, collecting changes
1061                 */
1062                 const s16 active_block_range = g_settings->getS16("active_block_range");
1063                 std::set<v3s16> blocks_removed;
1064                 std::set<v3s16> blocks_added;
1065                 m_active_blocks.update(players_blockpos, active_block_range,
1066                                 blocks_removed, blocks_added);
1067
1068                 /*
1069                         Handle removed blocks
1070                 */
1071
1072                 // Convert active objects that are no more in active blocks to static
1073                 deactivateFarObjects(false);
1074                 
1075                 for(std::set<v3s16>::iterator
1076                                 i = blocks_removed.begin();
1077                                 i != blocks_removed.end(); ++i)
1078                 {
1079                         v3s16 p = *i;
1080
1081                         /* infostream<<"Server: Block " << PP(p)
1082                                 << " became inactive"<<std::endl; */
1083                         
1084                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1085                         if(block==NULL)
1086                                 continue;
1087                         
1088                         // Set current time as timestamp (and let it set ChangedFlag)
1089                         block->setTimestamp(m_game_time);
1090                 }
1091
1092                 /*
1093                         Handle added blocks
1094                 */
1095
1096                 for(std::set<v3s16>::iterator
1097                                 i = blocks_added.begin();
1098                                 i != blocks_added.end(); ++i)
1099                 {
1100                         v3s16 p = *i;
1101
1102                         MapBlock *block = m_map->getBlockOrEmerge(p);
1103                         if(block==NULL){
1104                                 m_active_blocks.m_list.erase(p);
1105                                 continue;
1106                         }
1107
1108                         activateBlock(block);
1109                         /* infostream<<"Server: Block " << PP(p)
1110                                 << " became active"<<std::endl; */
1111                 }
1112         }
1113
1114         /*
1115                 Mess around in active blocks
1116         */
1117         if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
1118         {
1119                 ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg /1s", SPT_AVG);
1120                 
1121                 float dtime = 1.0;
1122
1123                 for(std::set<v3s16>::iterator
1124                                 i = m_active_blocks.m_list.begin();
1125                                 i != m_active_blocks.m_list.end(); ++i)
1126                 {
1127                         v3s16 p = *i;
1128                         
1129                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1130                                         <<") being handled"<<std::endl;*/
1131
1132                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1133                         if(block==NULL)
1134                                 continue;
1135
1136                         // Reset block usage timer
1137                         block->resetUsageTimer();
1138                         
1139                         // Set current time as timestamp
1140                         block->setTimestampNoChangedFlag(m_game_time);
1141                         // If time has changed much from the one on disk,
1142                         // set block to be saved when it is unloaded
1143                         if(block->getTimestamp() > block->getDiskTimestamp() + 60)
1144                                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1145                                                 "Timestamp older than 60s (step)");
1146
1147                         // Run node timers
1148                         std::map<v3s16, NodeTimer> elapsed_timers =
1149                                 block->m_node_timers.step((float)dtime);
1150                         if(!elapsed_timers.empty()){
1151                                 MapNode n;
1152                                 for(std::map<v3s16, NodeTimer>::iterator
1153                                                 i = elapsed_timers.begin();
1154                                                 i != elapsed_timers.end(); i++){
1155                                         n = block->getNodeNoEx(i->first);
1156                                         p = i->first + block->getPosRelative();
1157                                         if(m_script->node_on_timer(p,n,i->second.elapsed))
1158                                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
1159                                 }
1160                         }
1161                 }
1162         }
1163         
1164         const float abm_interval = 1.0;
1165         if(m_active_block_modifier_interval.step(dtime, abm_interval))
1166         do{ // breakable
1167                 if(m_active_block_interval_overload_skip > 0){
1168                         ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
1169                         m_active_block_interval_overload_skip--;
1170                         break;
1171                 }
1172                 ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg /1s", SPT_AVG);
1173                 TimeTaker timer("modify in active blocks");
1174                 
1175                 // Initialize handling of ActiveBlockModifiers
1176                 ABMHandler abmhandler(m_abms, abm_interval, this, true);
1177
1178                 for(std::set<v3s16>::iterator
1179                                 i = m_active_blocks.m_list.begin();
1180                                 i != m_active_blocks.m_list.end(); ++i)
1181                 {
1182                         v3s16 p = *i;
1183                         
1184                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1185                                         <<") being handled"<<std::endl;*/
1186
1187                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1188                         if(block==NULL)
1189                                 continue;
1190                         
1191                         // Set current time as timestamp
1192                         block->setTimestampNoChangedFlag(m_game_time);
1193
1194                         /* Handle ActiveBlockModifiers */
1195                         abmhandler.apply(block);
1196                 }
1197
1198                 u32 time_ms = timer.stop(true);
1199                 u32 max_time_ms = 200;
1200                 if(time_ms > max_time_ms){
1201                         infostream<<"WARNING: active block modifiers took "
1202                                         <<time_ms<<"ms (longer than "
1203                                         <<max_time_ms<<"ms)"<<std::endl;
1204                         m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
1205                 }
1206         }while(0);
1207         
1208         /*
1209                 Step script environment (run global on_step())
1210         */
1211         m_script->environment_Step(dtime);
1212
1213         /*
1214                 Step active objects
1215         */
1216         {
1217                 ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
1218                 //TimeTaker timer("Step active objects");
1219
1220                 g_profiler->avg("SEnv: num of objects", m_active_objects.size());
1221                 
1222                 // This helps the objects to send data at the same time
1223                 bool send_recommended = false;
1224                 m_send_recommended_timer += dtime;
1225                 if(m_send_recommended_timer > getSendRecommendedInterval())
1226                 {
1227                         m_send_recommended_timer -= getSendRecommendedInterval();
1228                         send_recommended = true;
1229                 }
1230
1231                 for(std::map<u16, ServerActiveObject*>::iterator
1232                                 i = m_active_objects.begin();
1233                                 i != m_active_objects.end(); ++i)
1234                 {
1235                         ServerActiveObject* obj = i->second;
1236                         // Remove non-peaceful mobs on peaceful mode
1237                         if(g_settings->getBool("only_peaceful_mobs")){
1238                                 if(!obj->isPeaceful())
1239                                         obj->m_removed = true;
1240                         }
1241                         // Don't step if is to be removed or stored statically
1242                         if(obj->m_removed || obj->m_pending_deactivation)
1243                                 continue;
1244                         // Step object
1245                         obj->step(dtime, send_recommended);
1246                         // Read messages from object
1247                         while(!obj->m_messages_out.empty())
1248                         {
1249                                 m_active_object_messages.push_back(
1250                                                 obj->m_messages_out.pop_front());
1251                         }
1252                 }
1253         }
1254         
1255         /*
1256                 Manage active objects
1257         */
1258         if(m_object_management_interval.step(dtime, 0.5))
1259         {
1260                 ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
1261                 /*
1262                         Remove objects that satisfy (m_removed && m_known_by_count==0)
1263                 */
1264                 removeRemovedObjects();
1265         }
1266 }
1267
1268 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
1269 {
1270         std::map<u16, ServerActiveObject*>::iterator n;
1271         n = m_active_objects.find(id);
1272         if(n == m_active_objects.end())
1273                 return NULL;
1274         return n->second;
1275 }
1276
1277 bool isFreeServerActiveObjectId(u16 id,
1278                 std::map<u16, ServerActiveObject*> &objects)
1279 {
1280         if(id == 0)
1281                 return false;
1282
1283         return objects.find(id) == objects.end();
1284 }
1285
1286 u16 getFreeServerActiveObjectId(
1287                 std::map<u16, ServerActiveObject*> &objects)
1288 {
1289         //try to reuse id's as late as possible
1290         static u16 last_used_id = 0;
1291         u16 startid = last_used_id;
1292         for(;;)
1293         {
1294                 last_used_id ++;
1295                 if(isFreeServerActiveObjectId(last_used_id, objects))
1296                         return last_used_id;
1297                 
1298                 if(last_used_id == startid)
1299                         return 0;
1300         }
1301 }
1302
1303 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1304 {
1305         assert(object);
1306         m_added_objects++;
1307         u16 id = addActiveObjectRaw(object, true, 0);
1308         return id;
1309 }
1310
1311 #if 0
1312 bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
1313 {
1314         assert(obj);
1315
1316         v3f objectpos = obj->getBasePosition();
1317
1318         // The block in which the object resides in
1319         v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1320
1321         /*
1322                 Update the static data
1323         */
1324
1325         // Create new static object
1326         std::string staticdata = obj->getStaticData();
1327         StaticObject s_obj(obj->getType(), objectpos, staticdata);
1328         // Add to the block where the object is located in
1329         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1330         // Get or generate the block
1331         MapBlock *block = m_map->emergeBlock(blockpos);
1332
1333         bool succeeded = false;
1334
1335         if(block)
1336         {
1337                 block->m_static_objects.insert(0, s_obj);
1338                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1339                                 "addActiveObjectAsStatic");
1340                 succeeded = true;
1341         }
1342         else{
1343                 infostream<<"ServerEnvironment::addActiveObjectAsStatic: "
1344                                 <<"Could not find or generate "
1345                                 <<"a block for storing static object"<<std::endl;
1346                 succeeded = false;
1347         }
1348
1349         if(obj->environmentDeletes())
1350                 delete obj;
1351
1352         return succeeded;
1353 }
1354 #endif
1355
1356 /*
1357         Finds out what new objects have been added to
1358         inside a radius around a position
1359 */
1360 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1361                 std::set<u16> &current_objects,
1362                 std::set<u16> &added_objects)
1363 {
1364         v3f pos_f = intToFloat(pos, BS);
1365         f32 radius_f = radius * BS;
1366         /*
1367                 Go through the object list,
1368                 - discard m_removed objects,
1369                 - discard objects that are too far away,
1370                 - discard objects that are found in current_objects.
1371                 - add remaining objects to added_objects
1372         */
1373         for(std::map<u16, ServerActiveObject*>::iterator
1374                         i = m_active_objects.begin();
1375                         i != m_active_objects.end(); ++i)
1376         {
1377                 u16 id = i->first;
1378                 // Get object
1379                 ServerActiveObject *object = i->second;
1380                 if(object == NULL)
1381                         continue;
1382                 // Discard if removed or deactivating
1383                 if(object->m_removed || object->m_pending_deactivation)
1384                         continue;
1385                 if(object->unlimitedTransferDistance() == false){
1386                         // Discard if too far
1387                         f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1388                         if(distance_f > radius_f)
1389                                 continue;
1390                 }
1391                 // Discard if already on current_objects
1392                 std::set<u16>::iterator n;
1393                 n = current_objects.find(id);
1394                 if(n != current_objects.end())
1395                         continue;
1396                 // Add to added_objects
1397                 added_objects.insert(id);
1398         }
1399 }
1400
1401 /*
1402         Finds out what objects have been removed from
1403         inside a radius around a position
1404 */
1405 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1406                 std::set<u16> &current_objects,
1407                 std::set<u16> &removed_objects)
1408 {
1409         v3f pos_f = intToFloat(pos, BS);
1410         f32 radius_f = radius * BS;
1411         /*
1412                 Go through current_objects; object is removed if:
1413                 - object is not found in m_active_objects (this is actually an
1414                   error condition; objects should be set m_removed=true and removed
1415                   only after all clients have been informed about removal), or
1416                 - object has m_removed=true, or
1417                 - object is too far away
1418         */
1419         for(std::set<u16>::iterator
1420                         i = current_objects.begin();
1421                         i != current_objects.end(); ++i)
1422         {
1423                 u16 id = *i;
1424                 ServerActiveObject *object = getActiveObject(id);
1425
1426                 if(object == NULL){
1427                         infostream<<"ServerEnvironment::getRemovedActiveObjects():"
1428                                         <<" object in current_objects is NULL"<<std::endl;
1429                         removed_objects.insert(id);
1430                         continue;
1431                 }
1432
1433                 if(object->m_removed || object->m_pending_deactivation)
1434                 {
1435                         removed_objects.insert(id);
1436                         continue;
1437                 }
1438                 
1439                 // If transfer distance is unlimited, don't remove
1440                 if(object->unlimitedTransferDistance())
1441                         continue;
1442
1443                 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1444
1445                 if(distance_f >= radius_f)
1446                 {
1447                         removed_objects.insert(id);
1448                         continue;
1449                 }
1450                 
1451                 // Not removed
1452         }
1453 }
1454
1455 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1456 {
1457         if(m_active_object_messages.empty())
1458                 return ActiveObjectMessage(0);
1459         
1460         ActiveObjectMessage message = m_active_object_messages.front();
1461         m_active_object_messages.pop_front();
1462         return message;
1463 }
1464
1465 /*
1466         ************ Private methods *************
1467 */
1468
1469 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1470                 bool set_changed, u32 dtime_s)
1471 {
1472         assert(object);
1473         if(object->getId() == 0){
1474                 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
1475                 if(new_id == 0)
1476                 {
1477                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1478                                         <<"no free ids available"<<std::endl;
1479                         if(object->environmentDeletes())
1480                                 delete object;
1481                         return 0;
1482                 }
1483                 object->setId(new_id);
1484         }
1485         else{
1486                 verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1487                                 <<"supplied with id "<<object->getId()<<std::endl;
1488         }
1489         if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
1490         {
1491                 errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1492                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1493                 if(object->environmentDeletes())
1494                         delete object;
1495                 return 0;
1496         }
1497         /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1498                         <<"added (id="<<object->getId()<<")"<<std::endl;*/
1499                         
1500         m_active_objects[object->getId()] = object;
1501   
1502         verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1503                         <<"Added id="<<object->getId()<<"; there are now "
1504                         <<m_active_objects.size()<<" active objects."
1505                         <<std::endl;
1506         
1507         // Register reference in scripting api (must be done before post-init)
1508         m_script->addObjectReference(object);
1509         // Post-initialize object
1510         object->addedToEnvironment(dtime_s);
1511         
1512         // Add static data to block
1513         if(object->isStaticAllowed())
1514         {
1515                 // Add static object to active static list of the block
1516                 v3f objectpos = object->getBasePosition();
1517                 std::string staticdata = object->getStaticData();
1518                 StaticObject s_obj(object->getType(), objectpos, staticdata);
1519                 // Add to the block where the object is located in
1520                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1521                 MapBlock *block = m_map->emergeBlock(blockpos);
1522                 if(block){
1523                         block->m_static_objects.m_active[object->getId()] = s_obj;
1524                         object->m_static_exists = true;
1525                         object->m_static_block = blockpos;
1526
1527                         if(set_changed)
1528                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1529                                                 "addActiveObjectRaw");
1530                 } else {
1531                         v3s16 p = floatToInt(objectpos, BS);
1532                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1533                                         <<"could not emerge block for storing id="<<object->getId()
1534                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1535                 }
1536         }
1537         
1538         return object->getId();
1539 }
1540
1541 /*
1542         Remove objects that satisfy (m_removed && m_known_by_count==0)
1543 */
1544 void ServerEnvironment::removeRemovedObjects()
1545 {
1546         std::list<u16> objects_to_remove;
1547         for(std::map<u16, ServerActiveObject*>::iterator
1548                         i = m_active_objects.begin();
1549                         i != m_active_objects.end(); ++i)
1550         {
1551                 u16 id = i->first;
1552                 ServerActiveObject* obj = i->second;
1553                 // This shouldn't happen but check it
1554                 if(obj == NULL)
1555                 {
1556                         infostream<<"NULL object found in ServerEnvironment"
1557                                         <<" while finding removed objects. id="<<id<<std::endl;
1558                         // Id to be removed from m_active_objects
1559                         objects_to_remove.push_back(id);
1560                         continue;
1561                 }
1562
1563                 /*
1564                         We will delete objects that are marked as removed or thatare
1565                         waiting for deletion after deactivation
1566                 */
1567                 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1568                         continue;
1569
1570                 /*
1571                         Delete static data from block if is marked as removed
1572                 */
1573                 if(obj->m_static_exists && obj->m_removed)
1574                 {
1575                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1576                         if (block) {
1577                                 block->m_static_objects.remove(id);
1578                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1579                                                 "removeRemovedObjects/remove");
1580                                 obj->m_static_exists = false;
1581                         } else {
1582                                 infostream<<"Failed to emerge block from which an object to "
1583                                                 <<"be removed was loaded from. id="<<id<<std::endl;
1584                         }
1585                 }
1586
1587                 // If m_known_by_count > 0, don't actually remove. On some future
1588                 // invocation this will be 0, which is when removal will continue.
1589                 if(obj->m_known_by_count > 0)
1590                         continue;
1591
1592                 /*
1593                         Move static data from active to stored if not marked as removed
1594                 */
1595                 if(obj->m_static_exists && !obj->m_removed){
1596                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1597                         if (block) {
1598                                 std::map<u16, StaticObject>::iterator i =
1599                                                 block->m_static_objects.m_active.find(id);
1600                                 if(i != block->m_static_objects.m_active.end()){
1601                                         block->m_static_objects.m_stored.push_back(i->second);
1602                                         block->m_static_objects.m_active.erase(id);
1603                                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1604                                                         "removeRemovedObjects/deactivate");
1605                                 }
1606                         } else {
1607                                 infostream<<"Failed to emerge block from which an object to "
1608                                                 <<"be deactivated was loaded from. id="<<id<<std::endl;
1609                         }
1610                 }
1611
1612                 // Tell the object about removal
1613                 obj->removingFromEnvironment();
1614                 // Deregister in scripting api
1615                 m_script->removeObjectReference(obj);
1616
1617                 // Delete
1618                 if(obj->environmentDeletes())
1619                         delete obj;
1620                 // Id to be removed from m_active_objects
1621                 objects_to_remove.push_back(id);
1622         }
1623         // Remove references from m_active_objects
1624         for(std::list<u16>::iterator i = objects_to_remove.begin();
1625                         i != objects_to_remove.end(); ++i)
1626         {
1627                 m_active_objects.erase(*i);
1628         }
1629 }
1630
1631 static void print_hexdump(std::ostream &o, const std::string &data)
1632 {
1633         const int linelength = 16;
1634         for(int l=0; ; l++){
1635                 int i0 = linelength * l;
1636                 bool at_end = false;
1637                 int thislinelength = linelength;
1638                 if(i0 + thislinelength > (int)data.size()){
1639                         thislinelength = data.size() - i0;
1640                         at_end = true;
1641                 }
1642                 for(int di=0; di<linelength; di++){
1643                         int i = i0 + di;
1644                         char buf[4];
1645                         if(di<thislinelength)
1646                                 snprintf(buf, 4, "%.2x ", data[i]);
1647                         else
1648                                 snprintf(buf, 4, "   ");
1649                         o<<buf;
1650                 }
1651                 o<<" ";
1652                 for(int di=0; di<thislinelength; di++){
1653                         int i = i0 + di;
1654                         if(data[i] >= 32)
1655                                 o<<data[i];
1656                         else
1657                                 o<<".";
1658                 }
1659                 o<<std::endl;
1660                 if(at_end)
1661                         break;
1662         }
1663 }
1664
1665 /*
1666         Convert stored objects from blocks near the players to active.
1667 */
1668 void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
1669 {
1670         if(block==NULL)
1671                 return;
1672         // Ignore if no stored objects (to not set changed flag)
1673         if(block->m_static_objects.m_stored.size() == 0)
1674                 return;
1675         verbosestream<<"ServerEnvironment::activateObjects(): "
1676                         <<"activating objects of block "<<PP(block->getPos())
1677                         <<" ("<<block->m_static_objects.m_stored.size()
1678                         <<" objects)"<<std::endl;
1679         bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
1680         if(large_amount){
1681                 errorstream<<"suspiciously large amount of objects detected: "
1682                                 <<block->m_static_objects.m_stored.size()<<" in "
1683                                 <<PP(block->getPos())
1684                                 <<"; removing all of them."<<std::endl;
1685                 // Clear stored list
1686                 block->m_static_objects.m_stored.clear();
1687                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1688                                 "stored list cleared in activateObjects due to "
1689                                 "large amount of objects");
1690                 return;
1691         }
1692
1693         // Activate stored objects
1694         std::list<StaticObject> new_stored;
1695         for(std::list<StaticObject>::iterator
1696                         i = block->m_static_objects.m_stored.begin();
1697                         i != block->m_static_objects.m_stored.end(); ++i)
1698         {
1699                 /*infostream<<"Server: Creating an active object from "
1700                                 <<"static data"<<std::endl;*/
1701                 StaticObject &s_obj = *i;
1702                 // Create an active object from the data
1703                 ServerActiveObject *obj = ServerActiveObject::create
1704                                 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1705                 // If couldn't create object, store static data back.
1706                 if(obj==NULL)
1707                 {
1708                         errorstream<<"ServerEnvironment::activateObjects(): "
1709                                         <<"failed to create active object from static object "
1710                                         <<"in block "<<PP(s_obj.pos/BS)
1711                                         <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
1712                         print_hexdump(verbosestream, s_obj.data);
1713                         
1714                         new_stored.push_back(s_obj);
1715                         continue;
1716                 }
1717                 verbosestream<<"ServerEnvironment::activateObjects(): "
1718                                 <<"activated static object pos="<<PP(s_obj.pos/BS)
1719                                 <<" type="<<(int)s_obj.type<<std::endl;
1720                 // This will also add the object to the active static list
1721                 addActiveObjectRaw(obj, false, dtime_s);
1722         }
1723         // Clear stored list
1724         block->m_static_objects.m_stored.clear();
1725         // Add leftover failed stuff to stored list
1726         for(std::list<StaticObject>::iterator
1727                         i = new_stored.begin();
1728                         i != new_stored.end(); ++i)
1729         {
1730                 StaticObject &s_obj = *i;
1731                 block->m_static_objects.m_stored.push_back(s_obj);
1732         }
1733
1734         // Turn the active counterparts of activated objects not pending for
1735         // deactivation
1736         for(std::map<u16, StaticObject>::iterator
1737                         i = block->m_static_objects.m_active.begin();
1738                         i != block->m_static_objects.m_active.end(); ++i)
1739         {
1740                 u16 id = i->first;
1741                 ServerActiveObject *object = getActiveObject(id);
1742                 assert(object);
1743                 object->m_pending_deactivation = false;
1744         }
1745
1746         /*
1747                 Note: Block hasn't really been modified here.
1748                 The objects have just been activated and moved from the stored
1749                 static list to the active static list.
1750                 As such, the block is essentially the same.
1751                 Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
1752                 Otherwise there would be a huge amount of unnecessary I/O.
1753         */
1754 }
1755
1756 /*
1757         Convert objects that are not standing inside active blocks to static.
1758
1759         If m_known_by_count != 0, active object is not deleted, but static
1760         data is still updated.
1761
1762         If force_delete is set, active object is deleted nevertheless. It
1763         shall only be set so in the destructor of the environment.
1764
1765         If block wasn't generated (not in memory or on disk),
1766 */
1767 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1768 {
1769         std::list<u16> objects_to_remove;
1770         for(std::map<u16, ServerActiveObject*>::iterator
1771                         i = m_active_objects.begin();
1772                         i != m_active_objects.end(); ++i)
1773         {
1774                 ServerActiveObject* obj = i->second;
1775                 assert(obj);
1776                 
1777                 // Do not deactivate if static data creation not allowed
1778                 if(!force_delete && !obj->isStaticAllowed())
1779                         continue;
1780
1781                 // If pending deactivation, let removeRemovedObjects() do it
1782                 if(!force_delete && obj->m_pending_deactivation)
1783                         continue;
1784
1785                 u16 id = i->first;
1786                 v3f objectpos = obj->getBasePosition();
1787
1788                 // The block in which the object resides in
1789                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1790
1791                 // If object's static data is stored in a deactivated block and object
1792                 // is actually located in an active block, re-save to the block in
1793                 // which the object is actually located in.
1794                 if(!force_delete &&
1795                                 obj->m_static_exists &&
1796                                 !m_active_blocks.contains(obj->m_static_block) &&
1797                                  m_active_blocks.contains(blockpos_o))
1798                 {
1799                         v3s16 old_static_block = obj->m_static_block;
1800
1801                         // Save to block where object is located
1802                         MapBlock *block = m_map->emergeBlock(blockpos_o, false);
1803                         if(!block){
1804                                 errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1805                                                 <<"Could not save object id="<<id
1806                                                 <<" to it's current block "<<PP(blockpos_o)
1807                                                 <<std::endl;
1808                                 continue;
1809                         }
1810                         std::string staticdata_new = obj->getStaticData();
1811                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1812                         block->m_static_objects.insert(id, s_obj);
1813                         obj->m_static_block = blockpos_o;
1814                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1815                                         "deactivateFarObjects: Static data moved in");
1816
1817                         // Delete from block where object was located
1818                         block = m_map->emergeBlock(old_static_block, false);
1819                         if(!block){
1820                                 errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1821                                                 <<"Could not delete object id="<<id
1822                                                 <<" from it's previous block "<<PP(old_static_block)
1823                                                 <<std::endl;
1824                                 continue;
1825                         }
1826                         block->m_static_objects.remove(id);
1827                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1828                                         "deactivateFarObjects: Static data moved out");
1829                         continue;
1830                 }
1831
1832                 // If block is active, don't remove
1833                 if(!force_delete && m_active_blocks.contains(blockpos_o))
1834                         continue;
1835
1836                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1837                                 <<"deactivating object id="<<id<<" on inactive block "
1838                                 <<PP(blockpos_o)<<std::endl;
1839
1840                 // If known by some client, don't immediately delete.
1841                 bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
1842
1843                 /*
1844                         Update the static data
1845                 */
1846
1847                 if(obj->isStaticAllowed())
1848                 {
1849                         // Create new static object
1850                         std::string staticdata_new = obj->getStaticData();
1851                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1852                         
1853                         bool stays_in_same_block = false;
1854                         bool data_changed = true;
1855
1856                         if(obj->m_static_exists){
1857                                 if(obj->m_static_block == blockpos_o)
1858                                         stays_in_same_block = true;
1859
1860                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1861                                 
1862                                 std::map<u16, StaticObject>::iterator n =
1863                                                 block->m_static_objects.m_active.find(id);
1864                                 if(n != block->m_static_objects.m_active.end()){
1865                                         StaticObject static_old = n->second;
1866
1867                                         float save_movem = obj->getMinimumSavedMovement();
1868
1869                                         if(static_old.data == staticdata_new &&
1870                                                         (static_old.pos - objectpos).getLength() < save_movem)
1871                                                 data_changed = false;
1872                                 } else {
1873                                         errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1874                                                         <<"id="<<id<<" m_static_exists=true but "
1875                                                         <<"static data doesn't actually exist in "
1876                                                         <<PP(obj->m_static_block)<<std::endl;
1877                                 }
1878                         }
1879
1880                         bool shall_be_written = (!stays_in_same_block || data_changed);
1881                         
1882                         // Delete old static object
1883                         if(obj->m_static_exists)
1884                         {
1885                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1886                                 if(block)
1887                                 {
1888                                         block->m_static_objects.remove(id);
1889                                         obj->m_static_exists = false;
1890                                         // Only mark block as modified if data changed considerably
1891                                         if(shall_be_written)
1892                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1893                                                                 "deactivateFarObjects: Static data "
1894                                                                 "changed considerably");
1895                                 }
1896                         }
1897
1898                         // Add to the block where the object is located in
1899                         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1900                         // Get or generate the block
1901                         MapBlock *block = NULL;
1902                         try{
1903                                 block = m_map->emergeBlock(blockpos);
1904                         } catch(InvalidPositionException &e){
1905                                 // Handled via NULL pointer
1906                                 // NOTE: emergeBlock's failure is usually determined by it
1907                                 //       actually returning NULL
1908                         }
1909
1910                         if(block)
1911                         {
1912                                 if(block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")){
1913                                         errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
1914                                                         <<" statically but block "<<PP(blockpos)
1915                                                         <<" already contains "
1916                                                         <<block->m_static_objects.m_stored.size()
1917                                                         <<" objects."
1918                                                         <<" Forcing delete."<<std::endl;
1919                                         force_delete = true;
1920                                 } else {
1921                                         // If static counterpart already exists in target block,
1922                                         // remove it first.
1923                                         // This shouldn't happen because the object is removed from
1924                                         // the previous block before this according to
1925                                         // obj->m_static_block, but happens rarely for some unknown
1926                                         // reason. Unsuccessful attempts have been made to find
1927                                         // said reason.
1928                                         if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
1929                                                 infostream<<"ServerEnv: WARNING: Performing hack #83274"
1930                                                                 <<std::endl;
1931                                                 block->m_static_objects.remove(id);
1932                                         }
1933                                         // Store static data
1934                                         u16 store_id = pending_delete ? id : 0;
1935                                         block->m_static_objects.insert(store_id, s_obj);
1936                                         
1937                                         // Only mark block as modified if data changed considerably
1938                                         if(shall_be_written)
1939                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1940                                                                 "deactivateFarObjects: Static data "
1941                                                                 "changed considerably");
1942                                         
1943                                         obj->m_static_exists = true;
1944                                         obj->m_static_block = block->getPos();
1945                                 }
1946                         }
1947                         else{
1948                                 if(!force_delete){
1949                                         v3s16 p = floatToInt(objectpos, BS);
1950                                         errorstream<<"ServerEnv: Could not find or generate "
1951                                                         <<"a block for storing id="<<obj->getId()
1952                                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1953                                         continue;
1954                                 }
1955                         }
1956                 }
1957
1958                 /*
1959                         If known by some client, set pending deactivation.
1960                         Otherwise delete it immediately.
1961                 */
1962
1963                 if(pending_delete && !force_delete)
1964                 {
1965                         verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1966                                         <<"object id="<<id<<" is known by clients"
1967                                         <<"; not deleting yet"<<std::endl;
1968
1969                         obj->m_pending_deactivation = true;
1970                         continue;
1971                 }
1972                 
1973                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1974                                 <<"object id="<<id<<" is not known by clients"
1975                                 <<"; deleting"<<std::endl;
1976
1977                 // Tell the object about removal
1978                 obj->removingFromEnvironment();
1979                 // Deregister in scripting api
1980                 m_script->removeObjectReference(obj);
1981
1982                 // Delete active object
1983                 if(obj->environmentDeletes())
1984                         delete obj;
1985                 // Id to be removed from m_active_objects
1986                 objects_to_remove.push_back(id);
1987         }
1988
1989         // Remove references from m_active_objects
1990         for(std::list<u16>::iterator i = objects_to_remove.begin();
1991                         i != objects_to_remove.end(); ++i)
1992         {
1993                 m_active_objects.erase(*i);
1994         }
1995 }
1996
1997
1998 #ifndef SERVER
1999
2000 #include "clientsimpleobject.h"
2001
2002 /*
2003         ClientEnvironment
2004 */
2005
2006 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
2007                 ITextureSource *texturesource, IGameDef *gamedef,
2008                 IrrlichtDevice *irr):
2009         m_map(map),
2010         m_smgr(smgr),
2011         m_texturesource(texturesource),
2012         m_gamedef(gamedef),
2013         m_irr(irr)
2014 {
2015         char zero = 0;
2016         memset(m_attachements, zero, sizeof(m_attachements));
2017 }
2018
2019 ClientEnvironment::~ClientEnvironment()
2020 {
2021         // delete active objects
2022         for(std::map<u16, ClientActiveObject*>::iterator
2023                         i = m_active_objects.begin();
2024                         i != m_active_objects.end(); ++i)
2025         {
2026                 delete i->second;
2027         }
2028
2029         for(std::list<ClientSimpleObject*>::iterator
2030                         i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i)
2031         {
2032                 delete *i;
2033         }
2034
2035         // Drop/delete map
2036         m_map->drop();
2037 }
2038
2039 Map & ClientEnvironment::getMap()
2040 {
2041         return *m_map;
2042 }
2043
2044 ClientMap & ClientEnvironment::getClientMap()
2045 {
2046         return *m_map;
2047 }
2048
2049 void ClientEnvironment::addPlayer(Player *player)
2050 {
2051         DSTACK(__FUNCTION_NAME);
2052         /*
2053                 It is a failure if player is local and there already is a local
2054                 player
2055         */
2056         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
2057
2058         Environment::addPlayer(player);
2059 }
2060
2061 LocalPlayer * ClientEnvironment::getLocalPlayer()
2062 {
2063         for(std::list<Player*>::iterator i = m_players.begin();
2064                         i != m_players.end(); ++i)
2065         {
2066                 Player *player = *i;
2067                 if(player->isLocal())
2068                         return (LocalPlayer*)player;
2069         }
2070         return NULL;
2071 }
2072
2073 void ClientEnvironment::step(float dtime)
2074 {
2075         DSTACK(__FUNCTION_NAME);
2076
2077         /* Step time of day */
2078         stepTimeOfDay(dtime);
2079
2080         // Get some settings
2081         bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
2082         bool free_move = fly_allowed && g_settings->getBool("free_move");
2083
2084         // Get local player
2085         LocalPlayer *lplayer = getLocalPlayer();
2086         assert(lplayer);
2087         // collision info queue
2088         std::list<CollisionInfo> player_collisions;
2089         
2090         /*
2091                 Get the speed the player is going
2092         */
2093         bool is_climbing = lplayer->is_climbing;
2094         
2095         f32 player_speed = lplayer->getSpeed().getLength();
2096         
2097         /*
2098                 Maximum position increment
2099         */
2100         //f32 position_max_increment = 0.05*BS;
2101         f32 position_max_increment = 0.1*BS;
2102
2103         // Maximum time increment (for collision detection etc)
2104         // time = distance / speed
2105         f32 dtime_max_increment = 1;
2106         if(player_speed > 0.001)
2107                 dtime_max_increment = position_max_increment / player_speed;
2108         
2109         // Maximum time increment is 10ms or lower
2110         if(dtime_max_increment > 0.01)
2111                 dtime_max_increment = 0.01;
2112         
2113         // Don't allow overly huge dtime
2114         if(dtime > 0.5)
2115                 dtime = 0.5;
2116         
2117         f32 dtime_downcount = dtime;
2118
2119         /*
2120                 Stuff that has a maximum time increment
2121         */
2122
2123         u32 loopcount = 0;
2124         do
2125         {
2126                 loopcount++;
2127
2128                 f32 dtime_part;
2129                 if(dtime_downcount > dtime_max_increment)
2130                 {
2131                         dtime_part = dtime_max_increment;
2132                         dtime_downcount -= dtime_part;
2133                 }
2134                 else
2135                 {
2136                         dtime_part = dtime_downcount;
2137                         /*
2138                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
2139                                 when dtime_part is so small that dtime_downcount -= dtime_part
2140                                 does nothing
2141                         */
2142                         dtime_downcount = 0;
2143                 }
2144                 
2145                 /*
2146                         Handle local player
2147                 */
2148                 
2149                 {
2150                         // Apply physics
2151                         if(free_move == false && is_climbing == false)
2152                         {
2153                                 // Gravity
2154                                 v3f speed = lplayer->getSpeed();
2155                                 if(lplayer->in_liquid == false)
2156                                         speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
2157
2158                                 // Liquid floating / sinking
2159                                 if(lplayer->in_liquid && !lplayer->swimming_vertical)
2160                                         speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
2161
2162                                 // Liquid resistance
2163                                 if(lplayer->in_liquid_stable || lplayer->in_liquid)
2164                                 {
2165                                         // How much the node's viscosity blocks movement, ranges between 0 and 1
2166                                         // Should match the scale at which viscosity increase affects other liquid attributes
2167                                         const f32 viscosity_factor = 0.3;
2168
2169                                         v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
2170                                         f32 dl = d_wanted.getLength();
2171                                         if(dl > lplayer->movement_liquid_fluidity_smooth)
2172                                                 dl = lplayer->movement_liquid_fluidity_smooth;
2173                                         dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
2174                                         
2175                                         v3f d = d_wanted.normalize() * dl;
2176                                         speed += d;
2177                                         
2178 #if 0 // old code
2179                                         if(speed.X > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.X -= lplayer->movement_liquid_fluidity_smooth;
2180                                         if(speed.X < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.X += lplayer->movement_liquid_fluidity_smooth;
2181                                         if(speed.Y > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Y -= lplayer->movement_liquid_fluidity_smooth;
2182                                         if(speed.Y < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Y += lplayer->movement_liquid_fluidity_smooth;
2183                                         if(speed.Z > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Z -= lplayer->movement_liquid_fluidity_smooth;
2184                                         if(speed.Z < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Z += lplayer->movement_liquid_fluidity_smooth;
2185 #endif
2186                                 }
2187
2188                                 lplayer->setSpeed(speed);
2189                         }
2190
2191                         /*
2192                                 Move the lplayer.
2193                                 This also does collision detection.
2194                         */
2195                         lplayer->move(dtime_part, this, position_max_increment,
2196                                         &player_collisions);
2197                 }
2198         }
2199         while(dtime_downcount > 0.001);
2200                 
2201         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
2202         
2203         for(std::list<CollisionInfo>::iterator
2204                         i = player_collisions.begin();
2205                         i != player_collisions.end(); ++i)
2206         {
2207                 CollisionInfo &info = *i;
2208                 v3f speed_diff = info.new_speed - info.old_speed;;
2209                 // Handle only fall damage
2210                 // (because otherwise walking against something in fast_move kills you)
2211                 if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
2212                         continue;
2213                 // Get rid of other components
2214                 speed_diff.X = 0;
2215                 speed_diff.Z = 0;
2216                 f32 pre_factor = 1; // 1 hp per node/s
2217                 f32 tolerance = BS*14; // 5 without damage
2218                 f32 post_factor = 1; // 1 hp per node/s
2219                 if(info.type == COLLISION_NODE)
2220                 {
2221                         const ContentFeatures &f = m_gamedef->ndef()->
2222                                         get(m_map->getNodeNoEx(info.node_p));
2223                         // Determine fall damage multiplier
2224                         int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
2225                         pre_factor = 1.0 + (float)addp/100.0;
2226                 }
2227                 float speed = pre_factor * speed_diff.getLength();
2228                 if(speed > tolerance)
2229                 {
2230                         f32 damage_f = (speed - tolerance)/BS * post_factor;
2231                         u16 damage = (u16)(damage_f+0.5);
2232                         if(damage != 0){
2233                                 damageLocalPlayer(damage, true);
2234                                 MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
2235                                 m_gamedef->event()->put(e);
2236                         }
2237                 }
2238         }
2239         
2240         /*
2241                 A quick draft of lava damage
2242         */
2243         if(m_lava_hurt_interval.step(dtime, 1.0))
2244         {
2245                 v3f pf = lplayer->getPosition();
2246                 
2247                 // Feet, middle and head
2248                 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
2249                 MapNode n1 = m_map->getNodeNoEx(p1);
2250                 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
2251                 MapNode n2 = m_map->getNodeNoEx(p2);
2252                 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2253                 MapNode n3 = m_map->getNodeNoEx(p3);
2254
2255                 u32 damage_per_second = 0;
2256                 damage_per_second = MYMAX(damage_per_second,
2257                                 m_gamedef->ndef()->get(n1).damage_per_second);
2258                 damage_per_second = MYMAX(damage_per_second,
2259                                 m_gamedef->ndef()->get(n2).damage_per_second);
2260                 damage_per_second = MYMAX(damage_per_second,
2261                                 m_gamedef->ndef()->get(n3).damage_per_second);
2262                 
2263                 if(damage_per_second != 0)
2264                 {
2265                         damageLocalPlayer(damage_per_second, true);
2266                 }
2267         }
2268
2269         /*
2270                 Drowning
2271         */
2272         if(m_drowning_interval.step(dtime, 2.0))
2273         {
2274                 v3f pf = lplayer->getPosition();
2275
2276                 // head
2277                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2278                 MapNode n = m_map->getNodeNoEx(p);
2279                 ContentFeatures c = m_gamedef->ndef()->get(n);
2280                 u8 drowning_damage = c.drowning;
2281                 if(drowning_damage > 0 && lplayer->hp > 0){
2282                         u16 breath = lplayer->getBreath();
2283                         if(breath > 10){
2284                                 breath = 11;
2285                         }
2286                         if(breath > 0){
2287                                 breath -= 1;
2288                         }
2289                         lplayer->setBreath(breath);
2290                         updateLocalPlayerBreath(breath);
2291                 }
2292
2293                 if(lplayer->getBreath() == 0 && drowning_damage > 0){
2294                         damageLocalPlayer(drowning_damage, true);
2295                 }
2296         }
2297         if(m_breathing_interval.step(dtime, 0.5))
2298         {
2299                 v3f pf = lplayer->getPosition();
2300
2301                 // head
2302                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2303                 MapNode n = m_map->getNodeNoEx(p);
2304                 ContentFeatures c = m_gamedef->ndef()->get(n);
2305                 if (!lplayer->hp){
2306                         lplayer->setBreath(11);
2307                 }
2308                 else if(c.drowning == 0){
2309                         u16 breath = lplayer->getBreath();
2310                         if(breath <= 10){
2311                                 breath += 1;
2312                                 lplayer->setBreath(breath);
2313                                 updateLocalPlayerBreath(breath);
2314                         }
2315                 }
2316         }
2317
2318         /*
2319                 Stuff that can be done in an arbitarily large dtime
2320         */
2321         for(std::list<Player*>::iterator i = m_players.begin();
2322                         i != m_players.end(); ++i)
2323         {
2324                 Player *player = *i;
2325                 
2326                 /*
2327                         Handle non-local players
2328                 */
2329                 if(player->isLocal() == false)
2330                 {
2331                         // Move
2332                         player->move(dtime, this, 100*BS);
2333
2334                 }
2335                 
2336                 // Update lighting on all players on client
2337                 float light = 1.0;
2338                 try{
2339                         // Get node at head
2340                         v3s16 p = player->getLightPosition();
2341                         MapNode n = m_map->getNode(p);
2342                         light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
2343                 }
2344                 catch(InvalidPositionException &e){
2345                         light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
2346                 }
2347                 player->light = light;
2348         }
2349         
2350         /*
2351                 Step active objects and update lighting of them
2352         */
2353         
2354         g_profiler->avg("CEnv: num of objects", m_active_objects.size());
2355         bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
2356         for(std::map<u16, ClientActiveObject*>::iterator
2357                         i = m_active_objects.begin();
2358                         i != m_active_objects.end(); ++i)
2359         {
2360                 ClientActiveObject* obj = i->second;
2361                 // Step object
2362                 obj->step(dtime, this);
2363
2364                 if(update_lighting)
2365                 {
2366                         // Update lighting
2367                         u8 light = 0;
2368                         try{
2369                                 // Get node at head
2370                                 v3s16 p = obj->getLightPosition();
2371                                 MapNode n = m_map->getNode(p);
2372                                 light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2373                         }
2374                         catch(InvalidPositionException &e){
2375                                 light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2376                         }
2377                         obj->updateLight(light);
2378                 }
2379         }
2380
2381         /*
2382                 Step and handle simple objects
2383         */
2384         g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
2385         for(std::list<ClientSimpleObject*>::iterator
2386                         i = m_simple_objects.begin(); i != m_simple_objects.end();)
2387         {
2388                 ClientSimpleObject *simple = *i;
2389                 std::list<ClientSimpleObject*>::iterator cur = i;
2390                 ++i;
2391                 simple->step(dtime);
2392                 if(simple->m_to_be_removed){
2393                         delete simple;
2394                         m_simple_objects.erase(cur);
2395                 }
2396         }
2397 }
2398         
2399 void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
2400 {
2401         m_simple_objects.push_back(simple);
2402 }
2403
2404 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
2405 {
2406         std::map<u16, ClientActiveObject*>::iterator n;
2407         n = m_active_objects.find(id);
2408         if(n == m_active_objects.end())
2409                 return NULL;
2410         return n->second;
2411 }
2412
2413 bool isFreeClientActiveObjectId(u16 id,
2414                 std::map<u16, ClientActiveObject*> &objects)
2415 {
2416         if(id == 0)
2417                 return false;
2418
2419         return objects.find(id) == objects.end();
2420 }
2421
2422 u16 getFreeClientActiveObjectId(
2423                 std::map<u16, ClientActiveObject*> &objects)
2424 {
2425         //try to reuse id's as late as possible
2426         static u16 last_used_id = 0;
2427         u16 startid = last_used_id;
2428         for(;;)
2429         {
2430                 last_used_id ++;
2431                 if(isFreeClientActiveObjectId(last_used_id, objects))
2432                         return last_used_id;
2433                 
2434                 if(last_used_id == startid)
2435                         return 0;
2436         }
2437 }
2438
2439 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
2440 {
2441         assert(object);
2442         if(object->getId() == 0)
2443         {
2444                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
2445                 if(new_id == 0)
2446                 {
2447                         infostream<<"ClientEnvironment::addActiveObject(): "
2448                                         <<"no free ids available"<<std::endl;
2449                         delete object;
2450                         return 0;
2451                 }
2452                 object->setId(new_id);
2453         }
2454         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
2455         {
2456                 infostream<<"ClientEnvironment::addActiveObject(): "
2457                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
2458                 delete object;
2459                 return 0;
2460         }
2461         infostream<<"ClientEnvironment::addActiveObject(): "
2462                         <<"added (id="<<object->getId()<<")"<<std::endl;
2463         m_active_objects[object->getId()] = object;
2464         object->addToScene(m_smgr, m_texturesource, m_irr);
2465         { // Update lighting immediately
2466                 u8 light = 0;
2467                 try{
2468                         // Get node at head
2469                         v3s16 p = object->getLightPosition();
2470                         MapNode n = m_map->getNode(p);
2471                         light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2472                 }
2473                 catch(InvalidPositionException &e){
2474                         light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2475                 }
2476                 object->updateLight(light);
2477         }
2478         return object->getId();
2479 }
2480
2481 void ClientEnvironment::addActiveObject(u16 id, u8 type,
2482                 const std::string &init_data)
2483 {
2484         ClientActiveObject* obj =
2485                         ClientActiveObject::create(type, m_gamedef, this);
2486         if(obj == NULL)
2487         {
2488                 infostream<<"ClientEnvironment::addActiveObject(): "
2489                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
2490                                 <<std::endl;
2491                 return;
2492         }
2493         
2494         obj->setId(id);
2495
2496         try
2497         {
2498                 obj->initialize(init_data);
2499         }
2500         catch(SerializationError &e)
2501         {
2502                 errorstream<<"ClientEnvironment::addActiveObject():"
2503                                 <<" id="<<id<<" type="<<type
2504                                 <<": SerializationError in initialize(): "
2505                                 <<e.what()
2506                                 <<": init_data="<<serializeJsonString(init_data)
2507                                 <<std::endl;
2508         }
2509
2510         addActiveObject(obj);
2511 }
2512
2513 void ClientEnvironment::removeActiveObject(u16 id)
2514 {
2515         verbosestream<<"ClientEnvironment::removeActiveObject(): "
2516                         <<"id="<<id<<std::endl;
2517         ClientActiveObject* obj = getActiveObject(id);
2518         if(obj == NULL)
2519         {
2520                 infostream<<"ClientEnvironment::removeActiveObject(): "
2521                                 <<"id="<<id<<" not found"<<std::endl;
2522                 return;
2523         }
2524         obj->removeFromScene(true);
2525         delete obj;
2526         m_active_objects.erase(id);
2527 }
2528
2529 void ClientEnvironment::processActiveObjectMessage(u16 id,
2530                 const std::string &data)
2531 {
2532         ClientActiveObject* obj = getActiveObject(id);
2533         if(obj == NULL)
2534         {
2535                 infostream<<"ClientEnvironment::processActiveObjectMessage():"
2536                                 <<" got message for id="<<id<<", which doesn't exist."
2537                                 <<std::endl;
2538                 return;
2539         }
2540         try
2541         {
2542                 obj->processMessage(data);
2543         }
2544         catch(SerializationError &e)
2545         {
2546                 errorstream<<"ClientEnvironment::processActiveObjectMessage():"
2547                                 <<" id="<<id<<" type="<<obj->getType()
2548                                 <<" SerializationError in processMessage(),"
2549                                 <<" message="<<serializeJsonString(data)
2550                                 <<std::endl;
2551         }
2552 }
2553
2554 /*
2555         Callbacks for activeobjects
2556 */
2557
2558 void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
2559 {
2560         LocalPlayer *lplayer = getLocalPlayer();
2561         assert(lplayer);
2562         
2563         if(handle_hp){
2564                 if(lplayer->hp > damage)
2565                         lplayer->hp -= damage;
2566                 else
2567                         lplayer->hp = 0;
2568         }
2569
2570         ClientEnvEvent event;
2571         event.type = CEE_PLAYER_DAMAGE;
2572         event.player_damage.amount = damage;
2573         event.player_damage.send_to_server = handle_hp;
2574         m_client_event_queue.push_back(event);
2575 }
2576
2577 void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
2578 {
2579         ClientEnvEvent event;
2580         event.type = CEE_PLAYER_BREATH;
2581         event.player_breath.amount = breath;
2582         m_client_event_queue.push_back(event);
2583 }
2584
2585 /*
2586         Client likes to call these
2587 */
2588         
2589 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
2590                 std::vector<DistanceSortedActiveObject> &dest)
2591 {
2592         for(std::map<u16, ClientActiveObject*>::iterator
2593                         i = m_active_objects.begin();
2594                         i != m_active_objects.end(); ++i)
2595         {
2596                 ClientActiveObject* obj = i->second;
2597
2598                 f32 d = (obj->getPosition() - origin).getLength();
2599
2600                 if(d > max_d)
2601                         continue;
2602
2603                 DistanceSortedActiveObject dso(obj, d);
2604
2605                 dest.push_back(dso);
2606         }
2607 }
2608
2609 ClientEnvEvent ClientEnvironment::getClientEvent()
2610 {
2611         ClientEnvEvent event;
2612         if(m_client_event_queue.empty())
2613                 event.type = CEE_NONE;
2614         else {
2615                 event = m_client_event_queue.front();
2616                 m_client_event_queue.pop_front();
2617         }
2618         return event;
2619 }
2620
2621 #endif // #ifndef SERVER
2622
2623