]> git.lizzy.rs Git - dragonfireclient.git/blob - src/environment.cpp
Fix spaces float islands code
[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 object's static data is stored in a deactivated block and object
1809                 // is actually located in an active block, re-save to the block in
1810                 // which the object is actually located in.
1811                 if(!force_delete &&
1812                                 obj->m_static_exists &&
1813                                 !m_active_blocks.contains(obj->m_static_block) &&
1814                                  m_active_blocks.contains(blockpos_o))
1815                 {
1816                         v3s16 old_static_block = obj->m_static_block;
1817
1818                         // Save to block where object is located
1819                         MapBlock *block = m_map->emergeBlock(blockpos_o, false);
1820                         if(!block){
1821                                 errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1822                                                 <<"Could not save object id="<<id
1823                                                 <<" to it's current block "<<PP(blockpos_o)
1824                                                 <<std::endl;
1825                                 continue;
1826                         }
1827                         std::string staticdata_new = obj->getStaticData();
1828                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1829                         block->m_static_objects.insert(id, s_obj);
1830                         obj->m_static_block = blockpos_o;
1831                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1832                                         "deactivateFarObjects: Static data moved in");
1833
1834                         // Delete from block where object was located
1835                         block = m_map->emergeBlock(old_static_block, false);
1836                         if(!block){
1837                                 errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1838                                                 <<"Could not delete object id="<<id
1839                                                 <<" from it's previous block "<<PP(old_static_block)
1840                                                 <<std::endl;
1841                                 continue;
1842                         }
1843                         block->m_static_objects.remove(id);
1844                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1845                                         "deactivateFarObjects: Static data moved out");
1846                         continue;
1847                 }
1848
1849                 // If block is active, don't remove
1850                 if(!force_delete && m_active_blocks.contains(blockpos_o))
1851                         continue;
1852
1853                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1854                                 <<"deactivating object id="<<id<<" on inactive block "
1855                                 <<PP(blockpos_o)<<std::endl;
1856
1857                 // If known by some client, don't immediately delete.
1858                 bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
1859
1860                 /*
1861                         Update the static data
1862                 */
1863
1864                 if(obj->isStaticAllowed())
1865                 {
1866                         // Create new static object
1867                         std::string staticdata_new = obj->getStaticData();
1868                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1869                         
1870                         bool stays_in_same_block = false;
1871                         bool data_changed = true;
1872
1873                         if(obj->m_static_exists){
1874                                 if(obj->m_static_block == blockpos_o)
1875                                         stays_in_same_block = true;
1876
1877                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1878                                 
1879                                 std::map<u16, StaticObject>::iterator n =
1880                                                 block->m_static_objects.m_active.find(id);
1881                                 if(n != block->m_static_objects.m_active.end()){
1882                                         StaticObject static_old = n->second;
1883
1884                                         float save_movem = obj->getMinimumSavedMovement();
1885
1886                                         if(static_old.data == staticdata_new &&
1887                                                         (static_old.pos - objectpos).getLength() < save_movem)
1888                                                 data_changed = false;
1889                                 } else {
1890                                         errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1891                                                         <<"id="<<id<<" m_static_exists=true but "
1892                                                         <<"static data doesn't actually exist in "
1893                                                         <<PP(obj->m_static_block)<<std::endl;
1894                                 }
1895                         }
1896
1897                         bool shall_be_written = (!stays_in_same_block || data_changed);
1898                         
1899                         // Delete old static object
1900                         if(obj->m_static_exists)
1901                         {
1902                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1903                                 if(block)
1904                                 {
1905                                         block->m_static_objects.remove(id);
1906                                         obj->m_static_exists = false;
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                         }
1914
1915                         // Add to the block where the object is located in
1916                         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1917                         // Get or generate the block
1918                         MapBlock *block = NULL;
1919                         try{
1920                                 block = m_map->emergeBlock(blockpos);
1921                         } catch(InvalidPositionException &e){
1922                                 // Handled via NULL pointer
1923                         }
1924
1925                         if(block)
1926                         {
1927                                 if(block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")){
1928                                         errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
1929                                                         <<" statically but block "<<PP(blockpos)
1930                                                         <<" already contains "
1931                                                         <<block->m_static_objects.m_stored.size()
1932                                                         <<" objects."
1933                                                         <<" Forcing delete."<<std::endl;
1934                                         force_delete = true;
1935                                 } else {
1936                                         // If static counterpart already exists, remove it first.
1937                                         // This shouldn't happen, but happens rarely for some
1938                                         // unknown reason. Unsuccessful attempts have been made to
1939                                         // find said reason.
1940                                         if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
1941                                                 infostream<<"ServerEnv: WARNING: Performing hack #83274"
1942                                                                 <<std::endl;
1943                                                 block->m_static_objects.remove(id);
1944                                         }
1945                                         //store static data
1946                                         block->m_static_objects.insert(0, s_obj);
1947                                         
1948                                         // Only mark block as modified if data changed considerably
1949                                         if(shall_be_written)
1950                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1951                                                                 "deactivateFarObjects: Static data "
1952                                                                 "changed considerably");
1953                                         
1954                                         obj->m_static_exists = true;
1955                                         obj->m_static_block = block->getPos();
1956                                 }
1957                         }
1958                         else{
1959                                 if(!force_delete){
1960                                         v3s16 p = floatToInt(objectpos, BS);
1961                                         errorstream<<"ServerEnv: Could not find or generate "
1962                                                         <<"a block for storing id="<<obj->getId()
1963                                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1964                                         continue;
1965                                 }
1966                         }
1967                 }
1968
1969                 /*
1970                         If known by some client, set pending deactivation.
1971                         Otherwise delete it immediately.
1972                 */
1973
1974                 if(pending_delete && !force_delete)
1975                 {
1976                         verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1977                                         <<"object id="<<id<<" is known by clients"
1978                                         <<"; not deleting yet"<<std::endl;
1979
1980                         obj->m_pending_deactivation = true;
1981                         continue;
1982                 }
1983                 
1984                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1985                                 <<"object id="<<id<<" is not known by clients"
1986                                 <<"; deleting"<<std::endl;
1987
1988                 // Tell the object about removal
1989                 obj->removingFromEnvironment();
1990                 // Deregister in scripting api
1991                 m_script->removeObjectReference(obj);
1992
1993                 // Delete active object
1994                 if(obj->environmentDeletes())
1995                         delete obj;
1996                 // Id to be removed from m_active_objects
1997                 objects_to_remove.push_back(id);
1998         }
1999
2000         // Remove references from m_active_objects
2001         for(std::list<u16>::iterator i = objects_to_remove.begin();
2002                         i != objects_to_remove.end(); ++i)
2003         {
2004                 m_active_objects.erase(*i);
2005         }
2006 }
2007
2008
2009 #ifndef SERVER
2010
2011 #include "clientsimpleobject.h"
2012
2013 /*
2014         ClientEnvironment
2015 */
2016
2017 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
2018                 ITextureSource *texturesource, IGameDef *gamedef,
2019                 IrrlichtDevice *irr):
2020         m_map(map),
2021         m_smgr(smgr),
2022         m_texturesource(texturesource),
2023         m_gamedef(gamedef),
2024         m_irr(irr)
2025 {
2026 }
2027
2028 ClientEnvironment::~ClientEnvironment()
2029 {
2030         // delete active objects
2031         for(std::map<u16, ClientActiveObject*>::iterator
2032                         i = m_active_objects.begin();
2033                         i != m_active_objects.end(); ++i)
2034         {
2035                 delete i->second;
2036         }
2037
2038         for(std::list<ClientSimpleObject*>::iterator
2039                         i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i)
2040         {
2041                 delete *i;
2042         }
2043
2044         // Drop/delete map
2045         m_map->drop();
2046 }
2047
2048 Map & ClientEnvironment::getMap()
2049 {
2050         return *m_map;
2051 }
2052
2053 ClientMap & ClientEnvironment::getClientMap()
2054 {
2055         return *m_map;
2056 }
2057
2058 void ClientEnvironment::addPlayer(Player *player)
2059 {
2060         DSTACK(__FUNCTION_NAME);
2061         /*
2062                 It is a failure if player is local and there already is a local
2063                 player
2064         */
2065         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
2066
2067         Environment::addPlayer(player);
2068 }
2069
2070 LocalPlayer * ClientEnvironment::getLocalPlayer()
2071 {
2072         for(std::list<Player*>::iterator i = m_players.begin();
2073                         i != m_players.end(); ++i)
2074         {
2075                 Player *player = *i;
2076                 if(player->isLocal())
2077                         return (LocalPlayer*)player;
2078         }
2079         return NULL;
2080 }
2081
2082 void ClientEnvironment::step(float dtime)
2083 {
2084         DSTACK(__FUNCTION_NAME);
2085
2086         /* Step time of day */
2087         stepTimeOfDay(dtime);
2088
2089         // Get some settings
2090         bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
2091         bool free_move = fly_allowed && g_settings->getBool("free_move");
2092
2093         // Get local player
2094         LocalPlayer *lplayer = getLocalPlayer();
2095         assert(lplayer);
2096         // collision info queue
2097         std::list<CollisionInfo> player_collisions;
2098         
2099         /*
2100                 Get the speed the player is going
2101         */
2102         bool is_climbing = lplayer->is_climbing;
2103         
2104         f32 player_speed = lplayer->getSpeed().getLength();
2105         
2106         /*
2107                 Maximum position increment
2108         */
2109         //f32 position_max_increment = 0.05*BS;
2110         f32 position_max_increment = 0.1*BS;
2111
2112         // Maximum time increment (for collision detection etc)
2113         // time = distance / speed
2114         f32 dtime_max_increment = 1;
2115         if(player_speed > 0.001)
2116                 dtime_max_increment = position_max_increment / player_speed;
2117         
2118         // Maximum time increment is 10ms or lower
2119         if(dtime_max_increment > 0.01)
2120                 dtime_max_increment = 0.01;
2121         
2122         // Don't allow overly huge dtime
2123         if(dtime > 0.5)
2124                 dtime = 0.5;
2125         
2126         f32 dtime_downcount = dtime;
2127
2128         /*
2129                 Stuff that has a maximum time increment
2130         */
2131
2132         u32 loopcount = 0;
2133         do
2134         {
2135                 loopcount++;
2136
2137                 f32 dtime_part;
2138                 if(dtime_downcount > dtime_max_increment)
2139                 {
2140                         dtime_part = dtime_max_increment;
2141                         dtime_downcount -= dtime_part;
2142                 }
2143                 else
2144                 {
2145                         dtime_part = dtime_downcount;
2146                         /*
2147                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
2148                                 when dtime_part is so small that dtime_downcount -= dtime_part
2149                                 does nothing
2150                         */
2151                         dtime_downcount = 0;
2152                 }
2153                 
2154                 /*
2155                         Handle local player
2156                 */
2157                 
2158                 {
2159                         // Apply physics
2160                         if(free_move == false && is_climbing == false)
2161                         {
2162                                 // Gravity
2163                                 v3f speed = lplayer->getSpeed();
2164                                 if(lplayer->in_liquid == false)
2165                                         speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
2166
2167                                 // Liquid floating / sinking
2168                                 if(lplayer->in_liquid && !lplayer->swimming_vertical)
2169                                         speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
2170
2171                                 // Liquid resistance
2172                                 if(lplayer->in_liquid_stable || lplayer->in_liquid)
2173                                 {
2174                                         // How much the node's viscosity blocks movement, ranges between 0 and 1
2175                                         // Should match the scale at which viscosity increase affects other liquid attributes
2176                                         const f32 viscosity_factor = 0.3;
2177
2178                                         v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
2179                                         f32 dl = d_wanted.getLength();
2180                                         if(dl > lplayer->movement_liquid_fluidity_smooth)
2181                                                 dl = lplayer->movement_liquid_fluidity_smooth;
2182                                         dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
2183                                         
2184                                         v3f d = d_wanted.normalize() * dl;
2185                                         speed += d;
2186                                         
2187 #if 0 // old code
2188                                         if(speed.X > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.X -= lplayer->movement_liquid_fluidity_smooth;
2189                                         if(speed.X < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.X += lplayer->movement_liquid_fluidity_smooth;
2190                                         if(speed.Y > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Y -= lplayer->movement_liquid_fluidity_smooth;
2191                                         if(speed.Y < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Y += lplayer->movement_liquid_fluidity_smooth;
2192                                         if(speed.Z > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Z -= lplayer->movement_liquid_fluidity_smooth;
2193                                         if(speed.Z < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Z += lplayer->movement_liquid_fluidity_smooth;
2194 #endif
2195                                 }
2196
2197                                 lplayer->setSpeed(speed);
2198                         }
2199
2200                         /*
2201                                 Move the lplayer.
2202                                 This also does collision detection.
2203                         */
2204                         lplayer->move(dtime_part, this, position_max_increment,
2205                                         &player_collisions);
2206                 }
2207         }
2208         while(dtime_downcount > 0.001);
2209                 
2210         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
2211         
2212         for(std::list<CollisionInfo>::iterator
2213                         i = player_collisions.begin();
2214                         i != player_collisions.end(); ++i)
2215         {
2216                 CollisionInfo &info = *i;
2217                 v3f speed_diff = info.new_speed - info.old_speed;;
2218                 // Handle only fall damage
2219                 // (because otherwise walking against something in fast_move kills you)
2220                 if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
2221                         continue;
2222                 // Get rid of other components
2223                 speed_diff.X = 0;
2224                 speed_diff.Z = 0;
2225                 f32 pre_factor = 1; // 1 hp per node/s
2226                 f32 tolerance = BS*14; // 5 without damage
2227                 f32 post_factor = 1; // 1 hp per node/s
2228                 if(info.type == COLLISION_NODE)
2229                 {
2230                         const ContentFeatures &f = m_gamedef->ndef()->
2231                                         get(m_map->getNodeNoEx(info.node_p));
2232                         // Determine fall damage multiplier
2233                         int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
2234                         pre_factor = 1.0 + (float)addp/100.0;
2235                 }
2236                 float speed = pre_factor * speed_diff.getLength();
2237                 if(speed > tolerance)
2238                 {
2239                         f32 damage_f = (speed - tolerance)/BS * post_factor;
2240                         u16 damage = (u16)(damage_f+0.5);
2241                         if(damage != 0){
2242                                 damageLocalPlayer(damage, true);
2243                                 MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
2244                                 m_gamedef->event()->put(e);
2245                         }
2246                 }
2247         }
2248         
2249         /*
2250                 A quick draft of lava damage
2251         */
2252         if(m_lava_hurt_interval.step(dtime, 1.0))
2253         {
2254                 v3f pf = lplayer->getPosition();
2255                 
2256                 // Feet, middle and head
2257                 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
2258                 MapNode n1 = m_map->getNodeNoEx(p1);
2259                 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
2260                 MapNode n2 = m_map->getNodeNoEx(p2);
2261                 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2262                 MapNode n3 = m_map->getNodeNoEx(p3);
2263
2264                 u32 damage_per_second = 0;
2265                 damage_per_second = MYMAX(damage_per_second,
2266                                 m_gamedef->ndef()->get(n1).damage_per_second);
2267                 damage_per_second = MYMAX(damage_per_second,
2268                                 m_gamedef->ndef()->get(n2).damage_per_second);
2269                 damage_per_second = MYMAX(damage_per_second,
2270                                 m_gamedef->ndef()->get(n3).damage_per_second);
2271                 
2272                 if(damage_per_second != 0)
2273                 {
2274                         damageLocalPlayer(damage_per_second, true);
2275                 }
2276         }
2277
2278         /*
2279                 Drowning
2280         */
2281         if(m_drowning_interval.step(dtime, 2.0))
2282         {
2283                 v3f pf = lplayer->getPosition();
2284
2285                 // head
2286                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2287                 MapNode n = m_map->getNodeNoEx(p);
2288                 ContentFeatures c = m_gamedef->ndef()->get(n);
2289                 u8 drowning_damage = c.drowning;
2290                 if(drowning_damage > 0 && lplayer->hp > 0){
2291                         u16 breath = lplayer->getBreath();
2292                         if(breath > 10){
2293                                 breath = 11;
2294                         }
2295                         if(breath > 0){
2296                                 breath -= 1;
2297                         }
2298                         lplayer->setBreath(breath);
2299                         updateLocalPlayerBreath(breath);
2300                 }
2301
2302                 if(lplayer->getBreath() == 0 && drowning_damage > 0){
2303                         damageLocalPlayer(drowning_damage, true);
2304                 }
2305         }
2306         if(m_breathing_interval.step(dtime, 0.5))
2307         {
2308                 v3f pf = lplayer->getPosition();
2309
2310                 // head
2311                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2312                 MapNode n = m_map->getNodeNoEx(p);
2313                 ContentFeatures c = m_gamedef->ndef()->get(n);
2314                 if (!lplayer->hp){
2315                         lplayer->setBreath(11);
2316                 }
2317                 else if(c.drowning == 0){
2318                         u16 breath = lplayer->getBreath();
2319                         if(breath <= 10){
2320                                 breath += 1;
2321                                 lplayer->setBreath(breath);
2322                                 updateLocalPlayerBreath(breath);
2323                         }
2324                 }
2325         }
2326
2327         /*
2328                 Stuff that can be done in an arbitarily large dtime
2329         */
2330         for(std::list<Player*>::iterator i = m_players.begin();
2331                         i != m_players.end(); ++i)
2332         {
2333                 Player *player = *i;
2334                 
2335                 /*
2336                         Handle non-local players
2337                 */
2338                 if(player->isLocal() == false)
2339                 {
2340                         // Move
2341                         player->move(dtime, *m_map, 100*BS);
2342
2343                 }
2344                 
2345                 // Update lighting on all players on client
2346                 float light = 1.0;
2347                 try{
2348                         // Get node at head
2349                         v3s16 p = player->getLightPosition();
2350                         MapNode n = m_map->getNode(p);
2351                         light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
2352                 }
2353                 catch(InvalidPositionException &e){
2354                         light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
2355                 }
2356                 player->light = light;
2357         }
2358         
2359         /*
2360                 Step active objects and update lighting of them
2361         */
2362         
2363         g_profiler->avg("CEnv: num of objects", m_active_objects.size());
2364         bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
2365         for(std::map<u16, ClientActiveObject*>::iterator
2366                         i = m_active_objects.begin();
2367                         i != m_active_objects.end(); ++i)
2368         {
2369                 ClientActiveObject* obj = i->second;
2370                 // Step object
2371                 obj->step(dtime, this);
2372
2373                 if(update_lighting)
2374                 {
2375                         // Update lighting
2376                         u8 light = 0;
2377                         try{
2378                                 // Get node at head
2379                                 v3s16 p = obj->getLightPosition();
2380                                 MapNode n = m_map->getNode(p);
2381                                 light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2382                         }
2383                         catch(InvalidPositionException &e){
2384                                 light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2385                         }
2386                         obj->updateLight(light);
2387                 }
2388         }
2389
2390         /*
2391                 Step and handle simple objects
2392         */
2393         g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
2394         for(std::list<ClientSimpleObject*>::iterator
2395                         i = m_simple_objects.begin(); i != m_simple_objects.end();)
2396         {
2397                 ClientSimpleObject *simple = *i;
2398                 std::list<ClientSimpleObject*>::iterator cur = i;
2399                 ++i;
2400                 simple->step(dtime);
2401                 if(simple->m_to_be_removed){
2402                         delete simple;
2403                         m_simple_objects.erase(cur);
2404                 }
2405         }
2406 }
2407         
2408 void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
2409 {
2410         m_simple_objects.push_back(simple);
2411 }
2412
2413 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
2414 {
2415         std::map<u16, ClientActiveObject*>::iterator n;
2416         n = m_active_objects.find(id);
2417         if(n == m_active_objects.end())
2418                 return NULL;
2419         return n->second;
2420 }
2421
2422 bool isFreeClientActiveObjectId(u16 id,
2423                 std::map<u16, ClientActiveObject*> &objects)
2424 {
2425         if(id == 0)
2426                 return false;
2427
2428         return objects.find(id) == objects.end();
2429 }
2430
2431 u16 getFreeClientActiveObjectId(
2432                 std::map<u16, ClientActiveObject*> &objects)
2433 {
2434         //try to reuse id's as late as possible
2435         static u16 last_used_id = 0;
2436         u16 startid = last_used_id;
2437         for(;;)
2438         {
2439                 last_used_id ++;
2440                 if(isFreeClientActiveObjectId(last_used_id, objects))
2441                         return last_used_id;
2442                 
2443                 if(last_used_id == startid)
2444                         return 0;
2445         }
2446 }
2447
2448 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
2449 {
2450         assert(object);
2451         if(object->getId() == 0)
2452         {
2453                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
2454                 if(new_id == 0)
2455                 {
2456                         infostream<<"ClientEnvironment::addActiveObject(): "
2457                                         <<"no free ids available"<<std::endl;
2458                         delete object;
2459                         return 0;
2460                 }
2461                 object->setId(new_id);
2462         }
2463         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
2464         {
2465                 infostream<<"ClientEnvironment::addActiveObject(): "
2466                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
2467                 delete object;
2468                 return 0;
2469         }
2470         infostream<<"ClientEnvironment::addActiveObject(): "
2471                         <<"added (id="<<object->getId()<<")"<<std::endl;
2472         m_active_objects[object->getId()] = object;
2473         object->addToScene(m_smgr, m_texturesource, m_irr);
2474         { // Update lighting immediately
2475                 u8 light = 0;
2476                 try{
2477                         // Get node at head
2478                         v3s16 p = object->getLightPosition();
2479                         MapNode n = m_map->getNode(p);
2480                         light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2481                 }
2482                 catch(InvalidPositionException &e){
2483                         light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2484                 }
2485                 object->updateLight(light);
2486         }
2487         return object->getId();
2488 }
2489
2490 void ClientEnvironment::addActiveObject(u16 id, u8 type,
2491                 const std::string &init_data)
2492 {
2493         ClientActiveObject* obj =
2494                         ClientActiveObject::create(type, m_gamedef, this);
2495         if(obj == NULL)
2496         {
2497                 infostream<<"ClientEnvironment::addActiveObject(): "
2498                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
2499                                 <<std::endl;
2500                 return;
2501         }
2502         
2503         obj->setId(id);
2504
2505         try
2506         {
2507                 obj->initialize(init_data);
2508         }
2509         catch(SerializationError &e)
2510         {
2511                 errorstream<<"ClientEnvironment::addActiveObject():"
2512                                 <<" id="<<id<<" type="<<type
2513                                 <<": SerializationError in initialize(): "
2514                                 <<e.what()
2515                                 <<": init_data="<<serializeJsonString(init_data)
2516                                 <<std::endl;
2517         }
2518
2519         addActiveObject(obj);
2520 }
2521
2522 void ClientEnvironment::removeActiveObject(u16 id)
2523 {
2524         verbosestream<<"ClientEnvironment::removeActiveObject(): "
2525                         <<"id="<<id<<std::endl;
2526         ClientActiveObject* obj = getActiveObject(id);
2527         if(obj == NULL)
2528         {
2529                 infostream<<"ClientEnvironment::removeActiveObject(): "
2530                                 <<"id="<<id<<" not found"<<std::endl;
2531                 return;
2532         }
2533         obj->removeFromScene(true);
2534         delete obj;
2535         m_active_objects.erase(id);
2536 }
2537
2538 void ClientEnvironment::processActiveObjectMessage(u16 id,
2539                 const std::string &data)
2540 {
2541         ClientActiveObject* obj = getActiveObject(id);
2542         if(obj == NULL)
2543         {
2544                 infostream<<"ClientEnvironment::processActiveObjectMessage():"
2545                                 <<" got message for id="<<id<<", which doesn't exist."
2546                                 <<std::endl;
2547                 return;
2548         }
2549         try
2550         {
2551                 obj->processMessage(data);
2552         }
2553         catch(SerializationError &e)
2554         {
2555                 errorstream<<"ClientEnvironment::processActiveObjectMessage():"
2556                                 <<" id="<<id<<" type="<<obj->getType()
2557                                 <<" SerializationError in processMessage(),"
2558                                 <<" message="<<serializeJsonString(data)
2559                                 <<std::endl;
2560         }
2561 }
2562
2563 /*
2564         Callbacks for activeobjects
2565 */
2566
2567 void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
2568 {
2569         LocalPlayer *lplayer = getLocalPlayer();
2570         assert(lplayer);
2571         
2572         if(handle_hp){
2573                 if(lplayer->hp > damage)
2574                         lplayer->hp -= damage;
2575                 else
2576                         lplayer->hp = 0;
2577         }
2578
2579         ClientEnvEvent event;
2580         event.type = CEE_PLAYER_DAMAGE;
2581         event.player_damage.amount = damage;
2582         event.player_damage.send_to_server = handle_hp;
2583         m_client_event_queue.push_back(event);
2584 }
2585
2586 void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
2587 {
2588         ClientEnvEvent event;
2589         event.type = CEE_PLAYER_BREATH;
2590         event.player_breath.amount = breath;
2591         m_client_event_queue.push_back(event);
2592 }
2593
2594 /*
2595         Client likes to call these
2596 */
2597         
2598 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
2599                 std::vector<DistanceSortedActiveObject> &dest)
2600 {
2601         for(std::map<u16, ClientActiveObject*>::iterator
2602                         i = m_active_objects.begin();
2603                         i != m_active_objects.end(); ++i)
2604         {
2605                 ClientActiveObject* obj = i->second;
2606
2607                 f32 d = (obj->getPosition() - origin).getLength();
2608
2609                 if(d > max_d)
2610                         continue;
2611
2612                 DistanceSortedActiveObject dso(obj, d);
2613
2614                 dest.push_back(dso);
2615         }
2616 }
2617
2618 ClientEnvEvent ClientEnvironment::getClientEvent()
2619 {
2620         ClientEnvEvent event;
2621         if(m_client_event_queue.empty())
2622                 event.type = CEE_NONE;
2623         else {
2624                 event = m_client_event_queue.front();
2625                 m_client_event_queue.pop_front();
2626         }
2627         return event;
2628 }
2629
2630 #endif // #ifndef SERVER
2631
2632