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