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