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