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