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