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