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