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