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