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