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