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