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