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