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