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