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