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