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