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