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