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