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