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