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