]> git.lizzy.rs Git - minetest.git/blob - src/environment.cpp
The new mapgen, noise functions, et al.
[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                         v3s16 p = i->first + block->getPosRelative();
808                         if(scriptapi_node_on_timer(m_lua,p,n,i->second.elapsed))
809                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
810                 }
811         }
812
813         /* Handle ActiveBlockModifiers */
814         ABMHandler abmhandler(m_abms, dtime_s, this, false);
815         abmhandler.apply(block);
816 }
817
818 void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
819 {
820         m_abms.push_back(ABMWithState(abm));
821 }
822
823 bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
824 {
825         INodeDefManager *ndef = m_gamedef->ndef();
826         MapNode n_old = m_map->getNodeNoEx(p);
827         // Call destructor
828         if(ndef->get(n_old).has_on_destruct)
829                 scriptapi_node_on_destruct(m_lua, p, n_old);
830         // Replace node
831         bool succeeded = m_map->addNodeWithEvent(p, n);
832         if(!succeeded)
833                 return false;
834         // Call post-destructor
835         if(ndef->get(n_old).has_after_destruct)
836                 scriptapi_node_after_destruct(m_lua, p, n_old);
837         // Call constructor
838         if(ndef->get(n).has_on_construct)
839                 scriptapi_node_on_construct(m_lua, p, n);
840         return true;
841 }
842
843 bool ServerEnvironment::removeNode(v3s16 p)
844 {
845         INodeDefManager *ndef = m_gamedef->ndef();
846         MapNode n_old = m_map->getNodeNoEx(p);
847         // Call destructor
848         if(ndef->get(n_old).has_on_destruct)
849                 scriptapi_node_on_destruct(m_lua, p, n_old);
850         // Replace with air
851         // This is slightly optimized compared to addNodeWithEvent(air)
852         bool succeeded = m_map->removeNodeWithEvent(p);
853         if(!succeeded)
854                 return false;
855         // Call post-destructor
856         if(ndef->get(n_old).has_after_destruct)
857                 scriptapi_node_after_destruct(m_lua, p, n_old);
858         // Air doesn't require constructor
859         return true;
860 }
861
862 std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
863 {
864         std::set<u16> objects;
865         for(core::map<u16, ServerActiveObject*>::Iterator
866                         i = m_active_objects.getIterator();
867                         i.atEnd()==false; i++)
868         {
869                 ServerActiveObject* obj = i.getNode()->getValue();
870                 u16 id = i.getNode()->getKey();
871                 v3f objectpos = obj->getBasePosition();
872                 if(objectpos.getDistanceFrom(pos) > radius)
873                         continue;
874                 objects.insert(id);
875         }
876         return objects;
877 }
878
879 void ServerEnvironment::clearAllObjects()
880 {
881         infostream<<"ServerEnvironment::clearAllObjects(): "
882                         <<"Removing all active objects"<<std::endl;
883         core::list<u16> objects_to_remove;
884         for(core::map<u16, ServerActiveObject*>::Iterator
885                         i = m_active_objects.getIterator();
886                         i.atEnd()==false; i++)
887         {
888                 ServerActiveObject* obj = i.getNode()->getValue();
889                 if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
890                         continue;
891                 u16 id = i.getNode()->getKey();         
892                 v3f objectpos = obj->getBasePosition(); 
893                 // Delete static object if block is loaded
894                 if(obj->m_static_exists){
895                         MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
896                         if(block){
897                                 block->m_static_objects.remove(id);
898                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
899                                                 "clearAllObjects");
900                                 obj->m_static_exists = false;
901                         }
902                 }
903                 // If known by some client, don't delete immediately
904                 if(obj->m_known_by_count > 0){
905                         obj->m_pending_deactivation = true;
906                         obj->m_removed = true;
907                         continue;
908                 }
909
910                 // Tell the object about removal
911                 obj->removingFromEnvironment();
912                 // Deregister in scripting api
913                 scriptapi_rm_object_reference(m_lua, obj);
914
915                 // Delete active object
916                 if(obj->environmentDeletes())
917                         delete obj;
918                 // Id to be removed from m_active_objects
919                 objects_to_remove.push_back(id);
920         }
921         // Remove references from m_active_objects
922         for(core::list<u16>::Iterator i = objects_to_remove.begin();
923                         i != objects_to_remove.end(); i++)
924         {
925                 m_active_objects.remove(*i);
926         }
927
928         core::list<v3s16> loadable_blocks;
929         infostream<<"ServerEnvironment::clearAllObjects(): "
930                         <<"Listing all loadable blocks"<<std::endl;
931         m_map->listAllLoadableBlocks(loadable_blocks);
932         infostream<<"ServerEnvironment::clearAllObjects(): "
933                         <<"Done listing all loadable blocks: "
934                         <<loadable_blocks.size()
935                         <<", now clearing"<<std::endl;
936         u32 report_interval = loadable_blocks.size() / 10;
937         u32 num_blocks_checked = 0;
938         u32 num_blocks_cleared = 0;
939         u32 num_objs_cleared = 0;
940         for(core::list<v3s16>::Iterator i = loadable_blocks.begin();
941                         i != loadable_blocks.end(); i++)
942         {
943                 v3s16 p = *i;
944                 MapBlock *block = m_map->emergeBlock(p, false);
945                 if(!block){
946                         errorstream<<"ServerEnvironment::clearAllObjects(): "
947                                         <<"Failed to emerge block "<<PP(p)<<std::endl;
948                         continue;
949                 }
950                 u32 num_stored = block->m_static_objects.m_stored.size();
951                 u32 num_active = block->m_static_objects.m_active.size();
952                 if(num_stored != 0 || num_active != 0){
953                         block->m_static_objects.m_stored.clear();
954                         block->m_static_objects.m_active.clear();
955                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
956                                         "clearAllObjects");
957                         num_objs_cleared += num_stored + num_active;
958                         num_blocks_cleared++;
959                 }
960                 num_blocks_checked++;
961
962                 if(num_blocks_checked % report_interval == 0){
963                         float percent = 100.0 * (float)num_blocks_checked /
964                                         loadable_blocks.size();
965                         infostream<<"ServerEnvironment::clearAllObjects(): "
966                                         <<"Cleared "<<num_objs_cleared<<" objects"
967                                         <<" in "<<num_blocks_cleared<<" blocks ("
968                                         <<percent<<"%)"<<std::endl;
969                 }
970         }
971         infostream<<"ServerEnvironment::clearAllObjects(): "
972                         <<"Finished: Cleared "<<num_objs_cleared<<" objects"
973                         <<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
974 }
975
976 void ServerEnvironment::step(float dtime)
977 {
978         DSTACK(__FUNCTION_NAME);
979         
980         //TimeTaker timer("ServerEnv step");
981
982         /* Step time of day */
983         stepTimeOfDay(dtime);
984
985         // Update this one
986         // NOTE: This is kind of funny on a singleplayer game, but doesn't
987         // really matter that much.
988         m_recommended_send_interval = g_settings->getFloat("dedicated_server_step");
989
990         /*
991                 Increment game time
992         */
993         {
994                 m_game_time_fraction_counter += dtime;
995                 u32 inc_i = (u32)m_game_time_fraction_counter;
996                 m_game_time += inc_i;
997                 m_game_time_fraction_counter -= (float)inc_i;
998         }
999         
1000         /*
1001                 Handle players
1002         */
1003         {
1004                 ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
1005                 for(core::list<Player*>::Iterator i = m_players.begin();
1006                                 i != m_players.end(); i++)
1007                 {
1008                         Player *player = *i;
1009                         
1010                         // Ignore disconnected players
1011                         if(player->peer_id == 0)
1012                                 continue;
1013
1014                         v3f playerpos = player->getPosition();
1015                         
1016                         // Move
1017                         player->move(dtime, *m_map, 100*BS);
1018                 }
1019         }
1020
1021         /*
1022                 Manage active block list
1023         */
1024         if(m_active_blocks_management_interval.step(dtime, 2.0))
1025         {
1026                 ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg /2s", SPT_AVG);
1027                 /*
1028                         Get player block positions
1029                 */
1030                 core::list<v3s16> players_blockpos;
1031                 for(core::list<Player*>::Iterator
1032                                 i = m_players.begin();
1033                                 i != m_players.end(); i++)
1034                 {
1035                         Player *player = *i;
1036                         // Ignore disconnected players
1037                         if(player->peer_id == 0)
1038                                 continue;
1039                         v3s16 blockpos = getNodeBlockPos(
1040                                         floatToInt(player->getPosition(), BS));
1041                         players_blockpos.push_back(blockpos);
1042                 }
1043                 
1044                 /*
1045                         Update list of active blocks, collecting changes
1046                 */
1047                 const s16 active_block_range = g_settings->getS16("active_block_range");
1048                 core::map<v3s16, bool> blocks_removed;
1049                 core::map<v3s16, bool> blocks_added;
1050                 m_active_blocks.update(players_blockpos, active_block_range,
1051                                 blocks_removed, blocks_added);
1052
1053                 /*
1054                         Handle removed blocks
1055                 */
1056
1057                 // Convert active objects that are no more in active blocks to static
1058                 deactivateFarObjects(false);
1059                 
1060                 for(core::map<v3s16, bool>::Iterator
1061                                 i = blocks_removed.getIterator();
1062                                 i.atEnd()==false; i++)
1063                 {
1064                         v3s16 p = i.getNode()->getKey();
1065
1066                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1067                                         <<") became inactive"<<std::endl;*/
1068                         
1069                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1070                         if(block==NULL)
1071                                 continue;
1072                         
1073                         // Set current time as timestamp (and let it set ChangedFlag)
1074                         block->setTimestamp(m_game_time);
1075                 }
1076
1077                 /*
1078                         Handle added blocks
1079                 */
1080
1081                 for(core::map<v3s16, bool>::Iterator
1082                                 i = blocks_added.getIterator();
1083                                 i.atEnd()==false; i++)
1084                 {
1085                         v3s16 p = i.getNode()->getKey();
1086                         
1087                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1088                                         <<") became active"<<std::endl;*/
1089
1090                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1091                         if(block==NULL){
1092                                 // Block needs to be fetched first
1093                                 m_emerger->queueBlockEmerge(p, false);
1094                                 m_active_blocks.m_list.remove(p);
1095                                 continue;
1096                         }
1097
1098                         activateBlock(block);
1099                 }
1100         }
1101
1102         /*
1103                 Mess around in active blocks
1104         */
1105         if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
1106         {
1107                 ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg /1s", SPT_AVG);
1108                 
1109                 float dtime = 1.0;
1110
1111                 for(core::map<v3s16, bool>::Iterator
1112                                 i = m_active_blocks.m_list.getIterator();
1113                                 i.atEnd()==false; i++)
1114                 {
1115                         v3s16 p = i.getNode()->getKey();
1116                         
1117                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1118                                         <<") being handled"<<std::endl;*/
1119
1120                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1121                         if(block==NULL)
1122                                 continue;
1123
1124                         // Reset block usage timer
1125                         block->resetUsageTimer();
1126                         
1127                         // Set current time as timestamp
1128                         block->setTimestampNoChangedFlag(m_game_time);
1129                         // If time has changed much from the one on disk,
1130                         // set block to be saved when it is unloaded
1131                         if(block->getTimestamp() > block->getDiskTimestamp() + 60)
1132                                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1133                                                 "Timestamp older than 60s (step)");
1134
1135                         // Run node timers
1136                         std::map<v3s16, NodeTimer> elapsed_timers =
1137                                 block->m_node_timers.step((float)dtime);
1138                         if(!elapsed_timers.empty()){
1139                                 MapNode n;
1140                                 for(std::map<v3s16, NodeTimer>::iterator
1141                                                 i = elapsed_timers.begin();
1142                                                 i != elapsed_timers.end(); i++){
1143                                         n = block->getNodeNoEx(i->first);
1144                                         p = i->first + block->getPosRelative();
1145                                         if(scriptapi_node_on_timer(m_lua,p,n,i->second.elapsed))
1146                                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
1147                                 }
1148                         }
1149                 }
1150         }
1151         
1152         const float abm_interval = 1.0;
1153         if(m_active_block_modifier_interval.step(dtime, abm_interval))
1154         do{ // breakable
1155                 if(m_active_block_interval_overload_skip > 0){
1156                         ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
1157                         m_active_block_interval_overload_skip--;
1158                         break;
1159                 }
1160                 ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg /1s", SPT_AVG);
1161                 TimeTaker timer("modify in active blocks");
1162                 
1163                 // Initialize handling of ActiveBlockModifiers
1164                 ABMHandler abmhandler(m_abms, abm_interval, this, true);
1165
1166                 for(core::map<v3s16, bool>::Iterator
1167                                 i = m_active_blocks.m_list.getIterator();
1168                                 i.atEnd()==false; i++)
1169                 {
1170                         v3s16 p = i.getNode()->getKey();
1171                         
1172                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1173                                         <<") being handled"<<std::endl;*/
1174
1175                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1176                         if(block==NULL)
1177                                 continue;
1178                         
1179                         // Set current time as timestamp
1180                         block->setTimestampNoChangedFlag(m_game_time);
1181
1182                         /* Handle ActiveBlockModifiers */
1183                         abmhandler.apply(block);
1184                 }
1185
1186                 u32 time_ms = timer.stop(true);
1187                 u32 max_time_ms = 200;
1188                 if(time_ms > max_time_ms){
1189                         infostream<<"WARNING: active block modifiers took "
1190                                         <<time_ms<<"ms (longer than "
1191                                         <<max_time_ms<<"ms)"<<std::endl;
1192                         m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
1193                 }
1194         }while(0);
1195         
1196         /*
1197                 Step script environment (run global on_step())
1198         */
1199         scriptapi_environment_step(m_lua, dtime);
1200
1201         /*
1202                 Step active objects
1203         */
1204         {
1205                 ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
1206                 //TimeTaker timer("Step active objects");
1207
1208                 g_profiler->avg("SEnv: num of objects", m_active_objects.size());
1209                 
1210                 // This helps the objects to send data at the same time
1211                 bool send_recommended = false;
1212                 m_send_recommended_timer += dtime;
1213                 if(m_send_recommended_timer > getSendRecommendedInterval())
1214                 {
1215                         m_send_recommended_timer -= getSendRecommendedInterval();
1216                         send_recommended = true;
1217                 }
1218
1219                 for(core::map<u16, ServerActiveObject*>::Iterator
1220                                 i = m_active_objects.getIterator();
1221                                 i.atEnd()==false; i++)
1222                 {
1223                         ServerActiveObject* obj = i.getNode()->getValue();
1224                         // Remove non-peaceful mobs on peaceful mode
1225                         if(g_settings->getBool("only_peaceful_mobs")){
1226                                 if(!obj->isPeaceful())
1227                                         obj->m_removed = true;
1228                         }
1229                         // Don't step if is to be removed or stored statically
1230                         if(obj->m_removed || obj->m_pending_deactivation)
1231                                 continue;
1232                         // Step object
1233                         obj->step(dtime, send_recommended);
1234                         // Read messages from object
1235                         while(obj->m_messages_out.size() > 0)
1236                         {
1237                                 m_active_object_messages.push_back(
1238                                                 obj->m_messages_out.pop_front());
1239                         }
1240                 }
1241         }
1242         
1243         /*
1244                 Manage active objects
1245         */
1246         if(m_object_management_interval.step(dtime, 0.5))
1247         {
1248                 ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
1249                 /*
1250                         Remove objects that satisfy (m_removed && m_known_by_count==0)
1251                 */
1252                 removeRemovedObjects();
1253         }
1254 }
1255
1256 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
1257 {
1258         core::map<u16, ServerActiveObject*>::Node *n;
1259         n = m_active_objects.find(id);
1260         if(n == NULL)
1261                 return NULL;
1262         return n->getValue();
1263 }
1264
1265 bool isFreeServerActiveObjectId(u16 id,
1266                 core::map<u16, ServerActiveObject*> &objects)
1267 {
1268         if(id == 0)
1269                 return false;
1270         
1271         for(core::map<u16, ServerActiveObject*>::Iterator
1272                         i = objects.getIterator();
1273                         i.atEnd()==false; i++)
1274         {
1275                 if(i.getNode()->getKey() == id)
1276                         return false;
1277         }
1278         return true;
1279 }
1280
1281 u16 getFreeServerActiveObjectId(
1282                 core::map<u16, ServerActiveObject*> &objects)
1283 {
1284         u16 new_id = 1;
1285         for(;;)
1286         {
1287                 if(isFreeServerActiveObjectId(new_id, objects))
1288                         return new_id;
1289                 
1290                 if(new_id == 65535)
1291                         return 0;
1292
1293                 new_id++;
1294         }
1295 }
1296
1297 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1298 {
1299         assert(object);
1300         u16 id = addActiveObjectRaw(object, true, 0);
1301         return id;
1302 }
1303
1304 #if 0
1305 bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
1306 {
1307         assert(obj);
1308
1309         v3f objectpos = obj->getBasePosition(); 
1310
1311         // The block in which the object resides in
1312         v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1313
1314         /*
1315                 Update the static data
1316         */
1317
1318         // Create new static object
1319         std::string staticdata = obj->getStaticData();
1320         StaticObject s_obj(obj->getType(), objectpos, staticdata);
1321         // Add to the block where the object is located in
1322         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1323         // Get or generate the block
1324         MapBlock *block = m_map->emergeBlock(blockpos);
1325
1326         bool succeeded = false;
1327
1328         if(block)
1329         {
1330                 block->m_static_objects.insert(0, s_obj);
1331                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1332                                 "addActiveObjectAsStatic");
1333                 succeeded = true;
1334         }
1335         else{
1336                 infostream<<"ServerEnvironment::addActiveObjectAsStatic: "
1337                                 <<"Could not find or generate "
1338                                 <<"a block for storing static object"<<std::endl;
1339                 succeeded = false;
1340         }
1341
1342         if(obj->environmentDeletes())
1343                 delete obj;
1344
1345         return succeeded;
1346 }
1347 #endif
1348
1349 /*
1350         Finds out what new objects have been added to
1351         inside a radius around a position
1352 */
1353 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1354                 core::map<u16, bool> &current_objects,
1355                 core::map<u16, bool> &added_objects)
1356 {
1357         v3f pos_f = intToFloat(pos, BS);
1358         f32 radius_f = radius * BS;
1359         /*
1360                 Go through the object list,
1361                 - discard m_removed objects,
1362                 - discard objects that are too far away,
1363                 - discard objects that are found in current_objects.
1364                 - add remaining objects to added_objects
1365         */
1366         for(core::map<u16, ServerActiveObject*>::Iterator
1367                         i = m_active_objects.getIterator();
1368                         i.atEnd()==false; i++)
1369         {
1370                 u16 id = i.getNode()->getKey();
1371                 // Get object
1372                 ServerActiveObject *object = i.getNode()->getValue();
1373                 if(object == NULL)
1374                         continue;
1375                 // Discard if removed
1376                 if(object->m_removed)
1377                         continue;
1378                 if(object->unlimitedTransferDistance() == false){
1379                         // Discard if too far
1380                         f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1381                         if(distance_f > radius_f)
1382                                 continue;
1383                 }
1384                 // Discard if already on current_objects
1385                 core::map<u16, bool>::Node *n;
1386                 n = current_objects.find(id);
1387                 if(n != NULL)
1388                         continue;
1389                 // Add to added_objects
1390                 added_objects.insert(id, false);
1391         }
1392 }
1393
1394 /*
1395         Finds out what objects have been removed from
1396         inside a radius around a position
1397 */
1398 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1399                 core::map<u16, bool> &current_objects,
1400                 core::map<u16, bool> &removed_objects)
1401 {
1402         v3f pos_f = intToFloat(pos, BS);
1403         f32 radius_f = radius * BS;
1404         /*
1405                 Go through current_objects; object is removed if:
1406                 - object is not found in m_active_objects (this is actually an
1407                   error condition; objects should be set m_removed=true and removed
1408                   only after all clients have been informed about removal), or
1409                 - object has m_removed=true, or
1410                 - object is too far away
1411         */
1412         for(core::map<u16, bool>::Iterator
1413                         i = current_objects.getIterator();
1414                         i.atEnd()==false; i++)
1415         {
1416                 u16 id = i.getNode()->getKey();
1417                 ServerActiveObject *object = getActiveObject(id);
1418
1419                 if(object == NULL){
1420                         infostream<<"ServerEnvironment::getRemovedActiveObjects():"
1421                                         <<" object in current_objects is NULL"<<std::endl;
1422                         removed_objects.insert(id, false);
1423                         continue;
1424                 }
1425
1426                 if(object->m_removed)
1427                 {
1428                         removed_objects.insert(id, false);
1429                         continue;
1430                 }
1431                 
1432                 // If transfer distance is unlimited, don't remove
1433                 if(object->unlimitedTransferDistance())
1434                         continue;
1435
1436                 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1437
1438                 if(distance_f >= radius_f)
1439                 {
1440                         removed_objects.insert(id, false);
1441                         continue;
1442                 }
1443                 
1444                 // Not removed
1445         }
1446 }
1447
1448 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1449 {
1450         if(m_active_object_messages.size() == 0)
1451                 return ActiveObjectMessage(0);
1452         
1453         return m_active_object_messages.pop_front();
1454 }
1455
1456 /*
1457         ************ Private methods *************
1458 */
1459
1460 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1461                 bool set_changed, u32 dtime_s)
1462 {
1463         assert(object);
1464         if(object->getId() == 0){
1465                 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
1466                 if(new_id == 0)
1467                 {
1468                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1469                                         <<"no free ids available"<<std::endl;
1470                         if(object->environmentDeletes())
1471                                 delete object;
1472                         return 0;
1473                 }
1474                 object->setId(new_id);
1475         }
1476         else{
1477                 verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1478                                 <<"supplied with id "<<object->getId()<<std::endl;
1479         }
1480         if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
1481         {
1482                 errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1483                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1484                 if(object->environmentDeletes())
1485                         delete object;
1486                 return 0;
1487         }
1488         /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1489                         <<"added (id="<<object->getId()<<")"<<std::endl;*/
1490                         
1491         m_active_objects.insert(object->getId(), object);
1492   
1493         verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1494                         <<"Added id="<<object->getId()<<"; there are now "
1495                         <<m_active_objects.size()<<" active objects."
1496                         <<std::endl;
1497         
1498         // Register reference in scripting api (must be done before post-init)
1499         scriptapi_add_object_reference(m_lua, object);
1500         // Post-initialize object
1501         object->addedToEnvironment(dtime_s);
1502         
1503         // Add static data to block
1504         if(object->isStaticAllowed())
1505         {
1506                 // Add static object to active static list of the block
1507                 v3f objectpos = object->getBasePosition();
1508                 std::string staticdata = object->getStaticData();
1509                 StaticObject s_obj(object->getType(), objectpos, staticdata);
1510                 // Add to the block where the object is located in
1511                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1512                 MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1513                 if(block)
1514                 {
1515                         block->m_static_objects.m_active.insert(object->getId(), s_obj);
1516                         object->m_static_exists = true;
1517                         object->m_static_block = blockpos;
1518
1519                         if(set_changed)
1520                                 block->raiseModified(MOD_STATE_WRITE_NEEDED, 
1521                                                 "addActiveObjectRaw");
1522                 }
1523                 else{
1524                         v3s16 p = floatToInt(objectpos, BS);
1525                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1526                                         <<"could not find block for storing id="<<object->getId()
1527                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1528                 }
1529         }
1530         
1531         return object->getId();
1532 }
1533
1534 /*
1535         Remove objects that satisfy (m_removed && m_known_by_count==0)
1536 */
1537 void ServerEnvironment::removeRemovedObjects()
1538 {
1539         core::list<u16> objects_to_remove;
1540         for(core::map<u16, ServerActiveObject*>::Iterator
1541                         i = m_active_objects.getIterator();
1542                         i.atEnd()==false; i++)
1543         {
1544                 u16 id = i.getNode()->getKey();
1545                 ServerActiveObject* obj = i.getNode()->getValue();
1546                 // This shouldn't happen but check it
1547                 if(obj == NULL)
1548                 {
1549                         infostream<<"NULL object found in ServerEnvironment"
1550                                         <<" while finding removed objects. id="<<id<<std::endl;
1551                         // Id to be removed from m_active_objects
1552                         objects_to_remove.push_back(id);
1553                         continue;
1554                 }
1555
1556                 /*
1557                         We will delete objects that are marked as removed or thatare
1558                         waiting for deletion after deactivation
1559                 */
1560                 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1561                         continue;
1562
1563                 /*
1564                         Delete static data from block if is marked as removed
1565                 */
1566                 if(obj->m_static_exists && obj->m_removed)
1567                 {
1568                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1569                         if (block) {
1570                                 block->m_static_objects.remove(id);
1571                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1572                                                 "removeRemovedObjects");
1573                                 obj->m_static_exists = false;
1574                         } else {
1575                                 infostream << "failed to emerge block from which "
1576                                         "an object to be removed was loaded from. id="<<id<<std::endl;
1577                         }
1578                 }
1579
1580                 // If m_known_by_count > 0, don't actually remove.
1581                 if(obj->m_known_by_count > 0)
1582                         continue;
1583                 
1584                 // Tell the object about removal
1585                 obj->removingFromEnvironment();
1586                 // Deregister in scripting api
1587                 scriptapi_rm_object_reference(m_lua, obj);
1588
1589                 // Delete
1590                 if(obj->environmentDeletes())
1591                         delete obj;
1592                 // Id to be removed from m_active_objects
1593                 objects_to_remove.push_back(id);
1594         }
1595         // Remove references from m_active_objects
1596         for(core::list<u16>::Iterator i = objects_to_remove.begin();
1597                         i != objects_to_remove.end(); i++)
1598         {
1599                 m_active_objects.remove(*i);
1600         }
1601 }
1602
1603 static void print_hexdump(std::ostream &o, const std::string &data)
1604 {
1605         const int linelength = 16;
1606         for(int l=0; ; l++){
1607                 int i0 = linelength * l;
1608                 bool at_end = false;
1609                 int thislinelength = linelength;
1610                 if(i0 + thislinelength > (int)data.size()){
1611                         thislinelength = data.size() - i0;
1612                         at_end = true;
1613                 }
1614                 for(int di=0; di<linelength; di++){
1615                         int i = i0 + di;
1616                         char buf[4];
1617                         if(di<thislinelength)
1618                                 snprintf(buf, 4, "%.2x ", data[i]);
1619                         else
1620                                 snprintf(buf, 4, "   ");
1621                         o<<buf;
1622                 }
1623                 o<<" ";
1624                 for(int di=0; di<thislinelength; di++){
1625                         int i = i0 + di;
1626                         if(data[i] >= 32)
1627                                 o<<data[i];
1628                         else
1629                                 o<<".";
1630                 }
1631                 o<<std::endl;
1632                 if(at_end)
1633                         break;
1634         }
1635 }
1636
1637 /*
1638         Convert stored objects from blocks near the players to active.
1639 */
1640 void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
1641 {
1642         if(block==NULL)
1643                 return;
1644         // Ignore if no stored objects (to not set changed flag)
1645         if(block->m_static_objects.m_stored.size() == 0)
1646                 return;
1647         verbosestream<<"ServerEnvironment::activateObjects(): "
1648                         <<"activating objects of block "<<PP(block->getPos())
1649                         <<" ("<<block->m_static_objects.m_stored.size()
1650                         <<" objects)"<<std::endl;
1651         bool large_amount = (block->m_static_objects.m_stored.size() > 49);
1652         if(large_amount){
1653                 errorstream<<"suspiciously large amount of objects detected: "
1654                                 <<block->m_static_objects.m_stored.size()<<" in "
1655                                 <<PP(block->getPos())
1656                                 <<"; removing all of them."<<std::endl;
1657                 // Clear stored list
1658                 block->m_static_objects.m_stored.clear();
1659                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1660                                 "stored list cleared in activateObjects due to "
1661                                 "large amount of objects");
1662                 return;
1663         }
1664         // A list for objects that couldn't be converted to active for some
1665         // reason. They will be stored back.
1666         core::list<StaticObject> new_stored;
1667         // Loop through stored static objects
1668         for(core::list<StaticObject>::Iterator
1669                         i = block->m_static_objects.m_stored.begin();
1670                         i != block->m_static_objects.m_stored.end(); i++)
1671         {
1672                 /*infostream<<"Server: Creating an active object from "
1673                                 <<"static data"<<std::endl;*/
1674                 StaticObject &s_obj = *i;
1675                 // Create an active object from the data
1676                 ServerActiveObject *obj = ServerActiveObject::create
1677                                 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1678                 // If couldn't create object, store static data back.
1679                 if(obj==NULL)
1680                 {
1681                         errorstream<<"ServerEnvironment::activateObjects(): "
1682                                         <<"failed to create active object from static object "
1683                                         <<"in block "<<PP(s_obj.pos/BS)
1684                                         <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
1685                         print_hexdump(verbosestream, s_obj.data);
1686                         
1687                         new_stored.push_back(s_obj);
1688                         continue;
1689                 }
1690                 verbosestream<<"ServerEnvironment::activateObjects(): "
1691                                 <<"activated static object pos="<<PP(s_obj.pos/BS)
1692                                 <<" type="<<(int)s_obj.type<<std::endl;
1693                 // This will also add the object to the active static list
1694                 addActiveObjectRaw(obj, false, dtime_s);
1695         }
1696         // Clear stored list
1697         block->m_static_objects.m_stored.clear();
1698         // Add leftover failed stuff to stored list
1699         for(core::list<StaticObject>::Iterator
1700                         i = new_stored.begin();
1701                         i != new_stored.end(); i++)
1702         {
1703                 StaticObject &s_obj = *i;
1704                 block->m_static_objects.m_stored.push_back(s_obj);
1705         }
1706         /*
1707                 Note: Block hasn't really been modified here.
1708                 The objects have just been activated and moved from the stored
1709                 static list to the active static list.
1710                 As such, the block is essentially the same.
1711                 Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
1712                 Otherwise there would be a huge amount of unnecessary I/O.
1713         */
1714 }
1715
1716 /*
1717         Convert objects that are not standing inside active blocks to static.
1718
1719         If m_known_by_count != 0, active object is not deleted, but static
1720         data is still updated.
1721
1722         If force_delete is set, active object is deleted nevertheless. It
1723         shall only be set so in the destructor of the environment.
1724
1725         If block wasn't generated (not in memory or on disk), 
1726 */
1727 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1728 {
1729         core::list<u16> objects_to_remove;
1730         for(core::map<u16, ServerActiveObject*>::Iterator
1731                         i = m_active_objects.getIterator();
1732                         i.atEnd()==false; i++)
1733         {
1734                 ServerActiveObject* obj = i.getNode()->getValue();
1735                 assert(obj);
1736                 
1737                 // Do not deactivate if static data creation not allowed
1738                 if(!force_delete && !obj->isStaticAllowed())
1739                         continue;
1740
1741                 // If pending deactivation, let removeRemovedObjects() do it
1742                 if(!force_delete && obj->m_pending_deactivation)
1743                         continue;
1744
1745                 u16 id = i.getNode()->getKey();         
1746                 v3f objectpos = obj->getBasePosition(); 
1747
1748                 // The block in which the object resides in
1749                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1750
1751                 // If block is active, don't remove
1752                 if(!force_delete && m_active_blocks.contains(blockpos_o))
1753                         continue;
1754
1755                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1756                                 <<"deactivating object id="<<id<<" on inactive block "
1757                                 <<PP(blockpos_o)<<std::endl;
1758
1759                 // If known by some client, don't immediately delete.
1760                 bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
1761
1762                 /*
1763                         Update the static data
1764                 */
1765
1766                 if(obj->isStaticAllowed())
1767                 {
1768                         // Create new static object
1769                         std::string staticdata_new = obj->getStaticData();
1770                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1771                         
1772                         bool stays_in_same_block = false;
1773                         bool data_changed = true;
1774
1775                         if(obj->m_static_exists){
1776                                 if(obj->m_static_block == blockpos_o)
1777                                         stays_in_same_block = true;
1778
1779                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1780                                 
1781                                 core::map<u16, StaticObject>::Node *n =
1782                                                 block->m_static_objects.m_active.find(id);
1783                                 if(n){
1784                                         StaticObject static_old = n->getValue();
1785
1786                                         float save_movem = obj->getMinimumSavedMovement();
1787
1788                                         if(static_old.data == staticdata_new &&
1789                                                         (static_old.pos - objectpos).getLength() < save_movem)
1790                                                 data_changed = false;
1791                                 } else {
1792                                         errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1793                                                         <<"id="<<id<<" m_static_exists=true but "
1794                                                         <<"static data doesn't actually exist in "
1795                                                         <<PP(obj->m_static_block)<<std::endl;
1796                                 }
1797                         }
1798
1799                         bool shall_be_written = (!stays_in_same_block || data_changed);
1800                         
1801                         // Delete old static object
1802                         if(obj->m_static_exists)
1803                         {
1804                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1805                                 if(block)
1806                                 {
1807                                         block->m_static_objects.remove(id);
1808                                         obj->m_static_exists = false;
1809                                         // Only mark block as modified if data changed considerably
1810                                         if(shall_be_written)
1811                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1812                                                                 "deactivateFarObjects: Static data "
1813                                                                 "changed considerably");
1814                                 }
1815                         }
1816
1817                         // Add to the block where the object is located in
1818                         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1819                         // Get or generate the block
1820                         MapBlock *block = NULL;
1821                         try{
1822                                 block = m_map->emergeBlock(blockpos);
1823                         } catch(InvalidPositionException &e){
1824                                 // Handled via NULL pointer
1825                         }
1826
1827                         if(block)
1828                         {
1829                                 if(block->m_static_objects.m_stored.size() >= 49){
1830                                         errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
1831                                                         <<" statically but block "<<PP(blockpos)
1832                                                         <<" already contains "
1833                                                         <<block->m_static_objects.m_stored.size()
1834                                                         <<" (over 49) objects."
1835                                                         <<" Forcing delete."<<std::endl;
1836                                         force_delete = true;
1837                                 } else {
1838                                         u16 new_id = pending_delete ? id : 0;
1839                                         // If static counterpart already exists, remove it first.
1840                                         // This shouldn't happen, but happens rarely for some
1841                                         // unknown reason. Unsuccessful attempts have been made to
1842                                         // find said reason.
1843                                         if(new_id && block->m_static_objects.m_active.find(new_id)){
1844                                                 infostream<<"ServerEnv: WARNING: Performing hack #83274"
1845                                                                 <<std::endl;
1846                                                 block->m_static_objects.remove(new_id);
1847                                         }
1848                                         block->m_static_objects.insert(new_id, s_obj);
1849                                         
1850                                         // Only mark block as modified if data changed considerably
1851                                         if(shall_be_written)
1852                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1853                                                                 "deactivateFarObjects: Static data "
1854                                                                 "changed considerably");
1855                                         
1856                                         obj->m_static_exists = true;
1857                                         obj->m_static_block = block->getPos();
1858                                 }
1859                         }
1860                         else{
1861                                 if(!force_delete){
1862                                         v3s16 p = floatToInt(objectpos, BS);
1863                                         errorstream<<"ServerEnv: Could not find or generate "
1864                                                         <<"a block for storing id="<<obj->getId()
1865                                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1866                                         continue;
1867                                 }
1868                         }
1869                 }
1870
1871                 /*
1872                         If known by some client, set pending deactivation.
1873                         Otherwise delete it immediately.
1874                 */
1875
1876                 if(pending_delete && !force_delete)
1877                 {
1878                         verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1879                                         <<"object id="<<id<<" is known by clients"
1880                                         <<"; not deleting yet"<<std::endl;
1881
1882                         obj->m_pending_deactivation = true;
1883                         continue;
1884                 }
1885                 
1886                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1887                                 <<"object id="<<id<<" is not known by clients"
1888                                 <<"; deleting"<<std::endl;
1889
1890                 // Tell the object about removal
1891                 obj->removingFromEnvironment();
1892                 // Deregister in scripting api
1893                 scriptapi_rm_object_reference(m_lua, obj);
1894
1895                 // Delete active object
1896                 if(obj->environmentDeletes())
1897                         delete obj;
1898                 // Id to be removed from m_active_objects
1899                 objects_to_remove.push_back(id);
1900         }
1901
1902         // Remove references from m_active_objects
1903         for(core::list<u16>::Iterator i = objects_to_remove.begin();
1904                         i != objects_to_remove.end(); i++)
1905         {
1906                 m_active_objects.remove(*i);
1907         }
1908 }
1909
1910
1911 #ifndef SERVER
1912
1913 #include "clientsimpleobject.h"
1914
1915 /*
1916         ClientEnvironment
1917 */
1918
1919 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
1920                 ITextureSource *texturesource, IGameDef *gamedef,
1921                 IrrlichtDevice *irr):
1922         m_map(map),
1923         m_smgr(smgr),
1924         m_texturesource(texturesource),
1925         m_gamedef(gamedef),
1926         m_irr(irr)
1927 {
1928 }
1929
1930 ClientEnvironment::~ClientEnvironment()
1931 {
1932         // delete active objects
1933         for(core::map<u16, ClientActiveObject*>::Iterator
1934                         i = m_active_objects.getIterator();
1935                         i.atEnd()==false; i++)
1936         {
1937                 delete i.getNode()->getValue();
1938         }
1939
1940         for(core::list<ClientSimpleObject*>::Iterator
1941                         i = m_simple_objects.begin(); i != m_simple_objects.end(); i++)
1942         {
1943                 delete *i;
1944         }
1945
1946         // Drop/delete map
1947         m_map->drop();
1948 }
1949
1950 Map & ClientEnvironment::getMap()
1951 {
1952         return *m_map;
1953 }
1954
1955 ClientMap & ClientEnvironment::getClientMap()
1956 {
1957         return *m_map;
1958 }
1959
1960 void ClientEnvironment::addPlayer(Player *player)
1961 {
1962         DSTACK(__FUNCTION_NAME);
1963         /*
1964                 It is a failure if player is local and there already is a local
1965                 player
1966         */
1967         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
1968
1969         Environment::addPlayer(player);
1970 }
1971
1972 LocalPlayer * ClientEnvironment::getLocalPlayer()
1973 {
1974         for(core::list<Player*>::Iterator i = m_players.begin();
1975                         i != m_players.end(); i++)
1976         {
1977                 Player *player = *i;
1978                 if(player->isLocal())
1979                         return (LocalPlayer*)player;
1980         }
1981         return NULL;
1982 }
1983
1984 void ClientEnvironment::step(float dtime)
1985 {
1986         DSTACK(__FUNCTION_NAME);
1987
1988         /* Step time of day */
1989         stepTimeOfDay(dtime);
1990
1991         // Get some settings
1992         bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
1993         bool free_move = fly_allowed && g_settings->getBool("free_move");
1994
1995         // Get local player
1996         LocalPlayer *lplayer = getLocalPlayer();
1997         assert(lplayer);
1998         // collision info queue
1999         core::list<CollisionInfo> player_collisions;
2000         
2001         /*
2002                 Get the speed the player is going
2003         */
2004         bool is_climbing = lplayer->is_climbing;
2005         
2006         f32 player_speed = lplayer->getSpeed().getLength();
2007         
2008         /*
2009                 Maximum position increment
2010         */
2011         //f32 position_max_increment = 0.05*BS;
2012         f32 position_max_increment = 0.1*BS;
2013
2014         // Maximum time increment (for collision detection etc)
2015         // time = distance / speed
2016         f32 dtime_max_increment = 1;
2017         if(player_speed > 0.001)
2018                 dtime_max_increment = position_max_increment / player_speed;
2019         
2020         // Maximum time increment is 10ms or lower
2021         if(dtime_max_increment > 0.01)
2022                 dtime_max_increment = 0.01;
2023         
2024         // Don't allow overly huge dtime
2025         if(dtime > 0.5)
2026                 dtime = 0.5;
2027         
2028         f32 dtime_downcount = dtime;
2029
2030         /*
2031                 Stuff that has a maximum time increment
2032         */
2033
2034         u32 loopcount = 0;
2035         do
2036         {
2037                 loopcount++;
2038
2039                 f32 dtime_part;
2040                 if(dtime_downcount > dtime_max_increment)
2041                 {
2042                         dtime_part = dtime_max_increment;
2043                         dtime_downcount -= dtime_part;
2044                 }
2045                 else
2046                 {
2047                         dtime_part = dtime_downcount;
2048                         /*
2049                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
2050                                 when dtime_part is so small that dtime_downcount -= dtime_part
2051                                 does nothing
2052                         */
2053                         dtime_downcount = 0;
2054                 }
2055                 
2056                 /*
2057                         Handle local player
2058                 */
2059                 
2060                 {
2061                         v3f lplayerpos = lplayer->getPosition();
2062                         
2063                         // Apply physics
2064                         if(free_move == false && is_climbing == false)
2065                         {
2066                                 // Gravity
2067                                 v3f speed = lplayer->getSpeed();
2068                                 if(lplayer->swimming_up == false)
2069                                         speed.Y -= 9.81 * BS * dtime_part * 2;
2070
2071                                 // Water resistance
2072                                 if(lplayer->in_water_stable || lplayer->in_water)
2073                                 {
2074                                         f32 max_down = 2.0*BS;
2075                                         if(speed.Y < -max_down) speed.Y = -max_down;
2076
2077                                         f32 max = 2.5*BS;
2078                                         if(speed.getLength() > max)
2079                                         {
2080                                                 speed = speed / speed.getLength() * max;
2081                                         }
2082                                 }
2083
2084                                 lplayer->setSpeed(speed);
2085                         }
2086
2087                         /*
2088                                 Move the lplayer.
2089                                 This also does collision detection.
2090                         */
2091                         lplayer->move(dtime_part, *m_map, position_max_increment,
2092                                         &player_collisions);
2093                 }
2094         }
2095         while(dtime_downcount > 0.001);
2096                 
2097         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
2098         
2099         for(core::list<CollisionInfo>::Iterator
2100                         i = player_collisions.begin();
2101                         i != player_collisions.end(); i++)
2102         {
2103                 CollisionInfo &info = *i;
2104                 v3f speed_diff = info.new_speed - info.old_speed;;
2105                 // Handle only fall damage
2106                 // (because otherwise walking against something in fast_move kills you)
2107                 if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
2108                         continue;
2109                 // Get rid of other components
2110                 speed_diff.X = 0;
2111                 speed_diff.Z = 0;
2112                 f32 pre_factor = 1; // 1 hp per node/s
2113                 f32 tolerance = BS*14; // 5 without damage
2114                 f32 post_factor = 1; // 1 hp per node/s
2115                 if(info.type == COLLISION_NODE)
2116                 {
2117                         const ContentFeatures &f = m_gamedef->ndef()->
2118                                         get(m_map->getNodeNoEx(info.node_p));
2119                         // Determine fall damage multiplier
2120                         int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
2121                         pre_factor = 1.0 + (float)addp/100.0;
2122                 }
2123                 float speed = pre_factor * speed_diff.getLength();
2124                 if(speed > tolerance)
2125                 {
2126                         f32 damage_f = (speed - tolerance)/BS * post_factor;
2127                         u16 damage = (u16)(damage_f+0.5);
2128                         if(damage != 0)
2129                                 damageLocalPlayer(damage, true);
2130                 }
2131         }
2132         
2133         /*
2134                 A quick draft of lava damage
2135         */
2136         if(m_lava_hurt_interval.step(dtime, 1.0))
2137         {
2138                 v3f pf = lplayer->getPosition();
2139                 
2140                 // Feet, middle and head
2141                 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
2142                 MapNode n1 = m_map->getNodeNoEx(p1);
2143                 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
2144                 MapNode n2 = m_map->getNodeNoEx(p2);
2145                 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2146                 MapNode n3 = m_map->getNodeNoEx(p2);
2147
2148                 u32 damage_per_second = 0;
2149                 damage_per_second = MYMAX(damage_per_second,
2150                                 m_gamedef->ndef()->get(n1).damage_per_second);
2151                 damage_per_second = MYMAX(damage_per_second,
2152                                 m_gamedef->ndef()->get(n2).damage_per_second);
2153                 damage_per_second = MYMAX(damage_per_second,
2154                                 m_gamedef->ndef()->get(n3).damage_per_second);
2155                 
2156                 if(damage_per_second != 0)
2157                 {
2158                         damageLocalPlayer(damage_per_second, true);
2159                 }
2160         }
2161         
2162         /*
2163                 Stuff that can be done in an arbitarily large dtime
2164         */
2165         for(core::list<Player*>::Iterator i = m_players.begin();
2166                         i != m_players.end(); i++)
2167         {
2168                 Player *player = *i;
2169                 v3f playerpos = player->getPosition();
2170                 
2171                 /*
2172                         Handle non-local players
2173                 */
2174                 if(player->isLocal() == false)
2175                 {
2176                         // Move
2177                         player->move(dtime, *m_map, 100*BS);
2178
2179                 }
2180                 
2181                 // Update lighting on all players on client
2182                 float light = 1.0;
2183                 try{
2184                         // Get node at head
2185                         v3s16 p = player->getLightPosition();
2186                         MapNode n = m_map->getNode(p);
2187                         light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
2188                 }
2189                 catch(InvalidPositionException &e){
2190                         light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
2191                 }
2192                 player->light = light;
2193         }
2194         
2195         /*
2196                 Step active objects and update lighting of them
2197         */
2198         
2199         bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
2200         for(core::map<u16, ClientActiveObject*>::Iterator
2201                         i = m_active_objects.getIterator();
2202                         i.atEnd()==false; i++)
2203         {
2204                 ClientActiveObject* obj = i.getNode()->getValue();
2205                 // Step object
2206                 obj->step(dtime, this);
2207
2208                 if(update_lighting)
2209                 {
2210                         // Update lighting
2211                         u8 light = 0;
2212                         try{
2213                                 // Get node at head
2214                                 v3s16 p = obj->getLightPosition();
2215                                 MapNode n = m_map->getNode(p);
2216                                 light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2217                         }
2218                         catch(InvalidPositionException &e){
2219                                 light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2220                         }
2221                         obj->updateLight(light);
2222                 }
2223         }
2224
2225         /*
2226                 Step and handle simple objects
2227         */
2228         for(core::list<ClientSimpleObject*>::Iterator
2229                         i = m_simple_objects.begin(); i != m_simple_objects.end();)
2230         {
2231                 ClientSimpleObject *simple = *i;
2232                 core::list<ClientSimpleObject*>::Iterator cur = i;
2233                 i++;
2234                 simple->step(dtime);
2235                 if(simple->m_to_be_removed){
2236                         delete simple;
2237                         m_simple_objects.erase(cur);
2238                 }
2239         }
2240 }
2241         
2242 void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
2243 {
2244         m_simple_objects.push_back(simple);
2245 }
2246
2247 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
2248 {
2249         core::map<u16, ClientActiveObject*>::Node *n;
2250         n = m_active_objects.find(id);
2251         if(n == NULL)
2252                 return NULL;
2253         return n->getValue();
2254 }
2255
2256 bool isFreeClientActiveObjectId(u16 id,
2257                 core::map<u16, ClientActiveObject*> &objects)
2258 {
2259         if(id == 0)
2260                 return false;
2261         
2262         for(core::map<u16, ClientActiveObject*>::Iterator
2263                         i = objects.getIterator();
2264                         i.atEnd()==false; i++)
2265         {
2266                 if(i.getNode()->getKey() == id)
2267                         return false;
2268         }
2269         return true;
2270 }
2271
2272 u16 getFreeClientActiveObjectId(
2273                 core::map<u16, ClientActiveObject*> &objects)
2274 {
2275         u16 new_id = 1;
2276         for(;;)
2277         {
2278                 if(isFreeClientActiveObjectId(new_id, objects))
2279                         return new_id;
2280                 
2281                 if(new_id == 65535)
2282                         return 0;
2283
2284                 new_id++;
2285         }
2286 }
2287
2288 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
2289 {
2290         assert(object);
2291         if(object->getId() == 0)
2292         {
2293                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
2294                 if(new_id == 0)
2295                 {
2296                         infostream<<"ClientEnvironment::addActiveObject(): "
2297                                         <<"no free ids available"<<std::endl;
2298                         delete object;
2299                         return 0;
2300                 }
2301                 object->setId(new_id);
2302         }
2303         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
2304         {
2305                 infostream<<"ClientEnvironment::addActiveObject(): "
2306                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
2307                 delete object;
2308                 return 0;
2309         }
2310         infostream<<"ClientEnvironment::addActiveObject(): "
2311                         <<"added (id="<<object->getId()<<")"<<std::endl;
2312         m_active_objects.insert(object->getId(), object);
2313         object->addToScene(m_smgr, m_texturesource, m_irr);
2314         { // Update lighting immediately
2315                 u8 light = 0;
2316                 try{
2317                         // Get node at head
2318                         v3s16 p = object->getLightPosition();
2319                         MapNode n = m_map->getNode(p);
2320                         light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2321                 }
2322                 catch(InvalidPositionException &e){
2323                         light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2324                 }
2325                 object->updateLight(light);
2326         }
2327         return object->getId();
2328 }
2329
2330 void ClientEnvironment::addActiveObject(u16 id, u8 type,
2331                 const std::string &init_data)
2332 {
2333         ClientActiveObject* obj =
2334                         ClientActiveObject::create(type, m_gamedef, this);
2335         if(obj == NULL)
2336         {
2337                 infostream<<"ClientEnvironment::addActiveObject(): "
2338                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
2339                                 <<std::endl;
2340                 return;
2341         }
2342         
2343         obj->setId(id);
2344
2345         try
2346         {
2347                 obj->initialize(init_data);
2348         }
2349         catch(SerializationError &e)
2350         {
2351                 errorstream<<"ClientEnvironment::addActiveObject():"
2352                                 <<" id="<<id<<" type="<<type
2353                                 <<": SerializationError in initialize(): "
2354                                 <<e.what()
2355                                 <<": init_data="<<serializeJsonString(init_data)
2356                                 <<std::endl;
2357         }
2358
2359         addActiveObject(obj);
2360 }
2361
2362 void ClientEnvironment::removeActiveObject(u16 id)
2363 {
2364         verbosestream<<"ClientEnvironment::removeActiveObject(): "
2365                         <<"id="<<id<<std::endl;
2366         ClientActiveObject* obj = getActiveObject(id);
2367         if(obj == NULL)
2368         {
2369                 infostream<<"ClientEnvironment::removeActiveObject(): "
2370                                 <<"id="<<id<<" not found"<<std::endl;
2371                 return;
2372         }
2373         obj->removeFromScene(true);
2374         delete obj;
2375         m_active_objects.remove(id);
2376 }
2377
2378 void ClientEnvironment::processActiveObjectMessage(u16 id,
2379                 const std::string &data)
2380 {
2381         ClientActiveObject* obj = getActiveObject(id);
2382         if(obj == NULL)
2383         {
2384                 infostream<<"ClientEnvironment::processActiveObjectMessage():"
2385                                 <<" got message for id="<<id<<", which doesn't exist."
2386                                 <<std::endl;
2387                 return;
2388         }
2389         try
2390         {
2391                 obj->processMessage(data);
2392         }
2393         catch(SerializationError &e)
2394         {
2395                 errorstream<<"ClientEnvironment::processActiveObjectMessage():"
2396                                 <<" id="<<id<<" type="<<obj->getType()
2397                                 <<" SerializationError in processMessage(),"
2398                                 <<" message="<<serializeJsonString(data)
2399                                 <<std::endl;
2400         }
2401 }
2402
2403 /*
2404         Callbacks for activeobjects
2405 */
2406
2407 void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
2408 {
2409         LocalPlayer *lplayer = getLocalPlayer();
2410         assert(lplayer);
2411         
2412         if(handle_hp){
2413                 if(lplayer->hp > damage)
2414                         lplayer->hp -= damage;
2415                 else
2416                         lplayer->hp = 0;
2417         }
2418
2419         ClientEnvEvent event;
2420         event.type = CEE_PLAYER_DAMAGE;
2421         event.player_damage.amount = damage;
2422         event.player_damage.send_to_server = handle_hp;
2423         m_client_event_queue.push_back(event);
2424 }
2425
2426 /*
2427         Client likes to call these
2428 */
2429         
2430 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
2431                 core::array<DistanceSortedActiveObject> &dest)
2432 {
2433         for(core::map<u16, ClientActiveObject*>::Iterator
2434                         i = m_active_objects.getIterator();
2435                         i.atEnd()==false; i++)
2436         {
2437                 ClientActiveObject* obj = i.getNode()->getValue();
2438
2439                 f32 d = (obj->getPosition() - origin).getLength();
2440
2441                 if(d > max_d)
2442                         continue;
2443
2444                 DistanceSortedActiveObject dso(obj, d);
2445
2446                 dest.push_back(dso);
2447         }
2448 }
2449
2450 ClientEnvEvent ClientEnvironment::getClientEvent()
2451 {
2452         if(m_client_event_queue.size() == 0)
2453         {
2454                 ClientEnvEvent event;
2455                 event.type = CEE_NONE;
2456                 return event;
2457         }
2458         return m_client_event_queue.pop_front();
2459 }
2460
2461 #endif // #ifndef SERVER
2462
2463