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