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