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