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