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