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