]> git.lizzy.rs Git - dragonfireclient.git/blob - src/serverenvironment.cpp
Immediately activate blocks when a player joins
[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         // Update active blocks asap so objects in those blocks appear on the client
630         m_force_update_active_blocks = true;
631
632         return playersao;
633 }
634
635 void ServerEnvironment::saveMeta()
636 {
637         if (!m_meta_loaded)
638                 return;
639
640         std::string path = m_path_world + DIR_DELIM "env_meta.txt";
641
642         // Open file and serialize
643         std::ostringstream ss(std::ios_base::binary);
644
645         Settings args("EnvArgsEnd");
646         args.setU64("game_time", m_game_time);
647         args.setU64("time_of_day", getTimeOfDay());
648         args.setU64("last_clear_objects_time", m_last_clear_objects_time);
649         args.setU64("lbm_introduction_times_version", 1);
650         args.set("lbm_introduction_times",
651                 m_lbm_mgr.createIntroductionTimesString());
652         args.setU64("day_count", m_day_count);
653         args.writeLines(ss);
654
655         if(!fs::safeWriteToFile(path, ss.str()))
656         {
657                 infostream<<"ServerEnvironment::saveMeta(): Failed to write "
658                         <<path<<std::endl;
659                 throw SerializationError("Couldn't save env meta");
660         }
661 }
662
663 void ServerEnvironment::loadMeta()
664 {
665         SANITY_CHECK(!m_meta_loaded);
666         m_meta_loaded = true;
667
668         // If file doesn't exist, load default environment metadata
669         if (!fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt")) {
670                 infostream << "ServerEnvironment: Loading default environment metadata"
671                         << std::endl;
672                 loadDefaultMeta();
673                 return;
674         }
675
676         infostream << "ServerEnvironment: Loading environment metadata" << std::endl;
677
678         std::string path = m_path_world + DIR_DELIM "env_meta.txt";
679
680         // Open file and deserialize
681         std::ifstream is(path.c_str(), std::ios_base::binary);
682         if (!is.good()) {
683                 infostream << "ServerEnvironment::loadMeta(): Failed to open "
684                         << path << std::endl;
685                 throw SerializationError("Couldn't load env meta");
686         }
687
688         Settings args("EnvArgsEnd");
689
690         if (!args.parseConfigLines(is)) {
691                 throw SerializationError("ServerEnvironment::loadMeta(): "
692                         "EnvArgsEnd not found!");
693         }
694
695         try {
696                 m_game_time = args.getU64("game_time");
697         } catch (SettingNotFoundException &e) {
698                 // Getting this is crucial, otherwise timestamps are useless
699                 throw SerializationError("Couldn't load env meta game_time");
700         }
701
702         setTimeOfDay(args.exists("time_of_day") ?
703                 // set day to early morning by default
704                 args.getU64("time_of_day") : 5250);
705
706         m_last_clear_objects_time = args.exists("last_clear_objects_time") ?
707                 // If missing, do as if clearObjects was never called
708                 args.getU64("last_clear_objects_time") : 0;
709
710         std::string lbm_introduction_times;
711         try {
712                 u64 ver = args.getU64("lbm_introduction_times_version");
713                 if (ver == 1) {
714                         lbm_introduction_times = args.get("lbm_introduction_times");
715                 } else {
716                         infostream << "ServerEnvironment::loadMeta(): Non-supported"
717                                 << " introduction time version " << ver << std::endl;
718                 }
719         } catch (SettingNotFoundException &e) {
720                 // No problem, this is expected. Just continue with an empty string
721         }
722         m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_server, m_game_time);
723
724         m_day_count = args.exists("day_count") ?
725                 args.getU64("day_count") : 0;
726 }
727
728 /**
729  * called if env_meta.txt doesn't exist (e.g. new world)
730  */
731 void ServerEnvironment::loadDefaultMeta()
732 {
733         m_lbm_mgr.loadIntroductionTimes("", m_server, m_game_time);
734 }
735
736 struct ActiveABM
737 {
738         ActiveBlockModifier *abm;
739         int chance;
740         std::vector<content_t> required_neighbors;
741         bool check_required_neighbors; // false if required_neighbors is known to be empty
742         s16 min_y;
743         s16 max_y;
744 };
745
746 class ABMHandler
747 {
748 private:
749         ServerEnvironment *m_env;
750         std::vector<std::vector<ActiveABM> *> m_aabms;
751 public:
752         ABMHandler(std::vector<ABMWithState> &abms,
753                 float dtime_s, ServerEnvironment *env,
754                 bool use_timers):
755                 m_env(env)
756         {
757                 if(dtime_s < 0.001)
758                         return;
759                 const NodeDefManager *ndef = env->getGameDef()->ndef();
760                 for (ABMWithState &abmws : abms) {
761                         ActiveBlockModifier *abm = abmws.abm;
762                         float trigger_interval = abm->getTriggerInterval();
763                         if(trigger_interval < 0.001)
764                                 trigger_interval = 0.001;
765                         float actual_interval = dtime_s;
766                         if(use_timers){
767                                 abmws.timer += dtime_s;
768                                 if(abmws.timer < trigger_interval)
769                                         continue;
770                                 abmws.timer -= trigger_interval;
771                                 actual_interval = trigger_interval;
772                         }
773                         float chance = abm->getTriggerChance();
774                         if(chance == 0)
775                                 chance = 1;
776                         ActiveABM aabm;
777                         aabm.abm = abm;
778                         if (abm->getSimpleCatchUp()) {
779                                 float intervals = actual_interval / trigger_interval;
780                                 if(intervals == 0)
781                                         continue;
782                                 aabm.chance = chance / intervals;
783                                 if(aabm.chance == 0)
784                                         aabm.chance = 1;
785                         } else {
786                                 aabm.chance = chance;
787                         }
788                         // y limits
789                         aabm.min_y = abm->getMinY();
790                         aabm.max_y = abm->getMaxY();
791
792                         // Trigger neighbors
793                         const std::vector<std::string> &required_neighbors_s =
794                                 abm->getRequiredNeighbors();
795                         for (const std::string &required_neighbor_s : required_neighbors_s) {
796                                 ndef->getIds(required_neighbor_s, aabm.required_neighbors);
797                         }
798                         aabm.check_required_neighbors = !required_neighbors_s.empty();
799
800                         // Trigger contents
801                         const std::vector<std::string> &contents_s = abm->getTriggerContents();
802                         for (const std::string &content_s : contents_s) {
803                                 std::vector<content_t> ids;
804                                 ndef->getIds(content_s, ids);
805                                 for (content_t c : ids) {
806                                         if (c >= m_aabms.size())
807                                                 m_aabms.resize(c + 256, NULL);
808                                         if (!m_aabms[c])
809                                                 m_aabms[c] = new std::vector<ActiveABM>;
810                                         m_aabms[c]->push_back(aabm);
811                                 }
812                         }
813                 }
814         }
815
816         ~ABMHandler()
817         {
818                 for (auto &aabms : m_aabms)
819                         delete aabms;
820         }
821
822         // Find out how many objects the given block and its neighbours contain.
823         // Returns the number of objects in the block, and also in 'wider' the
824         // number of objects in the block and all its neighbours. The latter
825         // may an estimate if any neighbours are unloaded.
826         u32 countObjects(MapBlock *block, ServerMap * map, u32 &wider)
827         {
828                 wider = 0;
829                 u32 wider_unknown_count = 0;
830                 for(s16 x=-1; x<=1; x++)
831                         for(s16 y=-1; y<=1; y++)
832                                 for(s16 z=-1; z<=1; z++)
833                                 {
834                                         MapBlock *block2 = map->getBlockNoCreateNoEx(
835                                                 block->getPos() + v3s16(x,y,z));
836                                         if(block2==NULL){
837                                                 wider_unknown_count++;
838                                                 continue;
839                                         }
840                                         wider += block2->m_static_objects.m_active.size()
841                                                 + block2->m_static_objects.m_stored.size();
842                                 }
843                 // Extrapolate
844                 u32 active_object_count = block->m_static_objects.m_active.size();
845                 u32 wider_known_count = 3*3*3 - wider_unknown_count;
846                 wider += wider_unknown_count * wider / wider_known_count;
847                 return active_object_count;
848
849         }
850         void apply(MapBlock *block, int &blocks_scanned, int &abms_run, int &blocks_cached)
851         {
852                 if(m_aabms.empty() || block->isDummy())
853                         return;
854
855                 // Check the content type cache first
856                 // to see whether there are any ABMs
857                 // to be run at all for this block.
858                 if (block->contents_cached) {
859                         blocks_cached++;
860                         bool run_abms = false;
861                         for (content_t c : block->contents) {
862                                 if (c < m_aabms.size() && m_aabms[c]) {
863                                         run_abms = true;
864                                         break;
865                                 }
866                         }
867                         if (!run_abms)
868                                 return;
869                 } else {
870                         // Clear any caching
871                         block->contents.clear();
872                 }
873                 blocks_scanned++;
874
875                 ServerMap *map = &m_env->getServerMap();
876
877                 u32 active_object_count_wider;
878                 u32 active_object_count = this->countObjects(block, map, active_object_count_wider);
879                 m_env->m_added_objects = 0;
880
881                 v3s16 p0;
882                 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
883                 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
884                 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
885                 {
886                         const MapNode &n = block->getNodeUnsafe(p0);
887                         content_t c = n.getContent();
888                         // Cache content types as we go
889                         if (!block->contents_cached && !block->do_not_cache_contents) {
890                                 block->contents.insert(c);
891                                 if (block->contents.size() > 64) {
892                                         // Too many different nodes... don't try to cache
893                                         block->do_not_cache_contents = true;
894                                         block->contents.clear();
895                                 }
896                         }
897
898                         if (c >= m_aabms.size() || !m_aabms[c])
899                                 continue;
900
901                         v3s16 p = p0 + block->getPosRelative();
902                         for (ActiveABM &aabm : *m_aabms[c]) {
903                                 if ((p.Y < aabm.min_y) || (p.Y > aabm.max_y))
904                                         continue;
905
906                                 if (myrand() % aabm.chance != 0)
907                                         continue;
908
909                                 // Check neighbors
910                                 if (aabm.check_required_neighbors) {
911                                         v3s16 p1;
912                                         for(p1.X = p0.X-1; p1.X <= p0.X+1; p1.X++)
913                                         for(p1.Y = p0.Y-1; p1.Y <= p0.Y+1; p1.Y++)
914                                         for(p1.Z = p0.Z-1; p1.Z <= p0.Z+1; p1.Z++)
915                                         {
916                                                 if(p1 == p0)
917                                                         continue;
918                                                 content_t c;
919                                                 if (block->isValidPosition(p1)) {
920                                                         // if the neighbor is found on the same map block
921                                                         // get it straight from there
922                                                         const MapNode &n = block->getNodeUnsafe(p1);
923                                                         c = n.getContent();
924                                                 } else {
925                                                         // otherwise consult the map
926                                                         MapNode n = map->getNode(p1 + block->getPosRelative());
927                                                         c = n.getContent();
928                                                 }
929                                                 if (CONTAINS(aabm.required_neighbors, c))
930                                                         goto neighbor_found;
931                                         }
932                                         // No required neighbor found
933                                         continue;
934                                 }
935                                 neighbor_found:
936
937                                 abms_run++;
938                                 // Call all the trigger variations
939                                 aabm.abm->trigger(m_env, p, n);
940                                 aabm.abm->trigger(m_env, p, n,
941                                         active_object_count, active_object_count_wider);
942
943                                 // Count surrounding objects again if the abms added any
944                                 if(m_env->m_added_objects > 0) {
945                                         active_object_count = countObjects(block, map, active_object_count_wider);
946                                         m_env->m_added_objects = 0;
947                                 }
948                         }
949                 }
950                 block->contents_cached = !block->do_not_cache_contents;
951         }
952 };
953
954 void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
955 {
956         // Reset usage timer immediately, otherwise a block that becomes active
957         // again at around the same time as it would normally be unloaded will
958         // get unloaded incorrectly. (I think this still leaves a small possibility
959         // of a race condition between this and server::AsyncRunStep, which only
960         // some kind of synchronisation will fix, but it at least reduces the window
961         // of opportunity for it to break from seconds to nanoseconds)
962         block->resetUsageTimer();
963
964         // Get time difference
965         u32 dtime_s = 0;
966         u32 stamp = block->getTimestamp();
967         if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
968                 dtime_s = m_game_time - stamp;
969         dtime_s += additional_dtime;
970
971         /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
972                         <<stamp<<", game time: "<<m_game_time<<std::endl;*/
973
974         // Remove stored static objects if clearObjects was called since block's timestamp
975         if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) {
976                 block->m_static_objects.m_stored.clear();
977                 // do not set changed flag to avoid unnecessary mapblock writes
978         }
979
980         // Set current time as timestamp
981         block->setTimestampNoChangedFlag(m_game_time);
982
983         /*infostream<<"ServerEnvironment::activateBlock(): block is "
984                         <<dtime_s<<" seconds old."<<std::endl;*/
985
986         // Activate stored objects
987         activateObjects(block, dtime_s);
988
989         /* Handle LoadingBlockModifiers */
990         m_lbm_mgr.applyLBMs(this, block, stamp);
991
992         // Run node timers
993         std::vector<NodeTimer> elapsed_timers =
994                 block->m_node_timers.step((float)dtime_s);
995         if (!elapsed_timers.empty()) {
996                 MapNode n;
997                 for (const NodeTimer &elapsed_timer : elapsed_timers) {
998                         n = block->getNodeNoEx(elapsed_timer.position);
999                         v3s16 p = elapsed_timer.position + block->getPosRelative();
1000                         if (m_script->node_on_timer(p, n, elapsed_timer.elapsed))
1001                                 block->setNodeTimer(NodeTimer(elapsed_timer.timeout, 0,
1002                                         elapsed_timer.position));
1003                 }
1004         }
1005 }
1006
1007 void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
1008 {
1009         m_abms.emplace_back(abm);
1010 }
1011
1012 void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm)
1013 {
1014         m_lbm_mgr.addLBMDef(lbm);
1015 }
1016
1017 bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
1018 {
1019         const NodeDefManager *ndef = m_server->ndef();
1020         MapNode n_old = m_map->getNode(p);
1021
1022         const ContentFeatures &cf_old = ndef->get(n_old);
1023
1024         // Call destructor
1025         if (cf_old.has_on_destruct)
1026                 m_script->node_on_destruct(p, n_old);
1027
1028         // Replace node
1029         if (!m_map->addNodeWithEvent(p, n))
1030                 return false;
1031
1032         // Update active VoxelManipulator if a mapgen thread
1033         m_map->updateVManip(p);
1034
1035         // Call post-destructor
1036         if (cf_old.has_after_destruct)
1037                 m_script->node_after_destruct(p, n_old);
1038
1039         // Retrieve node content features
1040         // if new node is same as old, reuse old definition to prevent a lookup
1041         const ContentFeatures &cf_new = n_old == n ? cf_old : ndef->get(n);
1042
1043         // Call constructor
1044         if (cf_new.has_on_construct)
1045                 m_script->node_on_construct(p, n);
1046
1047         return true;
1048 }
1049
1050 bool ServerEnvironment::removeNode(v3s16 p)
1051 {
1052         const NodeDefManager *ndef = m_server->ndef();
1053         MapNode n_old = m_map->getNode(p);
1054
1055         // Call destructor
1056         if (ndef->get(n_old).has_on_destruct)
1057                 m_script->node_on_destruct(p, n_old);
1058
1059         // Replace with air
1060         // This is slightly optimized compared to addNodeWithEvent(air)
1061         if (!m_map->removeNodeWithEvent(p))
1062                 return false;
1063
1064         // Update active VoxelManipulator if a mapgen thread
1065         m_map->updateVManip(p);
1066
1067         // Call post-destructor
1068         if (ndef->get(n_old).has_after_destruct)
1069                 m_script->node_after_destruct(p, n_old);
1070
1071         // Air doesn't require constructor
1072         return true;
1073 }
1074
1075 bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
1076 {
1077         if (!m_map->addNodeWithEvent(p, n, false))
1078                 return false;
1079
1080         // Update active VoxelManipulator if a mapgen thread
1081         m_map->updateVManip(p);
1082
1083         return true;
1084 }
1085
1086 u8 ServerEnvironment::findSunlight(v3s16 pos) const
1087 {
1088         // Directions for neighbouring nodes with specified order
1089         static const v3s16 dirs[] = {
1090                 v3s16(-1, 0, 0), v3s16(1, 0, 0), v3s16(0, 0, -1), v3s16(0, 0, 1),
1091                 v3s16(0, -1, 0), v3s16(0, 1, 0)
1092         };
1093
1094         const NodeDefManager *ndef = m_server->ndef();
1095
1096         // found_light remembers the highest known sunlight value at pos
1097         u8 found_light = 0;
1098
1099         struct stack_entry {
1100                 v3s16 pos;
1101                 s16 dist;
1102         };
1103         std::stack<stack_entry> stack;
1104         stack.push({pos, 0});
1105
1106         std::unordered_map<s64, s8> dists;
1107         dists[MapDatabase::getBlockAsInteger(pos)] = 0;
1108
1109         while (!stack.empty()) {
1110                 struct stack_entry e = stack.top();
1111                 stack.pop();
1112
1113                 v3s16 currentPos = e.pos;
1114                 s8 dist = e.dist + 1;
1115
1116                 for (const v3s16& off : dirs) {
1117                         v3s16 neighborPos = currentPos + off;
1118                         s64 neighborHash = MapDatabase::getBlockAsInteger(neighborPos);
1119
1120                         // Do not walk neighborPos multiple times unless the distance to the start
1121                         // position is shorter
1122                         auto it = dists.find(neighborHash);
1123                         if (it != dists.end() && dist >= it->second)
1124                                 continue;
1125
1126                         // Position to walk
1127                         bool is_position_ok;
1128                         MapNode node = m_map->getNode(neighborPos, &is_position_ok);
1129                         if (!is_position_ok) {
1130                                 // This happens very rarely because the map at currentPos is loaded
1131                                 m_map->emergeBlock(neighborPos, false);
1132                                 node = m_map->getNode(neighborPos, &is_position_ok);
1133                                 if (!is_position_ok)
1134                                         continue;  // not generated
1135                         }
1136
1137                         const ContentFeatures &def = ndef->get(node);
1138                         if (!def.sunlight_propagates) {
1139                                 // Do not test propagation here again
1140                                 dists[neighborHash] = -1;
1141                                 continue;
1142                         }
1143
1144                         // Sunlight could have come from here
1145                         dists[neighborHash] = dist;
1146                         u8 daylight = node.param1 & 0x0f;
1147
1148                         // In the special case where sunlight shines from above and thus
1149                         // does not decrease with upwards distance, daylight is always
1150                         // bigger than nightlight, which never reaches 15
1151                         int possible_finlight = daylight - dist;
1152                         if (possible_finlight <= found_light) {
1153                                 // Light from here cannot make a brighter light at currentPos than
1154                                 // found_light
1155                                 continue;
1156                         }
1157
1158                         u8 nightlight = node.param1 >> 4;
1159                         if (daylight > nightlight) {
1160                                 // Found a valid daylight
1161                                 found_light = possible_finlight;
1162                         } else {
1163                                 // Sunlight may be darker, so walk the neighbours
1164                                 stack.push({neighborPos, dist});
1165                         }
1166                 }
1167         }
1168         return found_light;
1169 }
1170
1171 void ServerEnvironment::clearObjects(ClearObjectsMode mode)
1172 {
1173         infostream << "ServerEnvironment::clearObjects(): "
1174                 << "Removing all active objects" << std::endl;
1175         auto cb_removal = [this] (ServerActiveObject *obj, u16 id) {
1176                 if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
1177                         return false;
1178
1179                 // Delete static object if block is loaded
1180                 deleteStaticFromBlock(obj, id, MOD_REASON_CLEAR_ALL_OBJECTS, true);
1181
1182                 // If known by some client, don't delete immediately
1183                 if (obj->m_known_by_count > 0) {
1184                         obj->markForRemoval();
1185                         return false;
1186                 }
1187
1188                 // Tell the object about removal
1189                 obj->removingFromEnvironment();
1190                 // Deregister in scripting api
1191                 m_script->removeObjectReference(obj);
1192
1193                 // Delete active object
1194                 if (obj->environmentDeletes())
1195                         delete obj;
1196
1197                 return true;
1198         };
1199
1200         m_ao_manager.clear(cb_removal);
1201
1202         // Get list of loaded blocks
1203         std::vector<v3s16> loaded_blocks;
1204         infostream << "ServerEnvironment::clearObjects(): "
1205                 << "Listing all loaded blocks" << std::endl;
1206         m_map->listAllLoadedBlocks(loaded_blocks);
1207         infostream << "ServerEnvironment::clearObjects(): "
1208                 << "Done listing all loaded blocks: "
1209                 << loaded_blocks.size()<<std::endl;
1210
1211         // Get list of loadable blocks
1212         std::vector<v3s16> loadable_blocks;
1213         if (mode == CLEAR_OBJECTS_MODE_FULL) {
1214                 infostream << "ServerEnvironment::clearObjects(): "
1215                         << "Listing all loadable blocks" << std::endl;
1216                 m_map->listAllLoadableBlocks(loadable_blocks);
1217                 infostream << "ServerEnvironment::clearObjects(): "
1218                         << "Done listing all loadable blocks: "
1219                         << loadable_blocks.size() << std::endl;
1220         } else {
1221                 loadable_blocks = loaded_blocks;
1222         }
1223
1224         actionstream << "ServerEnvironment::clearObjects(): "
1225                 << "Now clearing objects in " << loadable_blocks.size()
1226                 << " blocks" << std::endl;
1227
1228         // Grab a reference on each loaded block to avoid unloading it
1229         for (v3s16 p : loaded_blocks) {
1230                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1231                 assert(block != NULL);
1232                 block->refGrab();
1233         }
1234
1235         // Remove objects in all loadable blocks
1236         u32 unload_interval = U32_MAX;
1237         if (mode == CLEAR_OBJECTS_MODE_FULL) {
1238                 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
1239                 unload_interval = MYMAX(unload_interval, 1);
1240         }
1241         u32 report_interval = loadable_blocks.size() / 10;
1242         u32 num_blocks_checked = 0;
1243         u32 num_blocks_cleared = 0;
1244         u32 num_objs_cleared = 0;
1245         for (auto i = loadable_blocks.begin();
1246                 i != loadable_blocks.end(); ++i) {
1247                 v3s16 p = *i;
1248                 MapBlock *block = m_map->emergeBlock(p, false);
1249                 if (!block) {
1250                         errorstream << "ServerEnvironment::clearObjects(): "
1251                                 << "Failed to emerge block " << PP(p) << std::endl;
1252                         continue;
1253                 }
1254                 u32 num_stored = block->m_static_objects.m_stored.size();
1255                 u32 num_active = block->m_static_objects.m_active.size();
1256                 if (num_stored != 0 || num_active != 0) {
1257                         block->m_static_objects.m_stored.clear();
1258                         block->m_static_objects.m_active.clear();
1259                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1260                                 MOD_REASON_CLEAR_ALL_OBJECTS);
1261                         num_objs_cleared += num_stored + num_active;
1262                         num_blocks_cleared++;
1263                 }
1264                 num_blocks_checked++;
1265
1266                 if (report_interval != 0 &&
1267                         num_blocks_checked % report_interval == 0) {
1268                         float percent = 100.0 * (float)num_blocks_checked /
1269                                 loadable_blocks.size();
1270                         actionstream << "ServerEnvironment::clearObjects(): "
1271                                 << "Cleared " << num_objs_cleared << " objects"
1272                                 << " in " << num_blocks_cleared << " blocks ("
1273                                 << percent << "%)" << std::endl;
1274                 }
1275                 if (num_blocks_checked % unload_interval == 0) {
1276                         m_map->unloadUnreferencedBlocks();
1277                 }
1278         }
1279         m_map->unloadUnreferencedBlocks();
1280
1281         // Drop references that were added above
1282         for (v3s16 p : loaded_blocks) {
1283                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1284                 assert(block);
1285                 block->refDrop();
1286         }
1287
1288         m_last_clear_objects_time = m_game_time;
1289
1290         actionstream << "ServerEnvironment::clearObjects(): "
1291                 << "Finished: Cleared " << num_objs_cleared << " objects"
1292                 << " in " << num_blocks_cleared << " blocks" << std::endl;
1293 }
1294
1295 void ServerEnvironment::step(float dtime)
1296 {
1297         ScopeProfiler sp2(g_profiler, "ServerEnv::step()", SPT_AVG);
1298         const auto start_time = porting::getTimeUs();
1299
1300         /* Step time of day */
1301         stepTimeOfDay(dtime);
1302
1303         // Update this one
1304         // NOTE: This is kind of funny on a singleplayer game, but doesn't
1305         // really matter that much.
1306         static thread_local const float server_step =
1307                         g_settings->getFloat("dedicated_server_step");
1308         m_recommended_send_interval = server_step;
1309
1310         /*
1311                 Increment game time
1312         */
1313         {
1314                 m_game_time_fraction_counter += dtime;
1315                 u32 inc_i = (u32)m_game_time_fraction_counter;
1316                 m_game_time += inc_i;
1317                 m_game_time_fraction_counter -= (float)inc_i;
1318         }
1319
1320         /*
1321                 Handle players
1322         */
1323         {
1324                 ScopeProfiler sp(g_profiler, "ServerEnv: move players", SPT_AVG);
1325                 for (RemotePlayer *player : m_players) {
1326                         // Ignore disconnected players
1327                         if (player->getPeerId() == PEER_ID_INEXISTENT)
1328                                 continue;
1329
1330                         // Move
1331                         player->move(dtime, this, 100 * BS);
1332                 }
1333         }
1334
1335         /*
1336                 Manage active block list
1337         */
1338         if (m_active_blocks_mgmt_interval.step(dtime, m_cache_active_block_mgmt_interval) ||
1339                 m_force_update_active_blocks) {
1340                 ScopeProfiler sp(g_profiler, "ServerEnv: update active blocks", SPT_AVG);
1341
1342                 /*
1343                         Get player block positions
1344                 */
1345                 std::vector<PlayerSAO*> players;
1346                 for (RemotePlayer *player: m_players) {
1347                         // Ignore disconnected players
1348                         if (player->getPeerId() == PEER_ID_INEXISTENT)
1349                                 continue;
1350
1351                         PlayerSAO *playersao = player->getPlayerSAO();
1352                         assert(playersao);
1353
1354                         players.push_back(playersao);
1355                 }
1356
1357                 /*
1358                         Update list of active blocks, collecting changes
1359                 */
1360                 // use active_object_send_range_blocks since that is max distance
1361                 // for active objects sent the client anyway
1362                 static thread_local const s16 active_object_range =
1363                                 g_settings->getS16("active_object_send_range_blocks");
1364                 static thread_local const s16 active_block_range =
1365                                 g_settings->getS16("active_block_range");
1366                 std::set<v3s16> blocks_removed;
1367                 std::set<v3s16> blocks_added;
1368                 m_active_blocks.update(players, active_block_range, active_object_range,
1369                         blocks_removed, blocks_added);
1370
1371                 m_active_block_gauge->set(m_active_blocks.size());
1372
1373                 /*
1374                         Handle removed blocks
1375                 */
1376
1377                 // Convert active objects that are no more in active blocks to static
1378                 deactivateFarObjects(false);
1379
1380                 for (const v3s16 &p: blocks_removed) {
1381                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1382                         if (!block)
1383                                 continue;
1384
1385                         // Set current time as timestamp (and let it set ChangedFlag)
1386                         block->setTimestamp(m_game_time);
1387                 }
1388
1389                 /*
1390                         Handle added blocks
1391                 */
1392
1393                 for (const v3s16 &p: blocks_added) {
1394                         MapBlock *block = m_map->getBlockOrEmerge(p);
1395                         if (!block) {
1396                                 m_active_blocks.m_list.erase(p);
1397                                 m_active_blocks.m_abm_list.erase(p);
1398                                 continue;
1399                         }
1400
1401                         activateBlock(block);
1402                 }
1403         }
1404         m_force_update_active_blocks = false;
1405
1406         /*
1407                 Mess around in active blocks
1408         */
1409         if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval)) {
1410                 ScopeProfiler sp(g_profiler, "ServerEnv: Run node timers", SPT_AVG);
1411
1412                 float dtime = m_cache_nodetimer_interval;
1413
1414                 for (const v3s16 &p: m_active_blocks.m_list) {
1415                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1416                         if (!block)
1417                                 continue;
1418
1419                         // Reset block usage timer
1420                         block->resetUsageTimer();
1421
1422                         // Set current time as timestamp
1423                         block->setTimestampNoChangedFlag(m_game_time);
1424                         // If time has changed much from the one on disk,
1425                         // set block to be saved when it is unloaded
1426                         if(block->getTimestamp() > block->getDiskTimestamp() + 60)
1427                                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1428                                         MOD_REASON_BLOCK_EXPIRED);
1429
1430                         // Run node timers
1431                         std::vector<NodeTimer> elapsed_timers = block->m_node_timers.step(dtime);
1432                         if (!elapsed_timers.empty()) {
1433                                 MapNode n;
1434                                 v3s16 p2;
1435                                 for (const NodeTimer &elapsed_timer: elapsed_timers) {
1436                                         n = block->getNodeNoEx(elapsed_timer.position);
1437                                         p2 = elapsed_timer.position + block->getPosRelative();
1438                                         if (m_script->node_on_timer(p2, n, elapsed_timer.elapsed)) {
1439                                                 block->setNodeTimer(NodeTimer(
1440                                                         elapsed_timer.timeout, 0, elapsed_timer.position));
1441                                         }
1442                                 }
1443                         }
1444                 }
1445         }
1446
1447         if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval)) {
1448                 ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG);
1449                 TimeTaker timer("modify in active blocks per interval");
1450
1451                 // Initialize handling of ActiveBlockModifiers
1452                 ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);
1453
1454                 int blocks_scanned = 0;
1455                 int abms_run = 0;
1456                 int blocks_cached = 0;
1457
1458                 std::vector<v3s16> output(m_active_blocks.m_abm_list.size());
1459
1460                 // Shuffle the active blocks so that each block gets an equal chance
1461                 // of having its ABMs run.
1462                 std::copy(m_active_blocks.m_abm_list.begin(), m_active_blocks.m_abm_list.end(), output.begin());
1463                 std::shuffle(output.begin(), output.end(), m_rgen);
1464
1465                 int i = 0;
1466                 // determine the time budget for ABMs
1467                 u32 max_time_ms = m_cache_abm_interval * 1000 * m_cache_abm_time_budget;
1468                 for (const v3s16 &p : output) {
1469                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1470                         if (!block)
1471                                 continue;
1472
1473                         i++;
1474
1475                         // Set current time as timestamp
1476                         block->setTimestampNoChangedFlag(m_game_time);
1477
1478                         /* Handle ActiveBlockModifiers */
1479                         abmhandler.apply(block, blocks_scanned, abms_run, blocks_cached);
1480
1481                         u32 time_ms = timer.getTimerTime();
1482
1483                         if (time_ms > max_time_ms) {
1484                                 warningstream << "active block modifiers took "
1485                                           << time_ms << "ms (processed " << i << " of "
1486                                           << output.size() << " active blocks)" << std::endl;
1487                                 break;
1488                         }
1489                 }
1490                 g_profiler->avg("ServerEnv: active blocks", m_active_blocks.m_abm_list.size());
1491                 g_profiler->avg("ServerEnv: active blocks cached", blocks_cached);
1492                 g_profiler->avg("ServerEnv: active blocks scanned for ABMs", blocks_scanned);
1493                 g_profiler->avg("ServerEnv: ABMs run", abms_run);
1494
1495                 timer.stop(true);
1496         }
1497
1498         /*
1499                 Step script environment (run global on_step())
1500         */
1501         m_script->environment_Step(dtime);
1502
1503         m_script->stepAsync();
1504
1505         /*
1506                 Step active objects
1507         */
1508         {
1509                 ScopeProfiler sp(g_profiler, "ServerEnv: Run SAO::step()", SPT_AVG);
1510
1511                 // This helps the objects to send data at the same time
1512                 bool send_recommended = false;
1513                 m_send_recommended_timer += dtime;
1514                 if (m_send_recommended_timer > getSendRecommendedInterval()) {
1515                         m_send_recommended_timer -= getSendRecommendedInterval();
1516                         send_recommended = true;
1517                 }
1518
1519                 u32 object_count = 0;
1520
1521                 auto cb_state = [&] (ServerActiveObject *obj) {
1522                         if (obj->isGone())
1523                                 return;
1524                         object_count++;
1525
1526                         // Step object
1527                         obj->step(dtime, send_recommended);
1528                         // Read messages from object
1529                         obj->dumpAOMessagesToQueue(m_active_object_messages);
1530                 };
1531                 m_ao_manager.step(dtime, cb_state);
1532
1533                 m_active_object_gauge->set(object_count);
1534         }
1535
1536         /*
1537                 Manage active objects
1538         */
1539         if (m_object_management_interval.step(dtime, 0.5)) {
1540                 removeRemovedObjects();
1541         }
1542
1543         /*
1544                 Manage particle spawner expiration
1545         */
1546         if (m_particle_management_interval.step(dtime, 1.0)) {
1547                 for (std::unordered_map<u32, float>::iterator i = m_particle_spawners.begin();
1548                         i != m_particle_spawners.end(); ) {
1549                         //non expiring spawners
1550                         if (i->second == PARTICLE_SPAWNER_NO_EXPIRY) {
1551                                 ++i;
1552                                 continue;
1553                         }
1554
1555                         i->second -= 1.0f;
1556                         if (i->second <= 0.f)
1557                                 m_particle_spawners.erase(i++);
1558                         else
1559                                 ++i;
1560                 }
1561         }
1562
1563         // Send outdated player inventories
1564         for (RemotePlayer *player : m_players) {
1565                 if (player->getPeerId() == PEER_ID_INEXISTENT)
1566                         continue;
1567
1568                 PlayerSAO *sao = player->getPlayerSAO();
1569                 if (sao && player->inventory.checkModified())
1570                         m_server->SendInventory(sao, true);
1571         }
1572
1573         // Send outdated detached inventories
1574         m_server->sendDetachedInventories(PEER_ID_INEXISTENT, true);
1575
1576         const auto end_time = porting::getTimeUs();
1577         m_step_time_counter->increment(end_time - start_time);
1578 }
1579
1580 ServerEnvironment::BlockStatus ServerEnvironment::getBlockStatus(v3s16 blockpos)
1581 {
1582         if (m_active_blocks.contains(blockpos))
1583                 return BS_ACTIVE;
1584
1585         const MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1586         if (block && !block->isDummy())
1587                 return BS_LOADED;
1588
1589         if (m_map->isBlockInQueue(blockpos))
1590                 return BS_EMERGING;
1591
1592         return BS_UNKNOWN;
1593 }
1594
1595 u32 ServerEnvironment::addParticleSpawner(float exptime)
1596 {
1597         // Timers with lifetime 0 do not expire
1598         float time = exptime > 0.f ? exptime : PARTICLE_SPAWNER_NO_EXPIRY;
1599
1600         u32 id = 0;
1601         for (;;) { // look for unused particlespawner id
1602                 id++;
1603                 std::unordered_map<u32, float>::iterator f = m_particle_spawners.find(id);
1604                 if (f == m_particle_spawners.end()) {
1605                         m_particle_spawners[id] = time;
1606                         break;
1607                 }
1608         }
1609         return id;
1610 }
1611
1612 u32 ServerEnvironment::addParticleSpawner(float exptime, u16 attached_id)
1613 {
1614         u32 id = addParticleSpawner(exptime);
1615         m_particle_spawner_attachments[id] = attached_id;
1616         if (ServerActiveObject *obj = getActiveObject(attached_id)) {
1617                 obj->attachParticleSpawner(id);
1618         }
1619         return id;
1620 }
1621
1622 void ServerEnvironment::deleteParticleSpawner(u32 id, bool remove_from_object)
1623 {
1624         m_particle_spawners.erase(id);
1625         const auto &it = m_particle_spawner_attachments.find(id);
1626         if (it != m_particle_spawner_attachments.end()) {
1627                 u16 obj_id = it->second;
1628                 ServerActiveObject *sao = getActiveObject(obj_id);
1629                 if (sao != NULL && remove_from_object) {
1630                         sao->detachParticleSpawner(id);
1631                 }
1632                 m_particle_spawner_attachments.erase(id);
1633         }
1634 }
1635
1636 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1637 {
1638         assert(object); // Pre-condition
1639         m_added_objects++;
1640         u16 id = addActiveObjectRaw(object, true, 0);
1641         return id;
1642 }
1643
1644 /*
1645         Finds out what new objects have been added to
1646         inside a radius around a position
1647 */
1648 void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
1649         s16 player_radius,
1650         std::set<u16> &current_objects,
1651         std::queue<u16> &added_objects)
1652 {
1653         f32 radius_f = radius * BS;
1654         f32 player_radius_f = player_radius * BS;
1655
1656         if (player_radius_f < 0.0f)
1657                 player_radius_f = 0.0f;
1658
1659         m_ao_manager.getAddedActiveObjectsAroundPos(playersao->getBasePosition(), radius_f,
1660                 player_radius_f, current_objects, added_objects);
1661 }
1662
1663 /*
1664         Finds out what objects have been removed from
1665         inside a radius around a position
1666 */
1667 void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius,
1668         s16 player_radius,
1669         std::set<u16> &current_objects,
1670         std::queue<u16> &removed_objects)
1671 {
1672         f32 radius_f = radius * BS;
1673         f32 player_radius_f = player_radius * BS;
1674
1675         if (player_radius_f < 0)
1676                 player_radius_f = 0;
1677         /*
1678                 Go through current_objects; object is removed if:
1679                 - object is not found in m_active_objects (this is actually an
1680                   error condition; objects should be removed only after all clients
1681                   have been informed about removal), or
1682                 - object is to be removed or deactivated, or
1683                 - object is too far away
1684         */
1685         for (u16 id : current_objects) {
1686                 ServerActiveObject *object = getActiveObject(id);
1687
1688                 if (object == NULL) {
1689                         infostream << "ServerEnvironment::getRemovedActiveObjects():"
1690                                 << " object in current_objects is NULL" << std::endl;
1691                         removed_objects.push(id);
1692                         continue;
1693                 }
1694
1695                 if (object->isGone()) {
1696                         removed_objects.push(id);
1697                         continue;
1698                 }
1699
1700                 f32 distance_f = object->getBasePosition().getDistanceFrom(playersao->getBasePosition());
1701                 if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
1702                         if (distance_f <= player_radius_f || player_radius_f == 0)
1703                                 continue;
1704                 } else if (distance_f <= radius_f)
1705                         continue;
1706
1707                 // Object is no longer visible
1708                 removed_objects.push(id);
1709         }
1710 }
1711
1712 void ServerEnvironment::setStaticForActiveObjectsInBlock(
1713         v3s16 blockpos, bool static_exists, v3s16 static_block)
1714 {
1715         MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1716         if (!block)
1717                 return;
1718
1719         for (auto &so_it : block->m_static_objects.m_active) {
1720                 // Get the ServerActiveObject counterpart to this StaticObject
1721                 ServerActiveObject *sao = m_ao_manager.getActiveObject(so_it.first);
1722                 if (!sao) {
1723                         // If this ever happens, there must be some kind of nasty bug.
1724                         errorstream << "ServerEnvironment::setStaticForObjectsInBlock(): "
1725                                 "Object from MapBlock::m_static_objects::m_active not found "
1726                                 "in m_active_objects";
1727                         continue;
1728                 }
1729
1730                 sao->m_static_exists = static_exists;
1731                 sao->m_static_block  = static_block;
1732         }
1733 }
1734
1735 bool ServerEnvironment::getActiveObjectMessage(ActiveObjectMessage *dest)
1736 {
1737         if(m_active_object_messages.empty())
1738                 return false;
1739
1740         *dest = std::move(m_active_object_messages.front());
1741         m_active_object_messages.pop();
1742         return true;
1743 }
1744
1745 void ServerEnvironment::getSelectedActiveObjects(
1746         const core::line3d<f32> &shootline_on_map,
1747         std::vector<PointedThing> &objects)
1748 {
1749         std::vector<ServerActiveObject *> objs;
1750         getObjectsInsideRadius(objs, shootline_on_map.start,
1751                 shootline_on_map.getLength() + 10.0f, nullptr);
1752         const v3f line_vector = shootline_on_map.getVector();
1753
1754         for (auto obj : objs) {
1755                 if (obj->isGone())
1756                         continue;
1757                 aabb3f selection_box;
1758                 if (!obj->getSelectionBox(&selection_box))
1759                         continue;
1760
1761                 v3f pos = obj->getBasePosition();
1762
1763                 aabb3f offsetted_box(selection_box.MinEdge + pos,
1764                         selection_box.MaxEdge + pos);
1765
1766                 v3f current_intersection;
1767                 v3s16 current_normal;
1768                 if (boxLineCollision(offsetted_box, shootline_on_map.start, line_vector,
1769                                 &current_intersection, &current_normal)) {
1770                         objects.emplace_back(
1771                                 (s16) obj->getId(), current_intersection, current_normal,
1772                                 (current_intersection - shootline_on_map.start).getLengthSQ());
1773                 }
1774         }
1775 }
1776
1777 /*
1778         ************ Private methods *************
1779 */
1780
1781 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1782         bool set_changed, u32 dtime_s)
1783 {
1784         if (!m_ao_manager.registerObject(object)) {
1785                 return 0;
1786         }
1787
1788         // Register reference in scripting api (must be done before post-init)
1789         m_script->addObjectReference(object);
1790         // Post-initialize object
1791         object->addedToEnvironment(dtime_s);
1792
1793         // Add static data to block
1794         if (object->isStaticAllowed()) {
1795                 // Add static object to active static list of the block
1796                 v3f objectpos = object->getBasePosition();
1797                 StaticObject s_obj(object, objectpos);
1798                 // Add to the block where the object is located in
1799                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1800                 MapBlock *block = m_map->emergeBlock(blockpos);
1801                 if(block){
1802                         block->m_static_objects.m_active[object->getId()] = s_obj;
1803                         object->m_static_exists = true;
1804                         object->m_static_block = blockpos;
1805
1806                         if(set_changed)
1807                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1808                                         MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
1809                 } else {
1810                         v3s16 p = floatToInt(objectpos, BS);
1811                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1812                                 <<"could not emerge block for storing id="<<object->getId()
1813                                 <<" statically (pos="<<PP(p)<<")"<<std::endl;
1814                 }
1815         }
1816
1817         return object->getId();
1818 }
1819
1820 /*
1821         Remove objects that satisfy (isGone() && m_known_by_count==0)
1822 */
1823 void ServerEnvironment::removeRemovedObjects()
1824 {
1825         ScopeProfiler sp(g_profiler, "ServerEnvironment::removeRemovedObjects()", SPT_AVG);
1826
1827         auto clear_cb = [this] (ServerActiveObject *obj, u16 id) {
1828                 // This shouldn't happen but check it
1829                 if (!obj) {
1830                         errorstream << "ServerEnvironment::removeRemovedObjects(): "
1831                                         << "NULL object found. id=" << id << std::endl;
1832                         return true;
1833                 }
1834
1835                 /*
1836                         We will handle objects marked for removal or deactivation
1837                 */
1838                 if (!obj->isGone())
1839                         return false;
1840
1841                 /*
1842                         Delete static data from block if removed
1843                 */
1844                 if (obj->isPendingRemoval())
1845                         deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
1846
1847                 // If still known by clients, don't actually remove. On some future
1848                 // invocation this will be 0, which is when removal will continue.
1849                 if(obj->m_known_by_count > 0)
1850                         return false;
1851
1852                 /*
1853                         Move static data from active to stored if deactivated
1854                 */
1855                 if (!obj->isPendingRemoval() && obj->m_static_exists) {
1856                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1857                         if (block) {
1858                                 const auto i = block->m_static_objects.m_active.find(id);
1859                                 if (i != block->m_static_objects.m_active.end()) {
1860                                         block->m_static_objects.m_stored.push_back(i->second);
1861                                         block->m_static_objects.m_active.erase(id);
1862                                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1863                                                 MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
1864                                 } else {
1865                                         warningstream << "ServerEnvironment::removeRemovedObjects(): "
1866                                                         << "id=" << id << " m_static_exists=true but "
1867                                                         << "static data doesn't actually exist in "
1868                                                         << PP(obj->m_static_block) << std::endl;
1869                                 }
1870                         } else {
1871                                 infostream << "Failed to emerge block from which an object to "
1872                                                 << "be deactivated was loaded from. id=" << id << std::endl;
1873                         }
1874                 }
1875
1876                 // Tell the object about removal
1877                 obj->removingFromEnvironment();
1878                 // Deregister in scripting api
1879                 m_script->removeObjectReference(obj);
1880
1881                 // Delete
1882                 if (obj->environmentDeletes())
1883                         delete obj;
1884
1885                 return true;
1886         };
1887
1888         m_ao_manager.clear(clear_cb);
1889 }
1890
1891 static void print_hexdump(std::ostream &o, const std::string &data)
1892 {
1893         const int linelength = 16;
1894         for(int l=0; ; l++){
1895                 int i0 = linelength * l;
1896                 bool at_end = false;
1897                 int thislinelength = linelength;
1898                 if(i0 + thislinelength > (int)data.size()){
1899                         thislinelength = data.size() - i0;
1900                         at_end = true;
1901                 }
1902                 for(int di=0; di<linelength; di++){
1903                         int i = i0 + di;
1904                         char buf[4];
1905                         if(di<thislinelength)
1906                                 porting::mt_snprintf(buf, sizeof(buf), "%.2x ", data[i]);
1907                         else
1908                                 porting::mt_snprintf(buf, sizeof(buf), "   ");
1909                         o<<buf;
1910                 }
1911                 o<<" ";
1912                 for(int di=0; di<thislinelength; di++){
1913                         int i = i0 + di;
1914                         if(data[i] >= 32)
1915                                 o<<data[i];
1916                         else
1917                                 o<<".";
1918                 }
1919                 o<<std::endl;
1920                 if(at_end)
1921                         break;
1922         }
1923 }
1924
1925 ServerActiveObject* ServerEnvironment::createSAO(ActiveObjectType type, v3f pos,
1926                 const std::string &data)
1927 {
1928         switch (type) {
1929                 case ACTIVEOBJECT_TYPE_LUAENTITY:
1930                         return new LuaEntitySAO(this, pos, data);
1931                 default:
1932                         warningstream << "ServerActiveObject: No factory for type=" << type << std::endl;
1933         }
1934         return nullptr;
1935 }
1936
1937 /*
1938         Convert stored objects from blocks near the players to active.
1939 */
1940 void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
1941 {
1942         if(block == NULL)
1943                 return;
1944
1945         // Ignore if no stored objects (to not set changed flag)
1946         if(block->m_static_objects.m_stored.empty())
1947                 return;
1948
1949         verbosestream<<"ServerEnvironment::activateObjects(): "
1950                 <<"activating objects of block "<<PP(block->getPos())
1951                 <<" ("<<block->m_static_objects.m_stored.size()
1952                 <<" objects)"<<std::endl;
1953         bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
1954         if (large_amount) {
1955                 errorstream<<"suspiciously large amount of objects detected: "
1956                         <<block->m_static_objects.m_stored.size()<<" in "
1957                         <<PP(block->getPos())
1958                         <<"; removing all of them."<<std::endl;
1959                 // Clear stored list
1960                 block->m_static_objects.m_stored.clear();
1961                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1962                         MOD_REASON_TOO_MANY_OBJECTS);
1963                 return;
1964         }
1965
1966         // Activate stored objects
1967         std::vector<StaticObject> new_stored;
1968         for (const StaticObject &s_obj : block->m_static_objects.m_stored) {
1969                 // Create an active object from the data
1970                 ServerActiveObject *obj = createSAO((ActiveObjectType) s_obj.type, s_obj.pos,
1971                         s_obj.data);
1972                 // If couldn't create object, store static data back.
1973                 if (!obj) {
1974                         errorstream<<"ServerEnvironment::activateObjects(): "
1975                                 <<"failed to create active object from static object "
1976                                 <<"in block "<<PP(s_obj.pos/BS)
1977                                 <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
1978                         print_hexdump(verbosestream, s_obj.data);
1979
1980                         new_stored.push_back(s_obj);
1981                         continue;
1982                 }
1983                 verbosestream<<"ServerEnvironment::activateObjects(): "
1984                         <<"activated static object pos="<<PP(s_obj.pos/BS)
1985                         <<" type="<<(int)s_obj.type<<std::endl;
1986                 // This will also add the object to the active static list
1987                 addActiveObjectRaw(obj, false, dtime_s);
1988         }
1989
1990         // Clear stored list
1991         block->m_static_objects.m_stored.clear();
1992         // Add leftover failed stuff to stored list
1993         for (const StaticObject &s_obj : new_stored) {
1994                 block->m_static_objects.m_stored.push_back(s_obj);
1995         }
1996
1997         /*
1998                 Note: Block hasn't really been modified here.
1999                 The objects have just been activated and moved from the stored
2000                 static list to the active static list.
2001                 As such, the block is essentially the same.
2002                 Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
2003                 Otherwise there would be a huge amount of unnecessary I/O.
2004         */
2005 }
2006
2007 /*
2008         Convert objects that are not standing inside active blocks to static.
2009
2010         If m_known_by_count != 0, active object is not deleted, but static
2011         data is still updated.
2012
2013         If force_delete is set, active object is deleted nevertheless. It
2014         shall only be set so in the destructor of the environment.
2015
2016         If block wasn't generated (not in memory or on disk),
2017 */
2018 void ServerEnvironment::deactivateFarObjects(bool _force_delete)
2019 {
2020         auto cb_deactivate = [this, _force_delete] (ServerActiveObject *obj, u16 id) {
2021                 // force_delete might be overriden per object
2022                 bool force_delete = _force_delete;
2023
2024                 // Do not deactivate if disallowed
2025                 if (!force_delete && !obj->shouldUnload())
2026                         return false;
2027
2028                 // removeRemovedObjects() is responsible for these
2029                 if (!force_delete && obj->isGone())
2030                         return false;
2031
2032                 const v3f &objectpos = obj->getBasePosition();
2033
2034                 // The block in which the object resides in
2035                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
2036
2037                 // If object's static data is stored in a deactivated block and object
2038                 // is actually located in an active block, re-save to the block in
2039                 // which the object is actually located in.
2040                 if (!force_delete && obj->m_static_exists &&
2041                    !m_active_blocks.contains(obj->m_static_block) &&
2042                    m_active_blocks.contains(blockpos_o)) {
2043
2044                         // Delete from block where object was located
2045                         deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
2046
2047                         StaticObject s_obj(obj, objectpos);
2048                         // Save to block where object is located
2049                         saveStaticToBlock(blockpos_o, id, obj, s_obj, MOD_REASON_STATIC_DATA_ADDED);
2050
2051                         return false;
2052                 }
2053
2054                 // If block is still active, don't remove
2055                 bool still_active = obj->isStaticAllowed() ?
2056                         m_active_blocks.contains(blockpos_o) :
2057                         getMap().getBlockNoCreateNoEx(blockpos_o) != nullptr;
2058                 if (!force_delete && still_active)
2059                         return false;
2060
2061                 verbosestream << "ServerEnvironment::deactivateFarObjects(): "
2062                                           << "deactivating object id=" << id << " on inactive block "
2063                                           << PP(blockpos_o) << std::endl;
2064
2065                 // If known by some client, don't immediately delete.
2066                 bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
2067
2068                 /*
2069                         Update the static data
2070                 */
2071                 if (obj->isStaticAllowed()) {
2072                         // Create new static object
2073                         StaticObject s_obj(obj, objectpos);
2074
2075                         bool stays_in_same_block = false;
2076                         bool data_changed = true;
2077
2078                         // Check if static data has changed considerably
2079                         if (obj->m_static_exists) {
2080                                 if (obj->m_static_block == blockpos_o)
2081                                         stays_in_same_block = true;
2082
2083                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
2084
2085                                 if (block) {
2086                                         const auto n = block->m_static_objects.m_active.find(id);
2087                                         if (n != block->m_static_objects.m_active.end()) {
2088                                                 StaticObject static_old = n->second;
2089
2090                                                 float save_movem = obj->getMinimumSavedMovement();
2091
2092                                                 if (static_old.data == s_obj.data &&
2093                                                         (static_old.pos - objectpos).getLength() < save_movem)
2094                                                         data_changed = false;
2095                                         } else {
2096                                                 warningstream << "ServerEnvironment::deactivateFarObjects(): "
2097                                                                 << "id=" << id << " m_static_exists=true but "
2098                                                                 << "static data doesn't actually exist in "
2099                                                                 << PP(obj->m_static_block) << std::endl;
2100                                         }
2101                                 }
2102                         }
2103
2104                         /*
2105                                 While changes are always saved, blocks are only marked as modified
2106                                 if the object has moved or different staticdata. (see above)
2107                         */
2108                         bool shall_be_written = (!stays_in_same_block || data_changed);
2109                         u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN;
2110
2111                         // Delete old static object
2112                         deleteStaticFromBlock(obj, id, reason, false);
2113
2114                         // Add to the block where the object is located in
2115                         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
2116                         u16 store_id = pending_delete ? id : 0;
2117                         if (!saveStaticToBlock(blockpos, store_id, obj, s_obj, reason))
2118                                 force_delete = true;
2119                 }
2120
2121                 // Regardless of what happens to the object at this point, deactivate it first.
2122                 // This ensures that LuaEntity on_deactivate is always called.
2123                 obj->markForDeactivation();
2124
2125                 /*
2126                         If known by some client, set pending deactivation.
2127                         Otherwise delete it immediately.
2128                 */
2129                 if (pending_delete && !force_delete) {
2130                         verbosestream << "ServerEnvironment::deactivateFarObjects(): "
2131                                                   << "object id=" << id << " is known by clients"
2132                                                   << "; not deleting yet" << std::endl;
2133
2134                         return false;
2135                 }
2136
2137                 verbosestream << "ServerEnvironment::deactivateFarObjects(): "
2138                                           << "object id=" << id << " is not known by clients"
2139                                           << "; deleting" << std::endl;
2140
2141                 // Tell the object about removal
2142                 obj->removingFromEnvironment();
2143                 // Deregister in scripting api
2144                 m_script->removeObjectReference(obj);
2145
2146                 // Delete active object
2147                 if (obj->environmentDeletes())
2148                         delete obj;
2149
2150                 return true;
2151         };
2152
2153         m_ao_manager.clear(cb_deactivate);
2154 }
2155
2156 void ServerEnvironment::deleteStaticFromBlock(
2157                 ServerActiveObject *obj, u16 id, u32 mod_reason, bool no_emerge)
2158 {
2159         if (!obj->m_static_exists)
2160                 return;
2161
2162         MapBlock *block;
2163         if (no_emerge)
2164                 block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
2165         else
2166                 block = m_map->emergeBlock(obj->m_static_block, false);
2167         if (!block) {
2168                 if (!no_emerge)
2169                         errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
2170                                         << " when deleting static data of object from it. id=" << id << std::endl;
2171                 return;
2172         }
2173
2174         block->m_static_objects.remove(id);
2175         if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
2176                 block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
2177
2178         obj->m_static_exists = false;
2179 }
2180
2181 bool ServerEnvironment::saveStaticToBlock(
2182                 v3s16 blockpos, u16 store_id,
2183                 ServerActiveObject *obj, const StaticObject &s_obj,
2184                 u32 mod_reason)
2185 {
2186         MapBlock *block = nullptr;
2187         try {
2188                 block = m_map->emergeBlock(blockpos);
2189         } catch (InvalidPositionException &e) {
2190                 // Handled via NULL pointer
2191                 // NOTE: emergeBlock's failure is usually determined by it
2192                 //       actually returning NULL
2193         }
2194
2195         if (!block) {
2196                 errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
2197                                 << " when saving static data of object to it. id=" << store_id << std::endl;
2198                 return false;
2199         }
2200         if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
2201                 warningstream << "ServerEnv: Trying to store id = " << store_id
2202                                 << " statically but block " << PP(blockpos)
2203                                 << " already contains "
2204                                 << block->m_static_objects.m_stored.size()
2205                                 << " objects." << std::endl;
2206                 return false;
2207         }
2208
2209         block->m_static_objects.insert(store_id, s_obj);
2210         if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
2211                 block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
2212
2213         obj->m_static_exists = true;
2214         obj->m_static_block = blockpos;
2215
2216         return true;
2217 }
2218
2219 PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
2220                 const std::string &savedir, const Settings &conf)
2221 {
2222
2223         if (name == "sqlite3")
2224                 return new PlayerDatabaseSQLite3(savedir);
2225
2226         if (name == "dummy")
2227                 return new Database_Dummy();
2228
2229 #if USE_POSTGRESQL
2230         if (name == "postgresql") {
2231                 std::string connect_string;
2232                 conf.getNoEx("pgsql_player_connection", connect_string);
2233                 return new PlayerDatabasePostgreSQL(connect_string);
2234         }
2235 #endif
2236
2237 #if USE_LEVELDB
2238         if (name == "leveldb")
2239                 return new PlayerDatabaseLevelDB(savedir);
2240 #endif
2241
2242         if (name == "files")
2243                 return new PlayerDatabaseFiles(savedir + DIR_DELIM + "players");
2244
2245         throw BaseException(std::string("Database backend ") + name + " not supported.");
2246 }
2247
2248 bool ServerEnvironment::migratePlayersDatabase(const GameParams &game_params,
2249                 const Settings &cmd_args)
2250 {
2251         std::string migrate_to = cmd_args.get("migrate-players");
2252         Settings world_mt;
2253         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
2254         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
2255                 errorstream << "Cannot read world.mt!" << std::endl;
2256                 return false;
2257         }
2258
2259         if (!world_mt.exists("player_backend")) {
2260                 errorstream << "Please specify your current backend in world.mt:"
2261                         << std::endl
2262                         << "    player_backend = {files|sqlite3|leveldb|postgresql}"
2263                         << std::endl;
2264                 return false;
2265         }
2266
2267         std::string backend = world_mt.get("player_backend");
2268         if (backend == migrate_to) {
2269                 errorstream << "Cannot migrate: new backend is same"
2270                         << " as the old one" << std::endl;
2271                 return false;
2272         }
2273
2274         const std::string players_backup_path = game_params.world_path + DIR_DELIM
2275                 + "players.bak";
2276
2277         if (backend == "files") {
2278                 // Create backup directory
2279                 fs::CreateDir(players_backup_path);
2280         }
2281
2282         try {
2283                 PlayerDatabase *srcdb = ServerEnvironment::openPlayerDatabase(backend,
2284                         game_params.world_path, world_mt);
2285                 PlayerDatabase *dstdb = ServerEnvironment::openPlayerDatabase(migrate_to,
2286                         game_params.world_path, world_mt);
2287
2288                 std::vector<std::string> player_list;
2289                 srcdb->listPlayers(player_list);
2290                 for (std::vector<std::string>::const_iterator it = player_list.begin();
2291                         it != player_list.end(); ++it) {
2292                         actionstream << "Migrating player " << it->c_str() << std::endl;
2293                         RemotePlayer player(it->c_str(), NULL);
2294                         PlayerSAO playerSAO(NULL, &player, 15000, false);
2295
2296                         srcdb->loadPlayer(&player, &playerSAO);
2297
2298                         playerSAO.finalize(&player, std::set<std::string>());
2299                         player.setPlayerSAO(&playerSAO);
2300
2301                         dstdb->savePlayer(&player);
2302
2303                         // For files source, move player files to backup dir
2304                         if (backend == "files") {
2305                                 fs::Rename(
2306                                         game_params.world_path + DIR_DELIM + "players" + DIR_DELIM + (*it),
2307                                         players_backup_path + DIR_DELIM + (*it));
2308                         }
2309                 }
2310
2311                 actionstream << "Successfully migrated " << player_list.size() << " players"
2312                         << std::endl;
2313                 world_mt.set("player_backend", migrate_to);
2314                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
2315                         errorstream << "Failed to update world.mt!" << std::endl;
2316                 else
2317                         actionstream << "world.mt updated" << std::endl;
2318
2319                 // When migration is finished from file backend, remove players directory if empty
2320                 if (backend == "files") {
2321                         fs::DeleteSingleFileOrEmptyDirectory(game_params.world_path + DIR_DELIM
2322                                 + "players");
2323                 }
2324
2325                 delete srcdb;
2326                 delete dstdb;
2327
2328         } catch (BaseException &e) {
2329                 errorstream << "An error occurred during migration: " << e.what() << std::endl;
2330                 return false;
2331         }
2332         return true;
2333 }
2334
2335 AuthDatabase *ServerEnvironment::openAuthDatabase(
2336                 const std::string &name, const std::string &savedir, const Settings &conf)
2337 {
2338         if (name == "sqlite3")
2339                 return new AuthDatabaseSQLite3(savedir);
2340
2341 #if USE_POSTGRESQL
2342         if (name == "postgresql") {
2343                 std::string connect_string;
2344                 conf.getNoEx("pgsql_auth_connection", connect_string);
2345                 return new AuthDatabasePostgreSQL(connect_string);
2346         }
2347 #endif
2348
2349         if (name == "files")
2350                 return new AuthDatabaseFiles(savedir);
2351
2352 #if USE_LEVELDB
2353         if (name == "leveldb")
2354                 return new AuthDatabaseLevelDB(savedir);
2355 #endif
2356
2357         throw BaseException(std::string("Database backend ") + name + " not supported.");
2358 }
2359
2360 bool ServerEnvironment::migrateAuthDatabase(
2361                 const GameParams &game_params, const Settings &cmd_args)
2362 {
2363         std::string migrate_to = cmd_args.get("migrate-auth");
2364         Settings world_mt;
2365         std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
2366         if (!world_mt.readConfigFile(world_mt_path.c_str())) {
2367                 errorstream << "Cannot read world.mt!" << std::endl;
2368                 return false;
2369         }
2370
2371         std::string backend = "files";
2372         if (world_mt.exists("auth_backend"))
2373                 backend = world_mt.get("auth_backend");
2374         else
2375                 warningstream << "No auth_backend found in world.mt, "
2376                                 "assuming \"files\"." << std::endl;
2377
2378         if (backend == migrate_to) {
2379                 errorstream << "Cannot migrate: new backend is same"
2380                                 << " as the old one" << std::endl;
2381                 return false;
2382         }
2383
2384         try {
2385                 const std::unique_ptr<AuthDatabase> srcdb(ServerEnvironment::openAuthDatabase(
2386                                 backend, game_params.world_path, world_mt));
2387                 const std::unique_ptr<AuthDatabase> dstdb(ServerEnvironment::openAuthDatabase(
2388                                 migrate_to, game_params.world_path, world_mt));
2389
2390                 std::vector<std::string> names_list;
2391                 srcdb->listNames(names_list);
2392                 for (const std::string &name : names_list) {
2393                         actionstream << "Migrating auth entry for " << name << std::endl;
2394                         bool success;
2395                         AuthEntry authEntry;
2396                         success = srcdb->getAuth(name, authEntry);
2397                         success = success && dstdb->createAuth(authEntry);
2398                         if (!success)
2399                                 errorstream << "Failed to migrate " << name << std::endl;
2400                 }
2401
2402                 actionstream << "Successfully migrated " << names_list.size()
2403                                 << " auth entries" << std::endl;
2404                 world_mt.set("auth_backend", migrate_to);
2405                 if (!world_mt.updateConfigFile(world_mt_path.c_str()))
2406                         errorstream << "Failed to update world.mt!" << std::endl;
2407                 else
2408                         actionstream << "world.mt updated" << std::endl;
2409
2410                 if (backend == "files") {
2411                         // special-case files migration:
2412                         // move auth.txt to auth.txt.bak if possible
2413                         std::string auth_txt_path =
2414                                         game_params.world_path + DIR_DELIM + "auth.txt";
2415                         std::string auth_bak_path = auth_txt_path + ".bak";
2416                         if (!fs::PathExists(auth_bak_path))
2417                                 if (fs::Rename(auth_txt_path, auth_bak_path))
2418                                         actionstream << "Renamed auth.txt to auth.txt.bak"
2419                                                         << std::endl;
2420                                 else
2421                                         errorstream << "Could not rename auth.txt to "
2422                                                         "auth.txt.bak" << std::endl;
2423                         else
2424                                 warningstream << "auth.txt.bak already exists, auth.txt "
2425                                                 "not renamed" << std::endl;
2426                 }
2427
2428         } catch (BaseException &e) {
2429                 errorstream << "An error occurred during migration: " << e.what()
2430                             << std::endl;
2431                 return false;
2432         }
2433         return true;
2434 }