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