efb93b9a26d56b110cfe09e6b9d483a5a7bfd6df
[oweals/minetest.git] / src / serverenvironment.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2017 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 "serverenvironment.h"
21 #include "content_sao.h"
22 #include "settings.h"
23 #include "log.h"
24 #include "mapblock.h"
25 #include "nodedef.h"
26 #include "nodemetadata.h"
27 #include "gamedef.h"
28 #include "map.h"
29 #include "porting.h"
30 #include "profiler.h"
31 #include "raycast.h"
32 #include "remoteplayer.h"
33 #include "scripting_server.h"
34 #include "server.h"
35 #include "util/serialize.h"
36 #include "util/basic_macros.h"
37 #include "util/pointedthing.h"
38 #include "threading/mutex_auto_lock.h"
39 #include "filesys.h"
40 #include "gameparams.h"
41 #include "database/database-dummy.h"
42 #include "database/database-files.h"
43 #include "database/database-sqlite3.h"
44 #if USE_POSTGRESQL
45 #include "database/database-postgresql.h"
46 #endif
47 #include <algorithm>
48
49 #define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:"
50
51 // A number that is much smaller than the timeout for particle spawners should/could ever be
52 #define PARTICLE_SPAWNER_NO_EXPIRY -1024.f
53
54 /*
55         ABMWithState
56 */
57
58 ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
59         abm(abm_)
60 {
61         // Initialize timer to random value to spread processing
62         float itv = abm->getTriggerInterval();
63         itv = MYMAX(0.001, itv); // No less than 1ms
64         int minval = MYMAX(-0.51*itv, -60); // Clamp to
65         int maxval = MYMIN(0.51*itv, 60);   // +-60 seconds
66         timer = myrand_range(minval, maxval);
67 }
68
69 /*
70         LBMManager
71 */
72
73 void LBMContentMapping::deleteContents()
74 {
75         for (auto &it : lbm_list) {
76                 delete it;
77         }
78 }
79
80 void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef)
81 {
82         // Add the lbm_def to the LBMContentMapping.
83         // Unknown names get added to the global NameIdMapping.
84         const NodeDefManager *nodedef = gamedef->ndef();
85
86         lbm_list.push_back(lbm_def);
87
88         for (const std::string &nodeTrigger: lbm_def->trigger_contents) {
89                 std::vector<content_t> c_ids;
90                 bool found = nodedef->getIds(nodeTrigger, c_ids);
91                 if (!found) {
92                         content_t c_id = gamedef->allocateUnknownNodeId(nodeTrigger);
93                         if (c_id == CONTENT_IGNORE) {
94                                 // Seems it can't be allocated.
95                                 warningstream << "Could not internalize node name \"" << nodeTrigger
96                                         << "\" while loading LBM \"" << lbm_def->name << "\"." << std::endl;
97                                 continue;
98                         }
99                         c_ids.push_back(c_id);
100                 }
101
102                 for (content_t c_id : c_ids) {
103                         map[c_id].push_back(lbm_def);
104                 }
105         }
106 }
107
108 const std::vector<LoadingBlockModifierDef *> *
109 LBMContentMapping::lookup(content_t c) const
110 {
111         lbm_map::const_iterator it = map.find(c);
112         if (it == map.end())
113                 return NULL;
114         // This first dereferences the iterator, returning
115         // a std::vector<LoadingBlockModifierDef *>
116         // reference, then we convert it to a pointer.
117         return &(it->second);
118 }
119
120 LBMManager::~LBMManager()
121 {
122         for (auto &m_lbm_def : m_lbm_defs) {
123                 delete m_lbm_def.second;
124         }
125
126         for (auto &it : m_lbm_lookup) {
127                 (it.second).deleteContents();
128         }
129 }
130
131 void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def)
132 {
133         // Precondition, in query mode the map isn't used anymore
134         FATAL_ERROR_IF(m_query_mode,
135                 "attempted to modify LBMManager in query mode");
136
137         if (!string_allowed(lbm_def->name, LBM_NAME_ALLOWED_CHARS)) {
138                 throw ModError("Error adding LBM \"" + lbm_def->name +
139                         "\": Does not follow naming conventions: "
140                                 "Only characters [a-z0-9_:] are allowed.");
141         }
142
143         m_lbm_defs[lbm_def->name] = lbm_def;
144 }
145
146 void LBMManager::loadIntroductionTimes(const std::string &times,
147         IGameDef *gamedef, u32 now)
148 {
149         m_query_mode = true;
150
151         // name -> time map.
152         // Storing it in a map first instead of
153         // handling the stuff directly in the loop
154         // removes all duplicate entries.
155         // TODO make this std::unordered_map
156         std::map<std::string, u32> introduction_times;
157
158         /*
159         The introduction times string consists of name~time entries,
160         with each entry terminated by a semicolon. The time is decimal.
161          */
162
163         size_t idx = 0;
164         size_t idx_new;
165         while ((idx_new = times.find(';', idx)) != std::string::npos) {
166                 std::string entry = times.substr(idx, idx_new - idx);
167                 std::vector<std::string> components = str_split(entry, '~');
168                 if (components.size() != 2)
169                         throw SerializationError("Introduction times entry \""
170                                 + entry + "\" requires exactly one '~'!");
171                 const std::string &name = components[0];
172                 u32 time = from_string<u32>(components[1]);
173                 introduction_times[name] = time;
174                 idx = idx_new + 1;
175         }
176
177         // Put stuff from introduction_times into m_lbm_lookup
178         for (std::map<std::string, u32>::const_iterator it = introduction_times.begin();
179                 it != introduction_times.end(); ++it) {
180                 const std::string &name = it->first;
181                 u32 time = it->second;
182
183                 std::map<std::string, LoadingBlockModifierDef *>::iterator def_it =
184                         m_lbm_defs.find(name);
185                 if (def_it == m_lbm_defs.end()) {
186                         // This seems to be an LBM entry for
187                         // an LBM we haven't loaded. Discard it.
188                         continue;
189                 }
190                 LoadingBlockModifierDef *lbm_def = def_it->second;
191                 if (lbm_def->run_at_every_load) {
192                         // This seems to be an LBM entry for
193                         // an LBM that runs at every load.
194                         // Don't add it just yet.
195                         continue;
196                 }
197
198                 m_lbm_lookup[time].addLBM(lbm_def, gamedef);
199
200                 // Erase the entry so that we know later
201                 // what elements didn't get put into m_lbm_lookup
202                 m_lbm_defs.erase(name);
203         }
204
205         // Now also add the elements from m_lbm_defs to m_lbm_lookup
206         // that weren't added in the previous step.
207         // They are introduced first time to this world,
208         // or are run at every load (introducement time hardcoded to U32_MAX).
209
210         LBMContentMapping &lbms_we_introduce_now = m_lbm_lookup[now];
211         LBMContentMapping &lbms_running_always = m_lbm_lookup[U32_MAX];
212
213         for (auto &m_lbm_def : m_lbm_defs) {
214                 if (m_lbm_def.second->run_at_every_load) {
215                         lbms_running_always.addLBM(m_lbm_def.second, gamedef);
216                 } else {
217                         lbms_we_introduce_now.addLBM(m_lbm_def.second, gamedef);
218                 }
219         }
220
221         // Clear the list, so that we don't delete remaining elements
222         // twice in the destructor
223         m_lbm_defs.clear();
224 }
225
226 std::string LBMManager::createIntroductionTimesString()
227 {
228         // Precondition, we must be in query mode
229         FATAL_ERROR_IF(!m_query_mode,
230                 "attempted to query on non fully set up LBMManager");
231
232         std::ostringstream oss;
233         for (const auto &it : m_lbm_lookup) {
234                 u32 time = it.first;
235                 const std::vector<LoadingBlockModifierDef *> &lbm_list = it.second.lbm_list;
236                 for (const auto &lbm_def : lbm_list) {
237                         // Don't add if the LBM runs at every load,
238                         // then introducement time is hardcoded
239                         // and doesn't need to be stored
240                         if (lbm_def->run_at_every_load)
241                                 continue;
242                         oss << lbm_def->name << "~" << time << ";";
243                 }
244         }
245         return oss.str();
246 }
247
248 void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
249 {
250         // Precondition, we need m_lbm_lookup to be initialized
251         FATAL_ERROR_IF(!m_query_mode,
252                 "attempted to query on non fully set up LBMManager");
253         v3s16 pos_of_block = block->getPosRelative();
254         v3s16 pos;
255         MapNode n;
256         content_t c;
257         lbm_lookup_map::const_iterator it = getLBMsIntroducedAfter(stamp);
258         for (; it != m_lbm_lookup.end(); ++it) {
259                 // Cache previous version to speedup lookup which has a very high performance
260                 // penalty on each call
261                 content_t previous_c{};
262                 std::vector<LoadingBlockModifierDef *> *lbm_list = nullptr;
263
264                 for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++)
265                         for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++)
266                                 for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) {
267                                         n = block->getNodeNoEx(pos);
268                                         c = n.getContent();
269
270                                         // If content_t are not matching perform an LBM lookup
271                                         if (previous_c != c) {
272                                                 lbm_list = (std::vector<LoadingBlockModifierDef *> *)
273                                                         it->second.lookup(c);
274                                                 previous_c = c;
275                                         }
276
277                                         if (!lbm_list)
278                                                 continue;
279                                         for (auto lbmdef : *lbm_list) {
280                                                 lbmdef->trigger(env, pos + pos_of_block, n);
281                                         }
282                                 }
283         }
284 }
285
286 /*
287         ActiveBlockList
288 */
289
290 void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
291 {
292         v3s16 p;
293         for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
294                 for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
295                         for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
296                         {
297                                 // limit to a sphere
298                                 if (p.getDistanceFrom(p0) <= r) {
299                                         // Set in list
300                                         list.insert(p);
301                                 }
302                         }
303 }
304
305 void fillViewConeBlock(v3s16 p0,
306         const s16 r,
307         const v3f camera_pos,
308         const v3f camera_dir,
309         const float camera_fov,
310         std::set<v3s16> &list)
311 {
312         v3s16 p;
313         const s16 r_nodes = r * BS * MAP_BLOCKSIZE;
314         for (p.X = p0.X - r; p.X <= p0.X+r; p.X++)
315         for (p.Y = p0.Y - r; p.Y <= p0.Y+r; p.Y++)
316         for (p.Z = p0.Z - r; p.Z <= p0.Z+r; p.Z++) {
317                 if (isBlockInSight(p, camera_pos, camera_dir, camera_fov, r_nodes)) {
318                         list.insert(p);
319                 }
320         }
321 }
322
323 void ActiveBlockList::update(std::vector<PlayerSAO*> &active_players,
324         s16 active_block_range,
325         s16 active_object_range,
326         std::set<v3s16> &blocks_removed,
327         std::set<v3s16> &blocks_added)
328 {
329         /*
330                 Create the new list
331         */
332         std::set<v3s16> newlist = m_forceloaded_list;
333         m_abm_list = m_forceloaded_list;
334         for (const PlayerSAO *playersao : active_players) {
335                 v3s16 pos = getNodeBlockPos(floatToInt(playersao->getBasePosition(), BS));
336                 fillRadiusBlock(pos, active_block_range, m_abm_list);
337                 fillRadiusBlock(pos, active_block_range, newlist);
338
339                 s16 player_ao_range = std::min(active_object_range, playersao->getWantedRange());
340                 // only do this if this would add blocks
341                 if (player_ao_range > active_block_range) {
342                         v3f camera_dir = v3f(0,0,1);
343                         camera_dir.rotateYZBy(playersao->getLookPitch());
344                         camera_dir.rotateXZBy(playersao->getRotation().Y);
345                         fillViewConeBlock(pos,
346                                 player_ao_range,
347                                 playersao->getEyePosition(),
348                                 camera_dir,
349                                 playersao->getFov(),
350                                 newlist);
351                 }
352         }
353
354         /*
355                 Find out which blocks on the old list are not on the new list
356         */
357         // Go through old list
358         for (v3s16 p : m_list) {
359                 // If not on new list, it's been removed
360                 if (newlist.find(p) == newlist.end())
361                         blocks_removed.insert(p);
362         }
363
364         /*
365                 Find out which blocks on the new list are not on the old list
366         */
367         // Go through new list
368         for (v3s16 p : newlist) {
369                 // If not on old list, it's been added
370                 if(m_list.find(p) == m_list.end())
371                         blocks_added.insert(p);
372         }
373
374         /*
375                 Update m_list
376         */
377         m_list.clear();
378         for (v3s16 p : newlist) {
379                 m_list.insert(p);
380         }
381 }
382
383 /*
384         ServerEnvironment
385 */
386
387 ServerEnvironment::ServerEnvironment(ServerMap *map,
388         ServerScripting *scriptIface, Server *server,
389         const std::string &path_world):
390         Environment(server),
391         m_map(map),
392         m_script(scriptIface),
393         m_server(server),
394         m_path_world(path_world)
395 {
396         // Determine which database backend to use
397         std::string conf_path = path_world + DIR_DELIM + "world.mt";
398         Settings conf;
399         bool succeeded = conf.readConfigFile(conf_path.c_str());
400         if (!succeeded || !conf.exists("player_backend")) {
401                 // fall back to files
402                 conf.set("player_backend", "files");
403                 warningstream << "/!\\ You are using old player file backend. "
404                                 << "This backend is deprecated and will be removed in next release /!\\"
405                                 << std::endl << "Switching to SQLite3 or PostgreSQL is advised, "
406                                 << "please read http://wiki.minetest.net/Database_backends." << std::endl;
407
408                 if (!conf.updateConfigFile(conf_path.c_str())) {
409                         errorstream << "ServerEnvironment::ServerEnvironment(): "
410                                 << "Failed to update world.mt!" << std::endl;
411                 }
412         }
413
414         std::string name;
415         conf.getNoEx("player_backend", name);
416         m_player_database = openPlayerDatabase(name, path_world, conf);
417
418         std::string auth_name = "files";
419         if (conf.exists("auth_backend")) {
420                 conf.getNoEx("auth_backend", auth_name);
421         } else {
422                 conf.set("auth_backend", "files");
423                 if (!conf.updateConfigFile(conf_path.c_str())) {
424                         errorstream << "ServerEnvironment::ServerEnvironment(): "
425                                         << "Failed to update world.mt!" << std::endl;
426                 }
427         }
428         m_auth_database = openAuthDatabase(auth_name, path_world, conf);
429 }
430
431 ServerEnvironment::~ServerEnvironment()
432 {
433         // Clear active block list.
434         // This makes the next one delete all active objects.
435         m_active_blocks.clear();
436
437         // Convert all objects to static and delete the active objects
438         deactivateFarObjects(true);
439
440         // Drop/delete map
441         m_map->drop();
442
443         // Delete ActiveBlockModifiers
444         for (ABMWithState &m_abm : m_abms) {
445                 delete m_abm.abm;
446         }
447
448         // Deallocate players
449         for (RemotePlayer *m_player : m_players) {
450                 delete m_player;
451         }
452
453         delete m_player_database;
454         delete m_auth_database;
455 }
456
457 Map & ServerEnvironment::getMap()
458 {
459         return *m_map;
460 }
461
462 ServerMap & ServerEnvironment::getServerMap()
463 {
464         return *m_map;
465 }
466
467 RemotePlayer *ServerEnvironment::getPlayer(const session_t peer_id)
468 {
469         for (RemotePlayer *player : m_players) {
470                 if (player->getPeerId() == peer_id)
471                         return player;
472         }
473         return NULL;
474 }
475
476 RemotePlayer *ServerEnvironment::getPlayer(const char* name)
477 {
478         for (RemotePlayer *player : m_players) {
479                 if (strcmp(player->getName(), name) == 0)
480                         return player;
481         }
482         return NULL;
483 }
484
485 void ServerEnvironment::addPlayer(RemotePlayer *player)
486 {
487         /*
488                 Check that peer_ids are unique.
489                 Also check that names are unique.
490                 Exception: there can be multiple players with peer_id=0
491         */
492         // If peer id is non-zero, it has to be unique.
493         if (player->getPeerId() != PEER_ID_INEXISTENT)
494                 FATAL_ERROR_IF(getPlayer(player->getPeerId()) != NULL, "Peer id not unique");
495         // Name has to be unique.
496         FATAL_ERROR_IF(getPlayer(player->getName()) != NULL, "Player name not unique");
497         // Add.
498         m_players.push_back(player);
499 }
500
501 void ServerEnvironment::removePlayer(RemotePlayer *player)
502 {
503         for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
504                 it != m_players.end(); ++it) {
505                 if ((*it) == player) {
506                         delete *it;
507                         m_players.erase(it);
508                         return;
509                 }
510         }
511 }
512
513 bool ServerEnvironment::removePlayerFromDatabase(const std::string &name)
514 {
515         return m_player_database->removePlayer(name);
516 }
517
518 bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, v3s16 *p)
519 {
520         // Iterate trough nodes on the line
521         voxalgo::VoxelLineIterator iterator(pos1 / BS, (pos2 - pos1) / BS);
522         do {
523                 MapNode n = getMap().getNodeNoEx(iterator.m_current_node_pos);
524
525                 // Return non-air
526                 if (n.param0 != CONTENT_AIR) {
527                         if (p)
528                                 *p = iterator.m_current_node_pos;
529                         return false;
530                 }
531                 iterator.next();
532         } while (iterator.m_current_index <= iterator.m_last_index);
533         return true;
534 }
535
536 void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason,
537         const std::string &str_reason, bool reconnect)
538 {
539         for (RemotePlayer *player : m_players) {
540                 m_server->DenyAccessVerCompliant(player->getPeerId(),
541                         player->protocol_version, reason, str_reason, reconnect);
542         }
543 }
544
545 void ServerEnvironment::saveLoadedPlayers()
546 {
547         std::string players_path = m_path_world + DIR_DELIM + "players";
548         fs::CreateDir(players_path);
549
550         for (RemotePlayer *player : m_players) {
551                 if (player->checkModified() || (player->getPlayerSAO() &&
552                                 player->getPlayerSAO()->getMeta().isModified())) {
553                         try {
554                                 m_player_database->savePlayer(player);
555                         } catch (DatabaseException &e) {
556                                 errorstream << "Failed to save player " << player->getName() << " exception: "
557                                         << e.what() << std::endl;
558                                 throw;
559                         }
560                 }
561         }
562 }
563
564 void ServerEnvironment::savePlayer(RemotePlayer *player)
565 {
566         try {
567                 m_player_database->savePlayer(player);
568         } catch (DatabaseException &e) {
569                 errorstream << "Failed to save player " << player->getName() << " exception: "
570                         << e.what() << std::endl;
571                 throw;
572         }
573 }
574
575 PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player,
576         session_t peer_id, bool is_singleplayer)
577 {
578         PlayerSAO *playersao = new PlayerSAO(this, player, peer_id, is_singleplayer);
579         // Create player if it doesn't exist
580         if (!m_player_database->loadPlayer(player, playersao)) {
581                 *new_player = true;
582                 // Set player position
583                 infostream << "Server: Finding spawn place for player \""
584                         << player->getName() << "\"" << std::endl;
585                 playersao->setBasePosition(m_server->findSpawnPos());
586
587                 // Make sure the player is saved
588                 player->setModified(true);
589         } else {
590                 // If the player exists, ensure that they respawn inside legal bounds
591                 // This fixes an assert crash when the player can't be added
592                 // to the environment
593                 if (objectpos_over_limit(playersao->getBasePosition())) {
594                         actionstream << "Respawn position for player \""
595                                 << player->getName() << "\" outside limits, resetting" << std::endl;
596                         playersao->setBasePosition(m_server->findSpawnPos());
597                 }
598         }
599
600         // Add player to environment
601         addPlayer(player);
602
603         /* Clean up old HUD elements from previous sessions */
604         player->clearHud();
605
606         /* Add object to environment */
607         addActiveObject(playersao);
608
609         return playersao;
610 }
611
612 void ServerEnvironment::saveMeta()
613 {
614         std::string path = m_path_world + DIR_DELIM "env_meta.txt";
615
616         // Open file and serialize
617         std::ostringstream ss(std::ios_base::binary);
618
619         Settings args;
620         args.setU64("game_time", m_game_time);
621         args.setU64("time_of_day", getTimeOfDay());
622         args.setU64("last_clear_objects_time", m_last_clear_objects_time);
623         args.setU64("lbm_introduction_times_version", 1);
624         args.set("lbm_introduction_times",
625                 m_lbm_mgr.createIntroductionTimesString());
626         args.setU64("day_count", m_day_count);
627         args.writeLines(ss);
628         ss<<"EnvArgsEnd\n";
629
630         if(!fs::safeWriteToFile(path, ss.str()))
631         {
632                 infostream<<"ServerEnvironment::saveMeta(): Failed to write "
633                         <<path<<std::endl;
634                 throw SerializationError("Couldn't save env meta");
635         }
636 }
637
638 void ServerEnvironment::loadMeta()
639 {
640         // If file doesn't exist, load default environment metadata
641         if (!fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
642                 infostream << "ServerEnvironment: Loading default environment metadata"
643                         << std::endl;
644                 loadDefaultMeta();
645                 return;
646         }
647
648         infostream << "ServerEnvironment: Loading environment metadata" << std::endl;
649
650         std::string path = m_path_world + DIR_DELIM "env_meta.txt";
651
652         // Open file and deserialize
653         std::ifstream is(path.c_str(), std::ios_base::binary);
654         if (!is.good()) {
655                 infostream << "ServerEnvironment::loadMeta(): Failed to open "
656                         << path << std::endl;
657                 throw SerializationError("Couldn't load env meta");
658         }
659
660         Settings args;
661
662         if (!args.parseConfigLines(is, "EnvArgsEnd")) {
663                 throw SerializationError("ServerEnvironment::loadMeta(): "
664                         "EnvArgsEnd not found!");
665         }
666
667         try {
668                 m_game_time = args.getU64("game_time");
669         } catch (SettingNotFoundException &e) {
670                 // Getting this is crucial, otherwise timestamps are useless
671                 throw SerializationError("Couldn't load env meta game_time");
672         }
673
674         setTimeOfDay(args.exists("time_of_day") ?
675                 // set day to early morning by default
676                 args.getU64("time_of_day") : 5250);
677
678         m_last_clear_objects_time = args.exists("last_clear_objects_time") ?
679                 // If missing, do as if clearObjects was never called
680                 args.getU64("last_clear_objects_time") : 0;
681
682         std::string lbm_introduction_times;
683         try {
684                 u64 ver = args.getU64("lbm_introduction_times_version");
685                 if (ver == 1) {
686                         lbm_introduction_times = args.get("lbm_introduction_times");
687                 } else {
688                         infostream << "ServerEnvironment::loadMeta(): Non-supported"
689                                 << " introduction time version " << ver << std::endl;
690                 }
691         } catch (SettingNotFoundException &e) {
692                 // No problem, this is expected. Just continue with an empty string
693         }
694         m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_server, m_game_time);
695
696         m_day_count = args.exists("day_count") ?
697                 args.getU64("day_count") : 0;
698 }
699
700 /**
701  * called if env_meta.txt doesn't exist (e.g. new world)
702  */
703 void ServerEnvironment::loadDefaultMeta()
704 {
705         m_lbm_mgr.loadIntroductionTimes("", m_server, m_game_time);
706 }
707
708 struct ActiveABM
709 {
710         ActiveBlockModifier *abm;
711         int chance;
712         std::vector<content_t> required_neighbors;
713         bool check_required_neighbors; // false if required_neighbors is known to be empty
714 };
715
716 class ABMHandler
717 {
718 private:
719         ServerEnvironment *m_env;
720         std::vector<std::vector<ActiveABM> *> m_aabms;
721 public:
722         ABMHandler(std::vector<ABMWithState> &abms,
723                 float dtime_s, ServerEnvironment *env,
724                 bool use_timers):
725                 m_env(env)
726         {
727                 if(dtime_s < 0.001)
728                         return;
729                 const NodeDefManager *ndef = env->getGameDef()->ndef();
730                 for (ABMWithState &abmws : abms) {
731                         ActiveBlockModifier *abm = abmws.abm;
732                         float trigger_interval = abm->getTriggerInterval();
733                         if(trigger_interval < 0.001)
734                                 trigger_interval = 0.001;
735                         float actual_interval = dtime_s;
736                         if(use_timers){
737                                 abmws.timer += dtime_s;
738                                 if(abmws.timer < trigger_interval)
739                                         continue;
740                                 abmws.timer -= trigger_interval;
741                                 actual_interval = trigger_interval;
742                         }
743                         float chance = abm->getTriggerChance();
744                         if(chance == 0)
745                                 chance = 1;
746                         ActiveABM aabm;
747                         aabm.abm = abm;
748                         if (abm->getSimpleCatchUp()) {
749                                 float intervals = actual_interval / trigger_interval;
750                                 if(intervals == 0)
751                                         continue;
752                                 aabm.chance = chance / intervals;
753                                 if(aabm.chance == 0)
754                                         aabm.chance = 1;
755                         } else {
756                                 aabm.chance = chance;
757                         }
758
759                         // Trigger neighbors
760                         const std::vector<std::string> &required_neighbors_s =
761                                 abm->getRequiredNeighbors();
762                         for (const std::string &required_neighbor_s : required_neighbors_s) {
763                                 ndef->getIds(required_neighbor_s, aabm.required_neighbors);
764                         }
765                         aabm.check_required_neighbors = !required_neighbors_s.empty();
766
767                         // Trigger contents
768                         const std::vector<std::string> &contents_s = abm->getTriggerContents();
769                         for (const std::string &content_s : contents_s) {
770                                 std::vector<content_t> ids;
771                                 ndef->getIds(content_s, ids);
772                                 for (content_t c : ids) {
773                                         if (c >= m_aabms.size())
774                                                 m_aabms.resize(c + 256, NULL);
775                                         if (!m_aabms[c])
776                                                 m_aabms[c] = new std::vector<ActiveABM>;
777                                         m_aabms[c]->push_back(aabm);
778                                 }
779                         }
780                 }
781         }
782
783         ~ABMHandler()
784         {
785                 for (auto &aabms : m_aabms)
786                         delete aabms;
787         }
788
789         // Find out how many objects the given block and its neighbours contain.
790         // Returns the number of objects in the block, and also in 'wider' the
791         // number of objects in the block and all its neighbours. The latter
792         // may an estimate if any neighbours are unloaded.
793         u32 countObjects(MapBlock *block, ServerMap * map, u32 &wider)
794         {
795                 wider = 0;
796                 u32 wider_unknown_count = 0;
797                 for(s16 x=-1; x<=1; x++)
798                         for(s16 y=-1; y<=1; y++)
799                                 for(s16 z=-1; z<=1; z++)
800                                 {
801                                         MapBlock *block2 = map->getBlockNoCreateNoEx(
802                                                 block->getPos() + v3s16(x,y,z));
803                                         if(block2==NULL){
804                                                 wider_unknown_count++;
805                                                 continue;
806                                         }
807                                         wider += block2->m_static_objects.m_active.size()
808                                                 + block2->m_static_objects.m_stored.size();
809                                 }
810                 // Extrapolate
811                 u32 active_object_count = block->m_static_objects.m_active.size();
812                 u32 wider_known_count = 3*3*3 - wider_unknown_count;
813                 wider += wider_unknown_count * wider / wider_known_count;
814                 return active_object_count;
815
816         }
817         void apply(MapBlock *block, int &blocks_scanned, int &abms_run, int &blocks_cached)
818         {
819                 if(m_aabms.empty() || block->isDummy())
820                         return;
821
822                 // Check the content type cache first
823                 // to see whether there are any ABMs
824                 // to be run at all for this block.
825                 if (block->contents_cached) {
826                         blocks_cached++;
827                         bool run_abms = false;
828                         for (content_t c : block->contents) {
829                                 if (c < m_aabms.size() && m_aabms[c]) {
830                                         run_abms = true;
831                                         break;
832                                 }
833                         }
834                         if (!run_abms)
835                                 return;
836                 } else {
837                         // Clear any caching
838                         block->contents.clear();
839                 }
840                 blocks_scanned++;
841
842                 ServerMap *map = &m_env->getServerMap();
843
844                 u32 active_object_count_wider;
845                 u32 active_object_count = this->countObjects(block, map, active_object_count_wider);
846                 m_env->m_added_objects = 0;
847
848                 v3s16 p0;
849                 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
850                 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
851                 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
852                 {
853                         const MapNode &n = block->getNodeUnsafe(p0);
854                         content_t c = n.getContent();
855                         // Cache content types as we go
856                         if (!block->contents_cached && !block->do_not_cache_contents) {
857                                 block->contents.insert(c);
858                                 if (block->contents.size() > 64) {
859                                         // Too many different nodes... don't try to cache
860                                         block->do_not_cache_contents = true;
861                                         block->contents.clear();
862                                 }
863                         }
864
865                         if (c >= m_aabms.size() || !m_aabms[c])
866                                 continue;
867
868                         v3s16 p = p0 + block->getPosRelative();
869                         for (ActiveABM &aabm : *m_aabms[c]) {
870                                 if (myrand() % aabm.chance != 0)
871                                         continue;
872
873                                 // Check neighbors
874                                 if (aabm.check_required_neighbors) {
875                                         v3s16 p1;
876                                         for(p1.X = p0.X-1; p1.X <= p0.X+1; p1.X++)
877                                         for(p1.Y = p0.Y-1; p1.Y <= p0.Y+1; p1.Y++)
878                                         for(p1.Z = p0.Z-1; p1.Z <= p0.Z+1; p1.Z++)
879                                         {
880                                                 if(p1 == p0)
881                                                         continue;
882                                                 content_t c;
883                                                 if (block->isValidPosition(p1)) {
884                                                         // if the neighbor is found on the same map block
885                                                         // get it straight from there
886                                                         const MapNode &n = block->getNodeUnsafe(p1);
887                                                         c = n.getContent();
888                                                 } else {
889                                                         // otherwise consult the map
890                                                         MapNode n = map->getNodeNoEx(p1 + block->getPosRelative());
891                                                         c = n.getContent();
892                                                 }
893                                                 if (CONTAINS(aabm.required_neighbors, c))
894                                                         goto neighbor_found;
895                                         }
896                                         // No required neighbor found
897                                         continue;
898                                 }
899                                 neighbor_found:
900
901                                 abms_run++;
902                                 // Call all the trigger variations
903                                 aabm.abm->trigger(m_env, p, n);
904                                 aabm.abm->trigger(m_env, p, n,
905                                         active_object_count, active_object_count_wider);
906
907                                 // Count surrounding objects again if the abms added any
908                                 if(m_env->m_added_objects > 0) {
909                                         active_object_count = countObjects(block, map, active_object_count_wider);
910                                         m_env->m_added_objects = 0;
911                                 }
912                         }
913                 }
914                 block->contents_cached = !block->do_not_cache_contents;
915         }
916 };
917
918 void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
919 {
920         // Reset usage timer immediately, otherwise a block that becomes active
921         // again at around the same time as it would normally be unloaded will
922         // get unloaded incorrectly. (I think this still leaves a small possibility
923         // of a race condition between this and server::AsyncRunStep, which only
924         // some kind of synchronisation will fix, but it at least reduces the window
925         // of opportunity for it to break from seconds to nanoseconds)
926         block->resetUsageTimer();
927
928         // Get time difference
929         u32 dtime_s = 0;
930         u32 stamp = block->getTimestamp();
931         if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
932                 dtime_s = m_game_time - stamp;
933         dtime_s += additional_dtime;
934
935         /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
936                         <<stamp<<", game time: "<<m_game_time<<std::endl;*/
937
938         // Remove stored static objects if clearObjects was called since block's timestamp
939         if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) {
940                 block->m_static_objects.m_stored.clear();
941                 // do not set changed flag to avoid unnecessary mapblock writes
942         }
943
944         // Set current time as timestamp
945         block->setTimestampNoChangedFlag(m_game_time);
946
947         /*infostream<<"ServerEnvironment::activateBlock(): block is "
948                         <<dtime_s<<" seconds old."<<std::endl;*/
949
950         // Activate stored objects
951         activateObjects(block, dtime_s);
952
953         /* Handle LoadingBlockModifiers */
954         m_lbm_mgr.applyLBMs(this, block, stamp);
955
956         // Run node timers
957         std::vector<NodeTimer> elapsed_timers =
958                 block->m_node_timers.step((float)dtime_s);
959         if (!elapsed_timers.empty()) {
960                 MapNode n;
961                 for (const NodeTimer &elapsed_timer : elapsed_timers) {
962                         n = block->getNodeNoEx(elapsed_timer.position);
963                         v3s16 p = elapsed_timer.position + block->getPosRelative();
964                         if (m_script->node_on_timer(p, n, elapsed_timer.elapsed))
965                                 block->setNodeTimer(NodeTimer(elapsed_timer.timeout, 0,
966                                         elapsed_timer.position));
967                 }
968         }
969 }
970
971 void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
972 {
973         m_abms.emplace_back(abm);
974 }
975
976 void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm)
977 {
978         m_lbm_mgr.addLBMDef(lbm);
979 }
980
981 bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
982 {
983         const NodeDefManager *ndef = m_server->ndef();
984         MapNode n_old = m_map->getNodeNoEx(p);
985
986         const ContentFeatures &cf_old = ndef->get(n_old);
987
988         // Call destructor
989         if (cf_old.has_on_destruct)
990                 m_script->node_on_destruct(p, n_old);
991
992         // Replace node
993         if (!m_map->addNodeWithEvent(p, n))
994                 return false;
995
996         // Update active VoxelManipulator if a mapgen thread
997         m_map->updateVManip(p);
998
999         // Call post-destructor
1000         if (cf_old.has_after_destruct)
1001                 m_script->node_after_destruct(p, n_old);
1002
1003         // Retrieve node content features
1004         // if new node is same as old, reuse old definition to prevent a lookup
1005         const ContentFeatures &cf_new = n_old == n ? cf_old : ndef->get(n);
1006
1007         // Call constructor
1008         if (cf_new.has_on_construct)
1009                 m_script->node_on_construct(p, n);
1010
1011         return true;
1012 }
1013
1014 bool ServerEnvironment::removeNode(v3s16 p)
1015 {
1016         const NodeDefManager *ndef = m_server->ndef();
1017         MapNode n_old = m_map->getNodeNoEx(p);
1018
1019         // Call destructor
1020         if (ndef->get(n_old).has_on_destruct)
1021                 m_script->node_on_destruct(p, n_old);
1022
1023         // Replace with air
1024         // This is slightly optimized compared to addNodeWithEvent(air)
1025         if (!m_map->removeNodeWithEvent(p))
1026                 return false;
1027
1028         // Update active VoxelManipulator if a mapgen thread
1029         m_map->updateVManip(p);
1030
1031         // Call post-destructor
1032         if (ndef->get(n_old).has_after_destruct)
1033                 m_script->node_after_destruct(p, n_old);
1034
1035         // Air doesn't require constructor
1036         return true;
1037 }
1038
1039 bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
1040 {
1041         if (!m_map->addNodeWithEvent(p, n, false))
1042                 return false;
1043
1044         // Update active VoxelManipulator if a mapgen thread
1045         m_map->updateVManip(p);
1046
1047         return true;
1048 }
1049
1050 void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f pos,
1051         float radius)
1052 {
1053         for (auto &activeObject : m_active_objects) {
1054                 ServerActiveObject* obj = activeObject.second;
1055                 u16 id = activeObject.first;
1056                 v3f objectpos = obj->getBasePosition();
1057                 if (objectpos.getDistanceFrom(pos) > radius)
1058                         continue;
1059                 objects.push_back(id);
1060         }
1061 }
1062
1063 void ServerEnvironment::clearObjects(ClearObjectsMode mode)
1064 {
1065         infostream << "ServerEnvironment::clearObjects(): "
1066                 << "Removing all active objects" << std::endl;
1067         std::vector<u16> objects_to_remove;
1068         for (auto &it : m_active_objects) {
1069                 u16 id = it.first;
1070                 ServerActiveObject* obj = it.second;
1071                 if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
1072                         continue;
1073
1074                 // Delete static object if block is loaded
1075                 deleteStaticFromBlock(obj, id, MOD_REASON_CLEAR_ALL_OBJECTS, true);
1076
1077                 // If known by some client, don't delete immediately
1078                 if (obj->m_known_by_count > 0) {
1079                         obj->m_pending_removal = true;
1080                         continue;
1081                 }
1082
1083                 // Tell the object about removal
1084                 obj->removingFromEnvironment();
1085                 // Deregister in scripting api
1086                 m_script->removeObjectReference(obj);
1087
1088                 // Delete active object
1089                 if (obj->environmentDeletes())
1090                         delete obj;
1091                 // Id to be removed from m_active_objects
1092                 objects_to_remove.push_back(id);
1093         }
1094
1095         // Remove references from m_active_objects
1096         for (u16 i : objects_to_remove) {
1097                 m_active_objects.erase(i);
1098         }
1099
1100         // Get list of loaded blocks
1101         std::vector<v3s16> loaded_blocks;
1102         infostream << "ServerEnvironment::clearObjects(): "
1103                 << "Listing all loaded blocks" << std::endl;
1104         m_map->listAllLoadedBlocks(loaded_blocks);
1105         infostream << "ServerEnvironment::clearObjects(): "
1106                 << "Done listing all loaded blocks: "
1107                 << loaded_blocks.size()<<std::endl;
1108
1109         // Get list of loadable blocks
1110         std::vector<v3s16> loadable_blocks;
1111         if (mode == CLEAR_OBJECTS_MODE_FULL) {
1112                 infostream << "ServerEnvironment::clearObjects(): "
1113                         << "Listing all loadable blocks" << std::endl;
1114                 m_map->listAllLoadableBlocks(loadable_blocks);
1115                 infostream << "ServerEnvironment::clearObjects(): "
1116                         << "Done listing all loadable blocks: "
1117                         << loadable_blocks.size() << std::endl;
1118         } else {
1119                 loadable_blocks = loaded_blocks;
1120         }
1121
1122         actionstream << "ServerEnvironment::clearObjects(): "
1123                 << "Now clearing objects in " << loadable_blocks.size()
1124                 << " blocks" << std::endl;
1125
1126         // Grab a reference on each loaded block to avoid unloading it
1127         for (v3s16 p : loaded_blocks) {
1128                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1129                 assert(block != NULL);
1130                 block->refGrab();
1131         }
1132
1133         // Remove objects in all loadable blocks
1134         u32 unload_interval = U32_MAX;
1135         if (mode == CLEAR_OBJECTS_MODE_FULL) {
1136                 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
1137                 unload_interval = MYMAX(unload_interval, 1);
1138         }
1139         u32 report_interval = loadable_blocks.size() / 10;
1140         u32 num_blocks_checked = 0;
1141         u32 num_blocks_cleared = 0;
1142         u32 num_objs_cleared = 0;
1143         for (auto i = loadable_blocks.begin();
1144                 i != loadable_blocks.end(); ++i) {
1145                 v3s16 p = *i;
1146                 MapBlock *block = m_map->emergeBlock(p, false);
1147                 if (!block) {
1148                         errorstream << "ServerEnvironment::clearObjects(): "
1149                                 << "Failed to emerge block " << PP(p) << std::endl;
1150                         continue;
1151                 }
1152                 u32 num_stored = block->m_static_objects.m_stored.size();
1153                 u32 num_active = block->m_static_objects.m_active.size();
1154                 if (num_stored != 0 || num_active != 0) {
1155                         block->m_static_objects.m_stored.clear();
1156                         block->m_static_objects.m_active.clear();
1157                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1158                                 MOD_REASON_CLEAR_ALL_OBJECTS);
1159                         num_objs_cleared += num_stored + num_active;
1160                         num_blocks_cleared++;
1161                 }
1162                 num_blocks_checked++;
1163
1164                 if (report_interval != 0 &&
1165                         num_blocks_checked % report_interval == 0) {
1166                         float percent = 100.0 * (float)num_blocks_checked /
1167                                 loadable_blocks.size();
1168                         actionstream << "ServerEnvironment::clearObjects(): "
1169                                 << "Cleared " << num_objs_cleared << " objects"
1170                                 << " in " << num_blocks_cleared << " blocks ("
1171                                 << percent << "%)" << std::endl;
1172                 }
1173                 if (num_blocks_checked % unload_interval == 0) {
1174                         m_map->unloadUnreferencedBlocks();
1175                 }
1176         }
1177         m_map->unloadUnreferencedBlocks();
1178
1179         // Drop references that were added above
1180         for (v3s16 p : loaded_blocks) {
1181                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1182                 assert(block);
1183                 block->refDrop();
1184         }
1185
1186         m_last_clear_objects_time = m_game_time;
1187
1188         actionstream << "ServerEnvironment::clearObjects(): "
1189                 << "Finished: Cleared " << num_objs_cleared << " objects"
1190                 << " in " << num_blocks_cleared << " blocks" << std::endl;
1191 }
1192
1193 void ServerEnvironment::step(float dtime)
1194 {
1195         /* Step time of day */
1196         stepTimeOfDay(dtime);
1197
1198         // Update this one
1199         // NOTE: This is kind of funny on a singleplayer game, but doesn't
1200         // really matter that much.
1201         static thread_local const float server_step =
1202                         g_settings->getFloat("dedicated_server_step");
1203         m_recommended_send_interval = server_step;
1204
1205         /*
1206                 Increment game time
1207         */
1208         {
1209                 m_game_time_fraction_counter += dtime;
1210                 u32 inc_i = (u32)m_game_time_fraction_counter;
1211                 m_game_time += inc_i;
1212                 m_game_time_fraction_counter -= (float)inc_i;
1213         }
1214
1215         /*
1216                 Handle players
1217         */
1218         {
1219                 ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
1220                 for (RemotePlayer *player : m_players) {
1221                         // Ignore disconnected players
1222                         if (player->getPeerId() == PEER_ID_INEXISTENT)
1223                                 continue;
1224
1225                         // Move
1226                         player->move(dtime, this, 100 * BS);
1227                 }
1228         }
1229
1230         /*
1231                 Manage active block list
1232         */
1233         if (m_active_blocks_management_interval.step(dtime, m_cache_active_block_mgmt_interval)) {
1234                 ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg per interval", SPT_AVG);
1235                 /*
1236                         Get player block positions
1237                 */
1238                 std::vector<PlayerSAO*> players;
1239                 for (RemotePlayer *player: m_players) {
1240                         // Ignore disconnected players
1241                         if (player->getPeerId() == PEER_ID_INEXISTENT)
1242                                 continue;
1243
1244                         PlayerSAO *playersao = player->getPlayerSAO();
1245                         assert(playersao);
1246
1247                         players.push_back(playersao);
1248                 }
1249
1250                 /*
1251                         Update list of active blocks, collecting changes
1252                 */
1253                 // use active_object_send_range_blocks since that is max distance
1254                 // for active objects sent the client anyway
1255                 static thread_local const s16 active_object_range =
1256                                 g_settings->getS16("active_object_send_range_blocks");
1257                 static thread_local const s16 active_block_range =
1258                                 g_settings->getS16("active_block_range");
1259                 std::set<v3s16> blocks_removed;
1260                 std::set<v3s16> blocks_added;
1261                 m_active_blocks.update(players, active_block_range, active_object_range,
1262                         blocks_removed, blocks_added);
1263
1264                 /*
1265                         Handle removed blocks
1266                 */
1267
1268                 // Convert active objects that are no more in active blocks to static
1269                 deactivateFarObjects(false);
1270
1271                 for (const v3s16 &p: blocks_removed) {
1272                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1273                         if (!block)
1274                                 continue;
1275
1276                         // Set current time as timestamp (and let it set ChangedFlag)
1277                         block->setTimestamp(m_game_time);
1278                 }
1279
1280                 /*
1281                         Handle added blocks
1282                 */
1283
1284                 for (const v3s16 &p: blocks_added) {
1285                         MapBlock *block = m_map->getBlockOrEmerge(p);
1286                         if (!block) {
1287                                 m_active_blocks.m_list.erase(p);
1288                                 m_active_blocks.m_abm_list.erase(p);
1289                                 continue;
1290                         }
1291
1292                         activateBlock(block);
1293                 }
1294         }
1295
1296         /*
1297                 Mess around in active blocks
1298         */
1299         if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval)) {
1300                 ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg per interval", SPT_AVG);
1301
1302                 float dtime = m_cache_nodetimer_interval;
1303
1304                 for (const v3s16 &p: m_active_blocks.m_list) {
1305                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1306                         if (!block)
1307                                 continue;
1308
1309                         // Reset block usage timer
1310                         block->resetUsageTimer();
1311
1312                         // Set current time as timestamp
1313                         block->setTimestampNoChangedFlag(m_game_time);
1314                         // If time has changed much from the one on disk,
1315                         // set block to be saved when it is unloaded
1316                         if(block->getTimestamp() > block->getDiskTimestamp() + 60)
1317                                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1318                                         MOD_REASON_BLOCK_EXPIRED);
1319
1320                         // Run node timers
1321                         std::vector<NodeTimer> elapsed_timers = block->m_node_timers.step(dtime);
1322                         if (!elapsed_timers.empty()) {
1323                                 MapNode n;
1324                                 v3s16 p2;
1325                                 for (const NodeTimer &elapsed_timer: elapsed_timers) {
1326                                         n = block->getNodeNoEx(elapsed_timer.position);
1327                                         p2 = elapsed_timer.position + block->getPosRelative();
1328                                         if (m_script->node_on_timer(p2, n, elapsed_timer.elapsed)) {
1329                                                 block->setNodeTimer(NodeTimer(
1330                                                         elapsed_timer.timeout, 0, elapsed_timer.position));
1331                                         }
1332                                 }
1333                         }
1334                 }
1335         }
1336
1337         if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval))
1338                 do { // breakable
1339                         if (m_active_block_interval_overload_skip > 0) {
1340                                 ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
1341                                 m_active_block_interval_overload_skip--;
1342                                 break;
1343                         }
1344                         ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG);
1345                         TimeTaker timer("modify in active blocks per interval");
1346
1347                         // Initialize handling of ActiveBlockModifiers
1348                         ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);
1349
1350                         int blocks_scanned = 0;
1351                         int abms_run = 0;
1352                         int blocks_cached = 0;
1353                         for (const v3s16 &p : m_active_blocks.m_abm_list) {
1354                                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1355                                 if (!block)
1356                                         continue;
1357
1358                                 // Set current time as timestamp
1359                                 block->setTimestampNoChangedFlag(m_game_time);
1360
1361                                 /* Handle ActiveBlockModifiers */
1362                                 abmhandler.apply(block, blocks_scanned, abms_run, blocks_cached);
1363                         }
1364                         g_profiler->avg("SEnv: active blocks", m_active_blocks.m_abm_list.size());
1365                         g_profiler->avg("SEnv: active blocks cached", blocks_cached);
1366                         g_profiler->avg("SEnv: active blocks scanned for ABMs", blocks_scanned);
1367                         g_profiler->avg("SEnv: ABMs run", abms_run);
1368
1369                         u32 time_ms = timer.stop(true);
1370                         u32 max_time_ms = 200;
1371                         if (time_ms > max_time_ms) {
1372                                 warningstream<<"active block modifiers took "
1373                                         <<time_ms<<"ms (longer than "
1374                                         <<max_time_ms<<"ms)"<<std::endl;
1375                                 m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
1376                         }
1377                 }while(0);
1378
1379         /*
1380                 Step script environment (run global on_step())
1381         */
1382         m_script->environment_Step(dtime);
1383
1384         /*
1385                 Step active objects
1386         */
1387         {
1388                 ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
1389                 //TimeTaker timer("Step active objects");
1390
1391                 g_profiler->avg("SEnv: num of objects", m_active_objects.size());
1392
1393                 // This helps the objects to send data at the same time
1394                 bool send_recommended = false;
1395                 m_send_recommended_timer += dtime;
1396                 if(m_send_recommended_timer > getSendRecommendedInterval())
1397                 {
1398                         m_send_recommended_timer -= getSendRecommendedInterval();
1399                         send_recommended = true;
1400                 }
1401
1402                 for (auto &ao_it : m_active_objects) {
1403                         ServerActiveObject* obj = ao_it.second;
1404                         if (obj->isGone())
1405                                 continue;
1406
1407                         // Step object
1408                         obj->step(dtime, send_recommended);
1409                         // Read messages from object
1410                         while (!obj->m_messages_out.empty()) {
1411                                 m_active_object_messages.push(obj->m_messages_out.front());
1412                                 obj->m_messages_out.pop();
1413                         }
1414                 }
1415         }
1416
1417         /*
1418                 Manage active objects
1419         */
1420         if (m_object_management_interval.step(dtime, 0.5)) {
1421                 ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
1422                 removeRemovedObjects();
1423         }
1424
1425         /*
1426                 Manage particle spawner expiration
1427         */
1428         if (m_particle_management_interval.step(dtime, 1.0)) {
1429                 for (std::unordered_map<u32, float>::iterator i = m_particle_spawners.begin();
1430                         i != m_particle_spawners.end(); ) {
1431                         //non expiring spawners
1432                         if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) {
1433                                 ++i;
1434                                 continue;
1435                         }
1436
1437                         i->second -= 1.0f;
1438                         if (i->second <= 0.f)
1439                                 m_particle_spawners.erase(i++);
1440                         else
1441                                 ++i;
1442                 }
1443         }
1444 }
1445
1446 u32 ServerEnvironment::addParticleSpawner(float exptime)
1447 {
1448         // Timers with lifetime 0 do not expire
1449         float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY;
1450
1451         u32 id = 0;
1452         for (;;) { // look for unused particlespawner id
1453                 id++;
1454                 std::unordered_map<u32, float>::iterator f = m_particle_spawners.find(id);
1455                 if (f == m_particle_spawners.end()) {
1456                         m_particle_spawners[id] = time;
1457                         break;
1458                 }
1459         }
1460         return id;
1461 }
1462
1463 u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)
1464 {
1465         u32 id = addParticleSpawner(exptime);
1466         m_particle_spawner_attachments[id] = attached_id;
1467         if (ServerActiveObject *obj = getActiveObject(attached_id)) {
1468                 obj->attachParticleSpawner(id);
1469         }
1470         return id;
1471 }
1472
1473 void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
1474 {
1475         m_particle_spawners.erase(id);
1476         const auto &it = m_particle_spawner_attachments.find(id);
1477         if (it != m_particle_spawner_attachments.end()) {
1478                 u16 obj_id = it->second;
1479                 ServerActiveObject *sao = getActiveObject(obj_id);
1480                 if (sao != NULL && remove_from_object) {
1481                         sao->detachParticleSpawner(id);
1482                 }
1483                 m_particle_spawner_attachments.erase(id);
1484         }
1485 }
1486
1487 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
1488 {
1489         ServerActiveObjectMap::const_iterator n = m_active_objects.find(id);
1490         return (n != m_active_objects.end() ? n->second : NULL);
1491 }
1492
1493 /**
1494  * Verify if id is a free active object id
1495  * @param id
1496  * @return true if slot is free
1497  */
1498 bool ServerEnvironment::isFreeServerActiveObjectId(u16 id) const
1499 {
1500         if (id == 0)
1501                 return false;
1502
1503         return m_active_objects.find(id) == m_active_objects.end();
1504 }
1505
1506 /**
1507  * Retrieve the first free ActiveObject ID
1508  * @return free activeobject ID or 0 if none was found
1509  */
1510 u16 ServerEnvironment::getFreeServerActiveObjectId()
1511 {
1512         // try to reuse id's as late as possible
1513         static u16 last_used_id = 0;
1514         u16 startid = last_used_id;
1515         for (;;) {
1516                 last_used_id++;
1517                 if (isFreeServerActiveObjectId(last_used_id))
1518                         return last_used_id;
1519
1520                 if (last_used_id == startid)
1521                         return 0;
1522         }
1523 }
1524
1525 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1526 {
1527         assert(object); // Pre-condition
1528         m_added_objects++;
1529         u16 id = addActiveObjectRaw(object, true, 0);
1530         return id;
1531 }
1532
1533 /*
1534         Finds out what new objects have been added to
1535         inside a radius around a position
1536 */
1537 void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
1538         s16 player_radius,
1539         std::set<u16> &current_objects,
1540         std::queue<u16> &added_objects)
1541 {
1542         f32 radius_f = radius * BS;
1543         f32 player_radius_f = player_radius * BS;
1544
1545         if (player_radius_f < 0)
1546                 player_radius_f = 0;
1547         /*
1548                 Go through the object list,
1549                 - discard removed/deactivated objects,
1550                 - discard objects that are too far away,
1551                 - discard objects that are found in current_objects.
1552                 - add remaining objects to added_objects
1553         */
1554         for (auto &ao_it : m_active_objects) {
1555                 u16 id = ao_it.first;
1556
1557                 // Get object
1558                 ServerActiveObject *object = ao_it.second;
1559                 if (object == NULL)
1560                         continue;
1561
1562                 if (object->isGone())
1563                         continue;
1564
1565                 f32 distance_f = object->getBasePosition().
1566                         getDistanceFrom(playersao->getBasePosition());
1567                 if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
1568                         // Discard if too far
1569                         if (distance_f > player_radius_f && player_radius_f != 0)
1570                                 continue;
1571                 } else if (distance_f > radius_f)
1572                         continue;
1573
1574                 // Discard if already on current_objects
1575                 std::set<u16>::iterator n;
1576                 n = current_objects.find(id);
1577                 if(n != current_objects.end())
1578                         continue;
1579                 // Add to added_objects
1580                 added_objects.push(id);
1581         }
1582 }
1583
1584 /*
1585         Finds out what objects have been removed from
1586         inside a radius around a position
1587 */
1588 void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius,
1589         s16 player_radius,
1590         std::set<u16> &current_objects,
1591         std::queue<u16> &removed_objects)
1592 {
1593         f32 radius_f = radius * BS;
1594         f32 player_radius_f = player_radius * BS;
1595
1596         if (player_radius_f < 0)
1597                 player_radius_f = 0;
1598         /*
1599                 Go through current_objects; object is removed if:
1600                 - object is not found in m_active_objects (this is actually an
1601                   error condition; objects should be removed only after all clients
1602                   have been informed about removal), or
1603                 - object is to be removed or deactivated, or
1604                 - object is too far away
1605         */
1606         for (u16 id : current_objects) {
1607                 ServerActiveObject *object = getActiveObject(id);
1608
1609                 if (object == NULL) {
1610                         infostream << "ServerEnvironment::getRemovedActiveObjects():"
1611                                 << " object in current_objects is NULL" << std::endl;
1612                         removed_objects.push(id);
1613                         continue;
1614                 }
1615
1616                 if (object->isGone()) {
1617                         removed_objects.push(id);
1618                         continue;
1619                 }
1620
1621                 f32 distance_f = object->getBasePosition().getDistanceFrom(playersao->getBasePosition());
1622                 if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
1623                         if (distance_f <= player_radius_f || player_radius_f == 0)
1624                                 continue;
1625                 } else if (distance_f <= radius_f)
1626                         continue;
1627
1628                 // Object is no longer visible
1629                 removed_objects.push(id);
1630         }
1631 }
1632
1633 void ServerEnvironment::setStaticForActiveObjectsInBlock(
1634         v3s16 blockpos, bool static_exists, v3s16 static_block)
1635 {
1636         MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1637         if (!block)
1638                 return;
1639
1640         for (auto &so_it : block->m_static_objects.m_active) {
1641                 // Get the ServerActiveObject counterpart to this StaticObject
1642                 ServerActiveObjectMap::const_iterator ao_it = m_active_objects.find(so_it.first);
1643                 if (ao_it == m_active_objects.end()) {
1644                         // If this ever happens, there must be some kind of nasty bug.
1645                         errorstream << "ServerEnvironment::setStaticForObjectsInBlock(): "
1646                                 "Object from MapBlock::m_static_objects::m_active not found "
1647                                 "in m_active_objects";
1648                         continue;
1649                 }
1650
1651                 ServerActiveObject *sao = ao_it->second;
1652                 sao->m_static_exists = static_exists;
1653                 sao->m_static_block  = static_block;
1654         }
1655 }
1656
1657 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1658 {
1659         if(m_active_object_messages.empty())
1660                 return ActiveObjectMessage(0);
1661
1662         ActiveObjectMessage message = m_active_object_messages.front();
1663         m_active_object_messages.pop();
1664         return message;
1665 }
1666
1667 void ServerEnvironment::getSelectedActiveObjects(
1668         const core::line3d<f32> &shootline_on_map,
1669         std::vector<PointedThing> &objects)
1670 {
1671         std::vector<u16> objectIds;
1672         getObjectsInsideRadius(objectIds, shootline_on_map.start,
1673                 shootline_on_map.getLength() + 10.0f);
1674         const v3f line_vector = shootline_on_map.getVector();
1675
1676         for (u16 objectId : objectIds) {
1677                 ServerActiveObject* obj = getActiveObject(objectId);
1678
1679                 aabb3f selection_box;
1680                 if (!obj->getSelectionBox(&selection_box))
1681                         continue;
1682
1683                 v3f pos = obj->getBasePosition();
1684
1685                 aabb3f offsetted_box(selection_box.MinEdge + pos,
1686                         selection_box.MaxEdge + pos);
1687
1688                 v3f current_intersection;
1689                 v3s16 current_normal;
1690                 if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
1691                                 &current_intersection, &current_normal)) {
1692                         objects.emplace_back(
1693                                 (s16) objectId, current_intersection, current_normal,
1694                                 (current_intersection - shootline_on_map.start).getLengthSQ());
1695                 }
1696         }
1697 }
1698
1699 /*
1700         ************ Private methods *************
1701 */
1702
1703 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1704         bool set_changed, u32 dtime_s)
1705 {
1706         assert(object); // Pre-condition
1707         if(object->getId() == 0){
1708                 u16 new_id = getFreeServerActiveObjectId();
1709                 if(new_id == 0)
1710                 {
1711                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1712                                 <<"no free ids available"<<std::endl;
1713                         if(object->environmentDeletes())
1714                                 delete object;
1715                         return 0;
1716                 }
1717                 object->setId(new_id);
1718         }
1719         else{
1720                 verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1721                         <<"supplied with id "<<object->getId()<<std::endl;
1722         }
1723
1724         if(!isFreeServerActiveObjectId(object->getId())) {
1725                 errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1726                         <<"id is not free ("<<object->getId()<<")"<<std::endl;
1727                 if(object->environmentDeletes())
1728                         delete object;
1729                 return 0;
1730         }
1731
1732         if (objectpos_over_limit(object->getBasePosition())) {
1733                 v3f p = object->getBasePosition();
1734                 warningstream << "ServerEnvironment::addActiveObjectRaw(): "
1735                         << "object position (" << p.X << "," << p.Y << "," << p.Z
1736                         << ") outside maximum range" << std::endl;
1737                 if (object->environmentDeletes())
1738                         delete object;
1739                 return 0;
1740         }
1741
1742         /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1743                         <<"added (id="<<object->getId()<<")"<<std::endl;*/
1744
1745         m_active_objects[object->getId()] = object;
1746
1747         verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1748                 <<"Added id="<<object->getId()<<"; there are now "
1749                 <<m_active_objects.size()<<" active objects."
1750                 <<std::endl;
1751
1752         // Register reference in scripting api (must be done before post-init)
1753         m_script->addObjectReference(object);
1754         // Post-initialize object
1755         object->addedToEnvironment(dtime_s);
1756
1757         // Add static data to block
1758         if(object->isStaticAllowed())
1759         {
1760                 // Add static object to active static list of the block
1761                 v3f objectpos = object->getBasePosition();
1762                 StaticObject s_obj(object, objectpos);
1763                 // Add to the block where the object is located in
1764                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1765                 MapBlock *block = m_map->emergeBlock(blockpos);
1766                 if(block){
1767                         block->m_static_objects.m_active[object->getId()] = s_obj;
1768                         object->m_static_exists = true;
1769                         object->m_static_block = blockpos;
1770
1771                         if(set_changed)
1772                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1773                                         MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
1774                 } else {
1775                         v3s16 p = floatToInt(objectpos, BS);
1776                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1777                                 <<"could not emerge block for storing id="<<object->getId()
1778                                 <<" statically (pos="<<PP(p)<<")"<<std::endl;
1779                 }
1780         }
1781
1782         return object->getId();
1783 }
1784
1785 /*
1786         Remove objects that satisfy (isGone() && m_known_by_count==0)
1787 */
1788 void ServerEnvironment::removeRemovedObjects()
1789 {
1790         std::vector<u16> objects_to_remove;
1791         for (auto &ao_it : m_active_objects) {
1792                 u16 id = ao_it.first;
1793                 ServerActiveObject* obj = ao_it.second;
1794
1795                 // This shouldn't happen but check it
1796                 if (!obj) {
1797                         errorstream << "ServerEnvironment::removeRemovedObjects(): "
1798                                         << "NULL object found. id=" << id << std::endl;
1799                         objects_to_remove.push_back(id);
1800                         continue;
1801                 }
1802
1803                 /*
1804                         We will handle objects marked for removal or deactivation
1805                 */
1806                 if (!obj->isGone())
1807                         continue;
1808
1809                 /*
1810                         Delete static data from block if removed
1811                 */
1812                 if (obj->m_pending_removal)
1813                         deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
1814
1815                 // If still known by clients, don't actually remove. On some future
1816                 // invocation this will be 0, which is when removal will continue.
1817                 if(obj->m_known_by_count > 0)
1818                         continue;
1819
1820                 /*
1821                         Move static data from active to stored if deactivated
1822                 */
1823                 if (!obj->m_pending_removal && obj->m_static_exists) {
1824                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1825                         if (block) {
1826                                 std::map<u16, StaticObject>::iterator i =
1827                                         block->m_static_objects.m_active.find(id);
1828                                 if (i != block->m_static_objects.m_active.end()) {
1829                                         block->m_static_objects.m_stored.push_back(i->second);
1830                                         block->m_static_objects.m_active.erase(id);
1831                                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1832                                                 MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
1833                                 } else {
1834                                         warningstream << "ServerEnvironment::removeRemovedObjects(): "
1835                                                         << "id=" << id << " m_static_exists=true but "
1836                                                         << "static data doesn't actually exist in "
1837                                                         << PP(obj->m_static_block) << std::endl;
1838                                 }
1839                         } else {
1840                                 infostream << "Failed to emerge block from which an object to "
1841                                                 << "be deactivated was loaded from. id=" << id << std::endl;
1842                         }
1843                 }
1844
1845                 // Tell the object about removal
1846                 obj->removingFromEnvironment();
1847                 // Deregister in scripting api
1848                 m_script->removeObjectReference(obj);
1849
1850                 // Delete
1851                 if(obj->environmentDeletes())
1852                         delete obj;
1853
1854                 objects_to_remove.push_back(id);
1855         }
1856         // Remove references from m_active_objects
1857         for (u16 i : objects_to_remove) {
1858                 m_active_objects.erase(i);
1859         }
1860 }
1861
1862 static void print_hexdump(std::ostream &o, const std::string &data)
1863 {
1864         const int linelength = 16;
1865         for(int l=0; ; l++){
1866                 int i0 = linelength * l;
1867                 bool at_end = false;
1868                 int thislinelength = linelength;
1869                 if(i0 + thislinelength > (int)data.size()){
1870                         thislinelength = data.size() - i0;
1871                         at_end = true;
1872                 }
1873                 for(int di=0; di<linelength; di++){
1874                         int i = i0 + di;
1875                         char buf[4];
1876                         if(di<thislinelength)
1877                                 porting::mt_snprintf(buf, sizeof(buf), "%.2x ", data[i]);
1878                         else
1879                                 porting::mt_snprintf(buf, sizeof(buf), "   ");
1880                         o<<buf;
1881                 }
1882                 o<<" ";
1883                 for(int di=0; di<thislinelength; di++){
1884                         int i = i0 + di;
1885                         if(data[i] >= 32)
1886                                 o<<data[i];
1887                         else
1888                                 o<<".";
1889                 }
1890                 o<<std::endl;
1891                 if(at_end)
1892                         break;
1893         }
1894 }
1895
1896 /*
1897         Convert stored objects from blocks near the players to active.
1898 */
1899 void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
1900 {
1901         if(block == NULL)
1902                 return;
1903
1904         // Ignore if no stored objects (to not set changed flag)
1905         if(block->m_static_objects.m_stored.empty())
1906                 return;
1907
1908         verbosestream<<"ServerEnvironment::activateObjects(): "
1909                 <<"activating objects of block "<<PP(block->getPos())
1910                 <<" ("<<block->m_static_objects.m_stored.size()
1911                 <<" objects)"<<std::endl;
1912         bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
1913         if (large_amount) {
1914                 errorstream<<"suspiciously large amount of objects detected: "
1915                         <<block->m_static_objects.m_stored.size()<<" in "
1916                         <<PP(block->getPos())
1917                         <<"; removing all of them."<<std::endl;
1918                 // Clear stored list
1919                 block->m_static_objects.m_stored.clear();
1920                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1921                         MOD_REASON_TOO_MANY_OBJECTS);
1922                 return;
1923         }
1924
1925         // Activate stored objects
1926         std::vector<StaticObject> new_stored;
1927         for (const StaticObject &s_obj : block->m_static_objects.m_stored) {
1928                 // Create an active object from the data
1929                 ServerActiveObject *obj = ServerActiveObject::create
1930                         ((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data);
1931                 // If couldn't create object, store static data back.
1932                 if(obj == NULL) {
1933                         errorstream<<"ServerEnvironment::activateObjects(): "
1934                                 <<"failed to create active object from static object "
1935                                 <<"in block "<<PP(s_obj.pos/BS)
1936                                 <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
1937                         print_hexdump(verbosestream, s_obj.data);
1938
1939                         new_stored.push_back(s_obj);
1940                         continue;
1941                 }
1942                 verbosestream<<"ServerEnvironment::activateObjects(): "
1943                         <<"activated static object pos="<<PP(s_obj.pos/BS)
1944                         <<" type="<<(int)s_obj.type<<std::endl;
1945                 // This will also add the object to the active static list
1946                 addActiveObjectRaw(obj, false, dtime_s);
1947         }
1948
1949         // Clear stored list
1950         block->m_static_objects.m_stored.clear();
1951         // Add leftover failed stuff to stored list
1952         for (const StaticObject &s_obj : new_stored) {
1953                 block->m_static_objects.m_stored.push_back(s_obj);
1954         }
1955
1956         /*
1957                 Note: Block hasn't really been modified here.
1958                 The objects have just been activated and moved from the stored
1959                 static list to the active static list.
1960                 As such, the block is essentially the same.
1961                 Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
1962                 Otherwise there would be a huge amount of unnecessary I/O.
1963         */
1964 }
1965
1966 /*
1967         Convert objects that are not standing inside active blocks to static.
1968
1969         If m_known_by_count != 0, active object is not deleted, but static
1970         data is still updated.
1971
1972         If force_delete is set, active object is deleted nevertheless. It
1973         shall only be set so in the destructor of the environment.
1974
1975         If block wasn't generated (not in memory or on disk),
1976 */
1977 void ServerEnvironment::deactivateFarObjects(bool _force_delete)
1978 {
1979         std::vector<u16> objects_to_remove;
1980         for (auto &ao_it : m_active_objects) {
1981                 // force_delete might be overriden per object
1982                 bool force_delete = _force_delete;
1983
1984                 ServerActiveObject* obj = ao_it.second;
1985                 assert(obj);
1986
1987                 // Do not deactivate if static data creation not allowed
1988                 if(!force_delete && !obj->isStaticAllowed())
1989                         continue;
1990
1991                 // removeRemovedObjects() is responsible for these
1992                 if(!force_delete && obj->isGone())
1993                         continue;
1994
1995                 u16 id = ao_it.first;
1996                 v3f objectpos = obj->getBasePosition();
1997
1998                 // The block in which the object resides in
1999                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
2000
2001                 // If object's static data is stored in a deactivated block and object
2002                 // is actually located in an active block, re-save to the block in
2003                 // which the object is actually located in.
2004                 if(!force_delete &&
2005                         obj->m_static_exists &&
2006                         !m_active_blocks.contains(obj->m_static_block) &&
2007                         m_active_blocks.contains(blockpos_o))
2008                 {
2009                         // Delete from block where object was located
2010                         deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
2011
2012                         StaticObject s_obj(obj, objectpos);
2013                         // Save to block where object is located
2014                         saveStaticToBlock(blockpos_o, id, obj, s_obj, MOD_REASON_STATIC_DATA_ADDED);
2015
2016                         continue;
2017                 }
2018
2019                 // If block is still active, don't remove
2020                 if(!force_delete && m_active_blocks.contains(blockpos_o))
2021                         continue;
2022
2023                 verbosestream << "ServerEnvironment::deactivateFarObjects(): "
2024                                 << "deactivating object id=" << id << " on inactive block "
2025                                 << PP(blockpos_o) << std::endl;
2026
2027                 // If known by some client, don't immediately delete.
2028                 bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
2029
2030                 /*
2031                         Update the static data
2032                 */
2033                 if (obj->isStaticAllowed()) {
2034                         // Create new static object
2035                         StaticObject s_obj(obj, objectpos);
2036
2037                         bool stays_in_same_block = false;
2038                         bool data_changed = true;
2039
2040                         // Check if static data has changed considerably
2041                         if (obj->m_static_exists) {
2042                                 if (obj->m_static_block == blockpos_o)
2043                                         stays_in_same_block = true;
2044
2045                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
2046
2047                                 if (block) {
2048                                         std::map<u16, StaticObject>::iterator n =
2049                                                 block->m_static_objects.m_active.find(id);
2050                                         if (n != block->m_static_objects.m_active.end()) {
2051                                                 StaticObject static_old = n->second;
2052
2053                                                 float save_movem = obj->getMinimumSavedMovement();
2054
2055                                                 if (static_old.data == s_obj.data &&
2056                                                         (static_old.pos - objectpos).getLength() < save_movem)
2057                                                         data_changed = false;
2058                                         } else {
2059                                                 warningstream << "ServerEnvironment::deactivateFarObjects(): "
2060                                                                 << "id=" << id << " m_static_exists=true but "
2061                                                                 << "static data doesn't actually exist in "
2062                                                                 << PP(obj->m_static_block) << std::endl;
2063                                         }
2064                                 }
2065                         }
2066
2067                         /*
2068                                 While changes are always saved, blocks are only marked as modified
2069                                 if the object has moved or different staticdata. (see above)
2070                         */
2071                         bool shall_be_written = (!stays_in_same_block || data_changed);
2072                         u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN;
2073
2074                         // Delete old static object
2075                         deleteStaticFromBlock(obj, id, reason, false);
2076
2077                         // Add to the block where the object is located in
2078                         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
2079                         u16 store_id = pending_delete ? id : 0;
2080                         if (!saveStaticToBlock(blockpos, store_id, obj, s_obj, reason))
2081                                 force_delete = true;
2082                 }
2083
2084                 /*
2085                         If known by some client, set pending deactivation.
2086                         Otherwise delete it immediately.
2087                 */
2088                 if(pending_delete && !force_delete)
2089                 {
2090                         verbosestream << "ServerEnvironment::deactivateFarObjects(): "
2091                                         << "object id=" << id << " is known by clients"
2092                                         << "; not deleting yet" << std::endl;
2093
2094                         obj->m_pending_deactivation = true;
2095                         continue;
2096                 }
2097                 verbosestream << "ServerEnvironment::deactivateFarObjects(): "
2098                                 << "object id=" << id << " is not known by clients"
2099                                 << "; deleting" << std::endl;
2100
2101                 // Tell the object about removal
2102                 obj->removingFromEnvironment();
2103                 // Deregister in scripting api
2104                 m_script->removeObjectReference(obj);
2105
2106                 // Delete active object
2107                 if(obj->environmentDeletes())
2108                         delete obj;
2109                 // Id to be removed from m_active_objects
2110                 objects_to_remove.push_back(id);
2111         }
2112
2113         // Remove references from m_active_objects
2114         for (u16 i : objects_to_remove) {
2115                 m_active_objects.erase(i);
2116         }
2117 }
2118
2119 void ServerEnvironment::deleteStaticFromBlock(
2120                 ServerActiveObject *obj, u16 id, u32 mod_reason, bool no_emerge)
2121 {
2122         if (!obj->m_static_exists)
2123                 return;
2124
2125         MapBlock *block;
2126         if (no_emerge)
2127                 block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
2128         else
2129                 block = m_map->emergeBlock(obj->m_static_block, false);
2130         if (!block) {
2131                 if (!no_emerge)
2132                         errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
2133                                         << " when deleting static data of object from it. id=" << id << std::endl;
2134                 return;
2135         }
2136
2137         block->m_static_objects.remove(id);
2138         if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
2139                 block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
2140
2141         obj->m_static_exists = false;
2142 }
2143
2144 bool ServerEnvironment::saveStaticToBlock(
2145                 v3s16 blockpos, u16 store_id,
2146                 ServerActiveObject *obj, const StaticObject &s_obj,
2147                 u32 mod_reason)
2148 {
2149         MapBlock *block = nullptr;
2150         try {
2151                 block = m_map->emergeBlock(blockpos);
2152         } catch (InvalidPositionException &e) {
2153                 // Handled via NULL pointer
2154                 // NOTE: emergeBlock's failure is usually determined by it
2155                 //       actually returning NULL
2156         }
2157
2158         if (!block) {
2159                 errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
2160                                 << " when saving static data of object to it. id=" << store_id << std::endl;
2161                 return false;
2162         }
2163         if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
2164                 warningstream << "ServerEnv: Trying to store id = " << store_id
2165                                 << " statically but block " << PP(blockpos)
2166                                 << " already contains "
2167                                 << block->m_static_objects.m_stored.size()
2168                                 << " objects." << std::endl;
2169                 return false;
2170         }
2171
2172         block->m_static_objects.insert(store_id, s_obj);
2173         if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
2174                 block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
2175
2176         obj->m_static_exists = true;
2177         obj->m_static_block = blockpos;
2178
2179         return true;
2180 }
2181
2182 PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
2183                 const std::string &savedir, const Settings &conf)
2184 {
2185
2186         if (name == "sqlite3")
2187                 return new PlayerDatabaseSQLite3(savedir);
2188
2189         if (name == "dummy")
2190                 return new Database_Dummy();
2191 #if USE_POSTGRESQL
2192         if (name == "postgresql") {
2193                 std::string connect_string;
2194                 conf.getNoEx("pgsql_player_connection", connect_string);
2195                 return new PlayerDatabasePostgreSQL(connect_string);
2196         }
2197 #endif
2198         if (name == "files")
2199                 return new PlayerDatabaseFiles(savedir + DIR_DELIM + "players");
2200
2201         throw BaseException(std::string("Database backend ") + name + " not supported.");
2202 }
2203
2204 bool ServerEnvironment::migratePlayersDatabase(const GameParams &game_params,
2205                 const Settings &cmd_args)
2206 {
2207         std::string migrate_to = cmd_args.get("migrate-players");
2208         Settings world_mt;
2209         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
2210         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
2211                 errorstream << "Cannot read world.mt!" << std::endl;
2212                 return false;
2213         }
2214
2215         if (!world_mt.exists("player_backend")) {
2216                 errorstream << "Please specify your current backend in world.mt:"
2217                         << std::endl
2218                         << "    player_backend = {files|sqlite3|postgresql}"
2219                         << std::endl;
2220                 return false;
2221         }
2222
2223         std::string backend = world_mt.get("player_backend");
2224         if (backend == migrate_to) {
2225                 errorstream << "Cannot migrate: new backend is same"
2226                         << " as the old one" << std::endl;
2227                 return false;
2228         }
2229
2230         const std::string players_backup_path = game_params.world_path + DIR_DELIM
2231                 + "players.bak";
2232
2233         if (backend == "files") {
2234                 // Create backup directory
2235                 fs::CreateDir(players_backup_path);
2236         }
2237
2238         try {
2239                 PlayerDatabase *srcdb = ServerEnvironment::openPlayerDatabase(backend,
2240                         game_params.world_path, world_mt);
2241                 PlayerDatabase *dstdb = ServerEnvironment::openPlayerDatabase(migrate_to,
2242                         game_params.world_path, world_mt);
2243
2244                 std::vector<std::string> player_list;
2245                 srcdb->listPlayers(player_list);
2246                 for (std::vector<std::string>::const_iterator it = player_list.begin();
2247                         it != player_list.end(); ++it) {
2248                         actionstream << "Migrating player " << it->c_str() << std::endl;
2249                         RemotePlayer player(it->c_str(), NULL);
2250                         PlayerSAO playerSAO(NULL, &player, 15000, false);
2251
2252                         srcdb->loadPlayer(&player, &playerSAO);
2253
2254                         playerSAO.finalize(&player, std::set<std::string>());
2255                         player.setPlayerSAO(&playerSAO);
2256
2257                         dstdb->savePlayer(&player);
2258
2259                         // For files source, move player files to backup dir
2260                         if (backend == "files") {
2261                                 fs::Rename(
2262                                         game_params.world_path + DIR_DELIM + "players" + DIR_DELIM + (*it),
2263                                         players_backup_path + DIR_DELIM + (*it));
2264                         }
2265                 }
2266
2267                 actionstream << "Successfully migrated " << player_list.size() << " players"
2268                         << std::endl;
2269                 world_mt.set("player_backend", migrate_to);
2270                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
2271                         errorstream << "Failed to update world.mt!" << std::endl;
2272                 else
2273                         actionstream << "world.mt updated" << std::endl;
2274
2275                 // When migration is finished from file backend, remove players directory if empty
2276                 if (backend == "files") {
2277                         fs::DeleteSingleFileOrEmptyDirectory(game_params.world_path + DIR_DELIM
2278                                 + "players");
2279                 }
2280
2281                 delete srcdb;
2282                 delete dstdb;
2283
2284         } catch (BaseException &e) {
2285                 errorstream << "An error occured during migration: " << e.what() << std::endl;
2286                 return false;
2287         }
2288         return true;
2289 }
2290
2291 AuthDatabase *ServerEnvironment::openAuthDatabase(
2292                 const std::string &name, const std::string &savedir, const Settings &conf)
2293 {
2294         if (name == "sqlite3")
2295                 return new AuthDatabaseSQLite3(savedir);
2296
2297         if (name == "files")
2298                 return new AuthDatabaseFiles(savedir);
2299
2300         throw BaseException(std::string("Database backend ") + name + " not supported.");
2301 }
2302
2303 bool ServerEnvironment::migrateAuthDatabase(
2304                 const GameParams &game_params, const Settings &cmd_args)
2305 {
2306         std::string migrate_to = cmd_args.get("migrate-auth");
2307         Settings world_mt;
2308         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
2309         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
2310                 errorstream << "Cannot read world.mt!" << std::endl;
2311                 return false;
2312         }
2313
2314         std::string backend = "files";
2315         if (world_mt.exists("auth_backend"))
2316                 backend = world_mt.get("auth_backend");
2317         else
2318                 warningstream << "No auth_backend found in world.mt, "
2319                                 "assuming \"files\"." << std::endl;
2320
2321         if (backend == migrate_to) {
2322                 errorstream << "Cannot migrate: new backend is same"
2323                                 << " as the old one" << std::endl;
2324                 return false;
2325         }
2326
2327         try {
2328                 const std::unique_ptr<AuthDatabase> srcdb(ServerEnvironment::openAuthDatabase(
2329                                 backend, game_params.world_path, world_mt));
2330                 const std::unique_ptr<AuthDatabase> dstdb(ServerEnvironment::openAuthDatabase(
2331                                 migrate_to, game_params.world_path, world_mt));
2332
2333                 std::vector<std::string> names_list;
2334                 srcdb->listNames(names_list);
2335                 for (const std::string &name : names_list) {
2336                         actionstream << "Migrating auth entry for " << name << std::endl;
2337                         bool success;
2338                         AuthEntry authEntry;
2339                         success = srcdb->getAuth(name, authEntry);
2340                         success = success && dstdb->createAuth(authEntry);
2341                         if (!success)
2342                                 errorstream << "Failed to migrate " << name << std::endl;
2343                 }
2344
2345                 actionstream << "Successfully migrated " << names_list.size()
2346                                 << " auth entries" << std::endl;
2347                 world_mt.set("auth_backend", migrate_to);
2348                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
2349                         errorstream << "Failed to update world.mt!" << std::endl;
2350                 else
2351                         actionstream << "world.mt updated" << std::endl;
2352
2353                 if (backend == "files") {
2354                         // special-case files migration:
2355                         // move auth.txt to auth.txt.bak if possible
2356                         std::string auth_txt_path =
2357                                         game_params.world_path + DIR_DELIM + "auth.txt";
2358                         std::string auth_bak_path = auth_txt_path + ".bak";
2359                         if (!fs::PathExists(auth_bak_path))
2360                                 if (fs::Rename(auth_txt_path, auth_bak_path))
2361                                         actionstream << "Renamed auth.txt to auth.txt.bak"
2362                                                         << std::endl;
2363                                 else
2364                                         errorstream << "Could not rename auth.txt to "
2365                                                         "auth.txt.bak" << std::endl;
2366                         else
2367                                 warningstream << "auth.txt.bak already exists, auth.txt "
2368                                                 "not renamed" << std::endl;
2369                 }
2370
2371         } catch (BaseException &e) {
2372                 errorstream << "An error occured during migration: " << e.what()
2373                             << std::endl;
2374                 return false;
2375         }
2376         return true;
2377 }