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