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