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