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