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