]> git.lizzy.rs Git - minetest.git/blob - src/environment.cpp
9f7207b8d8533fa5c90d3466b36dad26c1912b9c
[minetest.git] / src / environment.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 "environment.h"
21 #include "filesys.h"
22 #include "porting.h"
23 #include "collision.h"
24 #include "content_mapnode.h"
25 #include "mapblock.h"
26 #include "serverobject.h"
27 #include "content_sao.h"
28 #include "settings.h"
29 #include "log.h"
30 #include "profiler.h"
31 #include "scripting_game.h"
32 #include "nodedef.h"
33 #include "nodemetadata.h"
34 #include "main.h" // For g_settings, g_profiler
35 #include "gamedef.h"
36 #ifndef SERVER
37 #include "clientmap.h"
38 #include "localplayer.h"
39 #include "event.h"
40 #endif
41 #include "daynightratio.h"
42 #include "map.h"
43 #include "emerge.h"
44 #include "util/serialize.h"
45
46 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
47
48 Environment::Environment():
49         m_time_of_day(9000),
50         m_time_of_day_f(9000./24000),
51         m_time_of_day_speed(0),
52         m_time_counter(0),
53         m_enable_day_night_ratio_override(false),
54         m_day_night_ratio_override(0.0f)
55 {
56 }
57
58 Environment::~Environment()
59 {
60         // Deallocate players
61         for(std::list<Player*>::iterator i = m_players.begin();
62                         i != m_players.end(); ++i)
63         {
64                 delete (*i);
65         }
66 }
67
68 void Environment::addPlayer(Player *player)
69 {
70         DSTACK(__FUNCTION_NAME);
71         /*
72                 Check that peer_ids are unique.
73                 Also check that names are unique.
74                 Exception: there can be multiple players with peer_id=0
75         */
76         // If peer id is non-zero, it has to be unique.
77         if(player->peer_id != 0)
78                 assert(getPlayer(player->peer_id) == NULL);
79         // Name has to be unique.
80         assert(getPlayer(player->getName()) == NULL);
81         // Add.
82         m_players.push_back(player);
83 }
84
85 void Environment::removePlayer(u16 peer_id)
86 {
87         DSTACK(__FUNCTION_NAME);
88 re_search:
89         for(std::list<Player*>::iterator i = m_players.begin();
90                         i != m_players.end(); ++i)
91         {
92                 Player *player = *i;
93                 if(player->peer_id != peer_id)
94                         continue;
95                 
96                 delete player;
97                 m_players.erase(i);
98                 // See if there is an another one
99                 // (shouldn't be, but just to be sure)
100                 goto re_search;
101         }
102 }
103
104 Player * Environment::getPlayer(u16 peer_id)
105 {
106         for(std::list<Player*>::iterator i = m_players.begin();
107                         i != m_players.end(); ++i)
108         {
109                 Player *player = *i;
110                 if(player->peer_id == peer_id)
111                         return player;
112         }
113         return NULL;
114 }
115
116 Player * Environment::getPlayer(const char *name)
117 {
118         for(std::list<Player*>::iterator i = m_players.begin();
119                         i != m_players.end(); ++i)
120         {
121                 Player *player = *i;
122                 if(strcmp(player->getName(), name) == 0)
123                         return player;
124         }
125         return NULL;
126 }
127
128 Player * Environment::getRandomConnectedPlayer()
129 {
130         std::list<Player*> connected_players = getPlayers(true);
131         u32 chosen_one = myrand() % connected_players.size();
132         u32 j = 0;
133         for(std::list<Player*>::iterator
134                         i = connected_players.begin();
135                         i != connected_players.end(); ++i)
136         {
137                 if(j == chosen_one)
138                 {
139                         Player *player = *i;
140                         return player;
141                 }
142                 j++;
143         }
144         return NULL;
145 }
146
147 Player * Environment::getNearestConnectedPlayer(v3f pos)
148 {
149         std::list<Player*> connected_players = getPlayers(true);
150         f32 nearest_d = 0;
151         Player *nearest_player = NULL;
152         for(std::list<Player*>::iterator
153                         i = connected_players.begin();
154                         i != connected_players.end(); ++i)
155         {
156                 Player *player = *i;
157                 f32 d = player->getPosition().getDistanceFrom(pos);
158                 if(d < nearest_d || nearest_player == NULL)
159                 {
160                         nearest_d = d;
161                         nearest_player = player;
162                 }
163         }
164         return nearest_player;
165 }
166
167 std::list<Player*> Environment::getPlayers()
168 {
169         return m_players;
170 }
171
172 std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
173 {
174         std::list<Player*> newlist;
175         for(std::list<Player*>::iterator
176                         i = m_players.begin();
177                         i != m_players.end(); ++i)
178         {
179                 Player *player = *i;
180                 
181                 if(ignore_disconnected)
182                 {
183                         // Ignore disconnected players
184                         if(player->peer_id == 0)
185                                 continue;
186                 }
187
188                 newlist.push_back(player);
189         }
190         return newlist;
191 }
192
193 u32 Environment::getDayNightRatio()
194 {
195         if(m_enable_day_night_ratio_override)
196                 return m_day_night_ratio_override;
197         bool smooth = g_settings->getBool("enable_shaders");
198         return time_to_daynight_ratio(m_time_of_day_f*24000, smooth);
199 }
200
201 void Environment::stepTimeOfDay(float dtime)
202 {
203         m_time_counter += dtime;
204         f32 speed = m_time_of_day_speed * 24000./(24.*3600);
205         u32 units = (u32)(m_time_counter*speed);
206         m_time_counter -= (f32)units / speed;
207         bool sync_f = false;
208         if(units > 0){
209                 // Sync at overflow
210                 if(m_time_of_day + units >= 24000)
211                         sync_f = true;
212                 m_time_of_day = (m_time_of_day + units) % 24000;
213                 if(sync_f)
214                         m_time_of_day_f = (float)m_time_of_day / 24000.0;
215         }
216         if(!sync_f){
217                 m_time_of_day_f += m_time_of_day_speed/24/3600*dtime;
218                 if(m_time_of_day_f > 1.0)
219                         m_time_of_day_f -= 1.0;
220                 if(m_time_of_day_f < 0.0)
221                         m_time_of_day_f += 1.0;
222         }
223 }
224
225 /*
226         ABMWithState
227 */
228
229 ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
230         abm(abm_),
231         timer(0)
232 {
233         // Initialize timer to random value to spread processing
234         float itv = abm->getTriggerInterval();
235         itv = MYMAX(0.001, itv); // No less than 1ms
236         int minval = MYMAX(-0.51*itv, -60); // Clamp to
237         int maxval = MYMIN(0.51*itv, 60);   // +-60 seconds
238         timer = myrand_range(minval, maxval);
239 }
240
241 /*
242         ActiveBlockList
243 */
244
245 void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
246 {
247         v3s16 p;
248         for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
249         for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
250         for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
251         {
252                 // Set in list
253                 list.insert(p);
254         }
255 }
256
257 void ActiveBlockList::update(std::list<v3s16> &active_positions,
258                 s16 radius,
259                 std::set<v3s16> &blocks_removed,
260                 std::set<v3s16> &blocks_added)
261 {
262         /*
263                 Create the new list
264         */
265         std::set<v3s16> newlist = m_forceloaded_list;
266         for(std::list<v3s16>::iterator i = active_positions.begin();
267                         i != active_positions.end(); ++i)
268         {
269                 fillRadiusBlock(*i, radius, newlist);
270         }
271
272         /*
273                 Find out which blocks on the old list are not on the new list
274         */
275         // Go through old list
276         for(std::set<v3s16>::iterator i = m_list.begin();
277                         i != m_list.end(); ++i)
278         {
279                 v3s16 p = *i;
280                 // If not on new list, it's been removed
281                 if(newlist.find(p) == newlist.end())
282                         blocks_removed.insert(p);
283         }
284
285         /*
286                 Find out which blocks on the new list are not on the old list
287         */
288         // Go through new list
289         for(std::set<v3s16>::iterator i = newlist.begin();
290                         i != newlist.end(); ++i)
291         {
292                 v3s16 p = *i;
293                 // If not on old list, it's been added
294                 if(m_list.find(p) == m_list.end())
295                         blocks_added.insert(p);
296         }
297
298         /*
299                 Update m_list
300         */
301         m_list.clear();
302         for(std::set<v3s16>::iterator i = newlist.begin();
303                         i != newlist.end(); ++i)
304         {
305                 v3s16 p = *i;
306                 m_list.insert(p);
307         }
308 }
309
310 /*
311         ServerEnvironment
312 */
313
314 ServerEnvironment::ServerEnvironment(ServerMap *map,
315                 GameScripting *scriptIface, IGameDef *gamedef):
316         m_map(map),
317         m_script(scriptIface),
318         m_gamedef(gamedef),
319         m_random_spawn_timer(3),
320         m_send_recommended_timer(0),
321         m_active_block_interval_overload_skip(0),
322         m_game_time(0),
323         m_game_time_fraction_counter(0),
324         m_recommended_send_interval(0.1),
325         m_max_lag_estimate(0.1)
326 {
327         m_use_weather = g_settings->getBool("weather");
328 }
329
330 ServerEnvironment::~ServerEnvironment()
331 {
332         // Clear active block list.
333         // This makes the next one delete all active objects.
334         m_active_blocks.clear();
335
336         // Convert all objects to static and delete the active objects
337         deactivateFarObjects(true);
338
339         // Drop/delete map
340         m_map->drop();
341
342         // Delete ActiveBlockModifiers
343         for(std::list<ABMWithState>::iterator
344                         i = m_abms.begin(); i != m_abms.end(); ++i){
345                 delete i->abm;
346         }
347 }
348
349 Map & ServerEnvironment::getMap()
350 {
351         return *m_map;
352 }
353
354 ServerMap & ServerEnvironment::getServerMap()
355 {
356         return *m_map;
357 }
358
359 bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16 *p)
360 {
361         float distance = pos1.getDistanceFrom(pos2);
362
363         //calculate normalized direction vector
364         v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
365                                                                 (pos2.Y - pos1.Y)/distance,
366                                                                 (pos2.Z - pos1.Z)/distance);
367
368         //find out if there's a node on path between pos1 and pos2
369         for (float i = 1; i < distance; i += stepsize) {
370                 v3s16 pos = floatToInt(v3f(normalized_vector.X * i,
371                                 normalized_vector.Y * i,
372                                 normalized_vector.Z * i) +pos1,BS);
373
374                 MapNode n = getMap().getNodeNoEx(pos);
375
376                 if(n.param0 != CONTENT_AIR) {
377                         if (p) {
378                                 *p = pos;
379                         }
380                         return false;
381                 }
382         }
383         return true;
384 }
385
386 void ServerEnvironment::serializePlayers(const std::string &savedir)
387 {
388         std::string players_path = savedir + "/players";
389         fs::CreateDir(players_path);
390
391         std::set<Player*> saved_players;
392
393         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
394         for(u32 i=0; i<player_files.size(); i++)
395         {
396                 if(player_files[i].dir || player_files[i].name[0] == '.')
397                         continue;
398                 
399                 // Full path to this file
400                 std::string path = players_path + "/" + player_files[i].name;
401
402                 //infostream<<"Checking player file "<<path<<std::endl;
403
404                 // Load player to see what is its name
405                 RemotePlayer testplayer(m_gamedef);
406                 {
407                         // Open file and deserialize
408                         std::ifstream is(path.c_str(), std::ios_base::binary);
409                         if(is.good() == false)
410                         {
411                                 infostream<<"Failed to read "<<path<<std::endl;
412                                 continue;
413                         }
414                         testplayer.deSerialize(is, player_files[i].name);
415                 }
416
417                 //infostream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
418                 
419                 // Search for the player
420                 std::string playername = testplayer.getName();
421                 Player *player = getPlayer(playername.c_str());
422                 if(player == NULL)
423                 {
424                         infostream<<"Didn't find matching player, ignoring file "<<path<<std::endl;
425                         continue;
426                 }
427
428                 //infostream<<"Found matching player, overwriting."<<std::endl;
429
430                 // OK, found. Save player there.
431                 if(player->checkModified())
432                 {
433                         // Open file and serialize
434                         std::ostringstream ss(std::ios_base::binary);
435                         player->serialize(ss);
436                         if(!fs::safeWriteToFile(path, ss.str()))
437                         {
438                                 infostream<<"Failed to write "<<path<<std::endl;
439                                 continue;
440                         }
441                         saved_players.insert(player);
442                 } else {
443                         saved_players.insert(player);
444                 }
445         }
446
447         for(std::list<Player*>::iterator i = m_players.begin();
448                         i != m_players.end(); ++i)
449         {
450                 Player *player = *i;
451                 if(saved_players.find(player) != saved_players.end())
452                 {
453                         /*infostream<<"Player "<<player->getName()
454                                         <<" was already saved."<<std::endl;*/
455                         continue;
456                 }
457                 std::string playername = player->getName();
458                 // Don't save unnamed player
459                 if(playername == "")
460                 {
461                         //infostream<<"Not saving unnamed player."<<std::endl;
462                         continue;
463                 }
464                 /*
465                         Find a sane filename
466                 */
467                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
468                         playername = "player";
469                 std::string path = players_path + "/" + playername;
470                 bool found = false;
471                 for(u32 i=0; i<1000; i++)
472                 {
473                         if(fs::PathExists(path) == false)
474                         {
475                                 found = true;
476                                 break;
477                         }
478                         path = players_path + "/" + playername + itos(i);
479                 }
480                 if(found == false)
481                 {
482                         infostream<<"Didn't find free file for player"<<std::endl;
483                         continue;
484                 }
485
486                 {
487                         /*infostream<<"Saving player "<<player->getName()<<" to "
488                                         <<path<<std::endl;*/
489                         // Open file and serialize
490                         std::ostringstream ss(std::ios_base::binary);
491                         player->serialize(ss);
492                         if(!fs::safeWriteToFile(path, ss.str()))
493                         {
494                                 infostream<<"Failed to write "<<path<<std::endl;
495                                 continue;
496                         }
497                         saved_players.insert(player);
498                 }
499         }
500
501         //infostream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
502 }
503
504 void ServerEnvironment::deSerializePlayers(const std::string &savedir)
505 {
506         std::string players_path = savedir + "/players";
507
508         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
509         for(u32 i=0; i<player_files.size(); i++)
510         {
511                 if(player_files[i].dir)
512                         continue;
513                 
514                 // Full path to this file
515                 std::string path = players_path + "/" + player_files[i].name;
516
517                 //infostream<<"Checking player file "<<path<<std::endl;
518
519                 // Load player to see what is its name
520                 RemotePlayer testplayer(m_gamedef);
521                 {
522                         // Open file and deserialize
523                         std::ifstream is(path.c_str(), std::ios_base::binary);
524                         if(is.good() == false)
525                         {
526                                 infostream<<"Failed to read "<<path<<std::endl;
527                                 continue;
528                         }
529                         testplayer.deSerialize(is, player_files[i].name);
530                 }
531
532                 if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS))
533                 {
534                         infostream<<"Not loading player with invalid name: "
535                                         <<testplayer.getName()<<std::endl;
536                 }
537
538                 /*infostream<<"Loaded test player with name "<<testplayer.getName()
539                                 <<std::endl;*/
540                 
541                 // Search for the player
542                 std::string playername = testplayer.getName();
543                 Player *player = getPlayer(playername.c_str());
544                 bool newplayer = false;
545                 if(player == NULL)
546                 {
547                         //infostream<<"Is a new player"<<std::endl;
548                         player = new RemotePlayer(m_gamedef);
549                         newplayer = true;
550                 }
551
552                 // Load player
553                 {
554                         verbosestream<<"Reading player "<<testplayer.getName()<<" from "
555                                         <<path<<std::endl;
556                         // Open file and deserialize
557                         std::ifstream is(path.c_str(), std::ios_base::binary);
558                         if(is.good() == false)
559                         {
560                                 infostream<<"Failed to read "<<path<<std::endl;
561                                 continue;
562                         }
563                         player->deSerialize(is, player_files[i].name);
564                 }
565
566                 if(newplayer)
567                 {
568                         addPlayer(player);
569                 }
570         }
571 }
572
573 void ServerEnvironment::saveMeta(const std::string &savedir)
574 {
575         std::string path = savedir + "/env_meta.txt";
576
577         // Open file and serialize
578         std::ostringstream ss(std::ios_base::binary);
579
580         Settings args;
581         args.setU64("game_time", m_game_time);
582         args.setU64("time_of_day", getTimeOfDay());
583         args.writeLines(ss);
584         ss<<"EnvArgsEnd\n";
585
586         if(!fs::safeWriteToFile(path, ss.str()))
587         {
588                 infostream<<"ServerEnvironment::saveMeta(): Failed to write "
589                                 <<path<<std::endl;
590                 throw SerializationError("Couldn't save env meta");
591         }
592 }
593
594 void ServerEnvironment::loadMeta(const std::string &savedir)
595 {
596         std::string path = savedir + "/env_meta.txt";
597
598         // Open file and deserialize
599         std::ifstream is(path.c_str(), std::ios_base::binary);
600         if(is.good() == false)
601         {
602                 infostream<<"ServerEnvironment::loadMeta(): Failed to open "
603                                 <<path<<std::endl;
604                 throw SerializationError("Couldn't load env meta");
605         }
606
607         Settings args;
608         
609         for(;;)
610         {
611                 if(is.eof())
612                         throw SerializationError
613                                         ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
614                 std::string line;
615                 std::getline(is, line);
616                 std::string trimmedline = trim(line);
617                 if(trimmedline == "EnvArgsEnd")
618                         break;
619                 args.parseConfigLine(line);
620         }
621         
622         try{
623                 m_game_time = args.getU64("game_time");
624         }catch(SettingNotFoundException &e){
625                 // Getting this is crucial, otherwise timestamps are useless
626                 throw SerializationError("Couldn't load env meta game_time");
627         }
628
629         try{
630                 m_time_of_day = args.getU64("time_of_day");
631         }catch(SettingNotFoundException &e){
632                 // This is not as important
633                 m_time_of_day = 9000;
634         }
635 }
636
637 struct ActiveABM
638 {
639         ActiveBlockModifier *abm;
640         int chance;
641         std::set<content_t> required_neighbors;
642 };
643
644 class ABMHandler
645 {
646 private:
647         ServerEnvironment *m_env;
648         std::map<content_t, std::list<ActiveABM> > m_aabms;
649 public:
650         ABMHandler(std::list<ABMWithState> &abms,
651                         float dtime_s, ServerEnvironment *env,
652                         bool use_timers):
653                 m_env(env)
654         {
655                 if(dtime_s < 0.001)
656                         return;
657                 INodeDefManager *ndef = env->getGameDef()->ndef();
658                 for(std::list<ABMWithState>::iterator
659                                 i = abms.begin(); i != abms.end(); ++i){
660                         ActiveBlockModifier *abm = i->abm;
661                         float trigger_interval = abm->getTriggerInterval();
662                         if(trigger_interval < 0.001)
663                                 trigger_interval = 0.001;
664                         float actual_interval = dtime_s;
665                         if(use_timers){
666                                 i->timer += dtime_s;
667                                 if(i->timer < trigger_interval)
668                                         continue;
669                                 i->timer -= trigger_interval;
670                                 actual_interval = trigger_interval;
671                         }
672                         float intervals = actual_interval / trigger_interval;
673                         if(intervals == 0)
674                                 continue;
675                         float chance = abm->getTriggerChance();
676                         if(chance == 0)
677                                 chance = 1;
678                         ActiveABM aabm;
679                         aabm.abm = abm;
680                         aabm.chance = chance / intervals;
681                         if(aabm.chance == 0)
682                                 aabm.chance = 1;
683                         // Trigger neighbors
684                         std::set<std::string> required_neighbors_s
685                                         = abm->getRequiredNeighbors();
686                         for(std::set<std::string>::iterator
687                                         i = required_neighbors_s.begin();
688                                         i != required_neighbors_s.end(); i++)
689                         {
690                                 ndef->getIds(*i, aabm.required_neighbors);
691                         }
692                         // Trigger contents
693                         std::set<std::string> contents_s = abm->getTriggerContents();
694                         for(std::set<std::string>::iterator
695                                         i = contents_s.begin(); i != contents_s.end(); i++)
696                         {
697                                 std::set<content_t> ids;
698                                 ndef->getIds(*i, ids);
699                                 for(std::set<content_t>::const_iterator k = ids.begin();
700                                                 k != ids.end(); k++)
701                                 {
702                                         content_t c = *k;
703                                         std::map<content_t, std::list<ActiveABM> >::iterator j;
704                                         j = m_aabms.find(c);
705                                         if(j == m_aabms.end()){
706                                                 std::list<ActiveABM> aabmlist;
707                                                 m_aabms[c] = aabmlist;
708                                                 j = m_aabms.find(c);
709                                         }
710                                         j->second.push_back(aabm);
711                                 }
712                         }
713                 }
714         }
715         void apply(MapBlock *block)
716         {
717                 if(m_aabms.empty())
718                         return;
719
720                 ServerMap *map = &m_env->getServerMap();
721
722                 // Find out how many objects the block contains
723                 u32 active_object_count = block->m_static_objects.m_active.size();
724                 // Find out how many objects this and all the neighbors contain
725                 u32 active_object_count_wider = 0;
726                 u32 wider_unknown_count = 0;
727                 for(s16 x=-1; x<=1; x++)
728                 for(s16 y=-1; y<=1; y++)
729                 for(s16 z=-1; z<=1; z++)
730                 {
731                         MapBlock *block2 = map->getBlockNoCreateNoEx(
732                                         block->getPos() + v3s16(x,y,z));
733                         if(block2==NULL){
734                                 wider_unknown_count = 0;
735                                 continue;
736                         }
737                         active_object_count_wider +=
738                                         block2->m_static_objects.m_active.size()
739                                         + block2->m_static_objects.m_stored.size();
740                 }
741                 // Extrapolate
742                 u32 wider_known_count = 3*3*3 - wider_unknown_count;
743                 active_object_count_wider += wider_unknown_count * active_object_count_wider / wider_known_count;
744                                 
745                 v3s16 p0;
746                 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
747                 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
748                 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
749                 {
750                         MapNode n = block->getNodeNoEx(p0);
751                         content_t c = n.getContent();
752                         v3s16 p = p0 + block->getPosRelative();
753
754                         std::map<content_t, std::list<ActiveABM> >::iterator j;
755                         j = m_aabms.find(c);
756                         if(j == m_aabms.end())
757                                 continue;
758
759                         for(std::list<ActiveABM>::iterator
760                                         i = j->second.begin(); i != j->second.end(); i++)
761                         {
762                                 if(myrand() % i->chance != 0)
763                                         continue;
764
765                                 // Check neighbors
766                                 if(!i->required_neighbors.empty())
767                                 {
768                                         v3s16 p1;
769                                         for(p1.X = p.X-1; p1.X <= p.X+1; p1.X++)
770                                         for(p1.Y = p.Y-1; p1.Y <= p.Y+1; p1.Y++)
771                                         for(p1.Z = p.Z-1; p1.Z <= p.Z+1; p1.Z++)
772                                         {
773                                                 if(p1 == p)
774                                                         continue;
775                                                 MapNode n = map->getNodeNoEx(p1);
776                                                 content_t c = n.getContent();
777                                                 std::set<content_t>::const_iterator k;
778                                                 k = i->required_neighbors.find(c);
779                                                 if(k != i->required_neighbors.end()){
780                                                         goto neighbor_found;
781                                                 }
782                                         }
783                                         // No required neighbor found
784                                         continue;
785                                 }
786 neighbor_found:
787
788                                 // Call all the trigger variations
789                                 i->abm->trigger(m_env, p, n);
790                                 i->abm->trigger(m_env, p, n,
791                                                 active_object_count, active_object_count_wider);
792                         }
793                 }
794         }
795 };
796
797 void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
798 {
799         // Reset usage timer immediately, otherwise a block that becomes active
800         // again at around the same time as it would normally be unloaded will
801         // get unloaded incorrectly. (I think this still leaves a small possibility
802         // of a race condition between this and server::AsyncRunStep, which only
803         // some kind of synchronisation will fix, but it at least reduces the window
804         // of opportunity for it to break from seconds to nanoseconds)
805         block->resetUsageTimer();
806
807         // Get time difference
808         u32 dtime_s = 0;
809         u32 stamp = block->getTimestamp();
810         if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
811                 dtime_s = m_game_time - block->getTimestamp();
812         dtime_s += additional_dtime;
813
814         /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
815                         <<stamp<<", game time: "<<m_game_time<<std::endl;*/
816
817         // Set current time as timestamp
818         block->setTimestampNoChangedFlag(m_game_time);
819
820         /*infostream<<"ServerEnvironment::activateBlock(): block is "
821                         <<dtime_s<<" seconds old."<<std::endl;*/
822         
823         // Activate stored objects
824         activateObjects(block, dtime_s);
825
826         // Run node timers
827         std::map<v3s16, NodeTimer> elapsed_timers =
828                 block->m_node_timers.step((float)dtime_s);
829         if(!elapsed_timers.empty()){
830                 MapNode n;
831                 for(std::map<v3s16, NodeTimer>::iterator
832                                 i = elapsed_timers.begin();
833                                 i != elapsed_timers.end(); i++){
834                         n = block->getNodeNoEx(i->first);
835                         v3s16 p = i->first + block->getPosRelative();
836                         if(m_script->node_on_timer(p,n,i->second.elapsed))
837                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
838                 }
839         }
840
841         /* Handle ActiveBlockModifiers */
842         ABMHandler abmhandler(m_abms, dtime_s, this, false);
843         abmhandler.apply(block);
844 }
845
846 void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
847 {
848         m_abms.push_back(ABMWithState(abm));
849 }
850
851 bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
852 {
853         INodeDefManager *ndef = m_gamedef->ndef();
854         MapNode n_old = m_map->getNodeNoEx(p);
855         // Call destructor
856         if(ndef->get(n_old).has_on_destruct)
857                 m_script->node_on_destruct(p, n_old);
858         // Replace node
859         bool succeeded = m_map->addNodeWithEvent(p, n);
860         if(!succeeded)
861                 return false;
862         // Call post-destructor
863         if(ndef->get(n_old).has_after_destruct)
864                 m_script->node_after_destruct(p, n_old);
865         // Call constructor
866         if(ndef->get(n).has_on_construct)
867                 m_script->node_on_construct(p, n);
868         return true;
869 }
870
871 bool ServerEnvironment::removeNode(v3s16 p)
872 {
873         INodeDefManager *ndef = m_gamedef->ndef();
874         MapNode n_old = m_map->getNodeNoEx(p);
875         // Call destructor
876         if(ndef->get(n_old).has_on_destruct)
877                 m_script->node_on_destruct(p, n_old);
878         // Replace with air
879         // This is slightly optimized compared to addNodeWithEvent(air)
880         bool succeeded = m_map->removeNodeWithEvent(p);
881         if(!succeeded)
882                 return false;
883         // Call post-destructor
884         if(ndef->get(n_old).has_after_destruct)
885                 m_script->node_after_destruct(p, n_old);
886         // Air doesn't require constructor
887         return true;
888 }
889
890 bool ServerEnvironment::swapNode(v3s16 p, const MapNode &n)
891 {
892         return m_map->addNodeWithEvent(p, n, false);
893 }
894
895 std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
896 {
897         std::set<u16> objects;
898         for(std::map<u16, ServerActiveObject*>::iterator
899                         i = m_active_objects.begin();
900                         i != m_active_objects.end(); ++i)
901         {
902                 ServerActiveObject* obj = i->second;
903                 u16 id = i->first;
904                 v3f objectpos = obj->getBasePosition();
905                 if(objectpos.getDistanceFrom(pos) > radius)
906                         continue;
907                 objects.insert(id);
908         }
909         return objects;
910 }
911
912 void ServerEnvironment::clearAllObjects()
913 {
914         infostream<<"ServerEnvironment::clearAllObjects(): "
915                         <<"Removing all active objects"<<std::endl;
916         std::list<u16> objects_to_remove;
917         for(std::map<u16, ServerActiveObject*>::iterator
918                         i = m_active_objects.begin();
919                         i != m_active_objects.end(); ++i)
920         {
921                 ServerActiveObject* obj = i->second;
922                 if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
923                         continue;
924                 u16 id = i->first;
925                 // Delete static object if block is loaded
926                 if(obj->m_static_exists){
927                         MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
928                         if(block){
929                                 block->m_static_objects.remove(id);
930                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
931                                                 "clearAllObjects");
932                                 obj->m_static_exists = false;
933                         }
934                 }
935                 // If known by some client, don't delete immediately
936                 if(obj->m_known_by_count > 0){
937                         obj->m_pending_deactivation = true;
938                         obj->m_removed = true;
939                         continue;
940                 }
941
942                 // Tell the object about removal
943                 obj->removingFromEnvironment();
944                 // Deregister in scripting api
945                 m_script->removeObjectReference(obj);
946
947                 // Delete active object
948                 if(obj->environmentDeletes())
949                         delete obj;
950                 // Id to be removed from m_active_objects
951                 objects_to_remove.push_back(id);
952         }
953         // Remove references from m_active_objects
954         for(std::list<u16>::iterator i = objects_to_remove.begin();
955                         i != objects_to_remove.end(); ++i)
956         {
957                 m_active_objects.erase(*i);
958         }
959
960         // Get list of loaded blocks
961         std::list<v3s16> loaded_blocks;
962         infostream<<"ServerEnvironment::clearAllObjects(): "
963                         <<"Listing all loaded blocks"<<std::endl;
964         m_map->listAllLoadedBlocks(loaded_blocks);
965         infostream<<"ServerEnvironment::clearAllObjects(): "
966                         <<"Done listing all loaded blocks: "
967                         <<loaded_blocks.size()<<std::endl;
968
969         // Get list of loadable blocks
970         std::list<v3s16> loadable_blocks;
971         infostream<<"ServerEnvironment::clearAllObjects(): "
972                         <<"Listing all loadable blocks"<<std::endl;
973         m_map->listAllLoadableBlocks(loadable_blocks);
974         infostream<<"ServerEnvironment::clearAllObjects(): "
975                         <<"Done listing all loadable blocks: "
976                         <<loadable_blocks.size()
977                         <<", now clearing"<<std::endl;
978
979         // Grab a reference on each loaded block to avoid unloading it
980         for(std::list<v3s16>::iterator i = loaded_blocks.begin();
981                         i != loaded_blocks.end(); ++i)
982         {
983                 v3s16 p = *i;
984                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
985                 assert(block);
986                 block->refGrab();
987         }
988
989         // Remove objects in all loadable blocks
990         u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
991         unload_interval = MYMAX(unload_interval, 1);
992         u32 report_interval = loadable_blocks.size() / 10;
993         u32 num_blocks_checked = 0;
994         u32 num_blocks_cleared = 0;
995         u32 num_objs_cleared = 0;
996         for(std::list<v3s16>::iterator i = loadable_blocks.begin();
997                         i != loadable_blocks.end(); ++i)
998         {
999                 v3s16 p = *i;
1000                 MapBlock *block = m_map->emergeBlock(p, false);
1001                 if(!block){
1002                         errorstream<<"ServerEnvironment::clearAllObjects(): "
1003                                         <<"Failed to emerge block "<<PP(p)<<std::endl;
1004                         continue;
1005                 }
1006                 u32 num_stored = block->m_static_objects.m_stored.size();
1007                 u32 num_active = block->m_static_objects.m_active.size();
1008                 if(num_stored != 0 || num_active != 0){
1009                         block->m_static_objects.m_stored.clear();
1010                         block->m_static_objects.m_active.clear();
1011                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1012                                         "clearAllObjects");
1013                         num_objs_cleared += num_stored + num_active;
1014                         num_blocks_cleared++;
1015                 }
1016                 num_blocks_checked++;
1017
1018                 if(report_interval != 0 &&
1019                                 num_blocks_checked % report_interval == 0){
1020                         float percent = 100.0 * (float)num_blocks_checked /
1021                                         loadable_blocks.size();
1022                         infostream<<"ServerEnvironment::clearAllObjects(): "
1023                                         <<"Cleared "<<num_objs_cleared<<" objects"
1024                                         <<" in "<<num_blocks_cleared<<" blocks ("
1025                                         <<percent<<"%)"<<std::endl;
1026                 }
1027                 if(num_blocks_checked % unload_interval == 0){
1028                         m_map->unloadUnreferencedBlocks();
1029                 }
1030         }
1031         m_map->unloadUnreferencedBlocks();
1032
1033         // Drop references that were added above
1034         for(std::list<v3s16>::iterator i = loaded_blocks.begin();
1035                         i != loaded_blocks.end(); ++i)
1036         {
1037                 v3s16 p = *i;
1038                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1039                 assert(block);
1040                 block->refDrop();
1041         }
1042
1043         infostream<<"ServerEnvironment::clearAllObjects(): "
1044                         <<"Finished: Cleared "<<num_objs_cleared<<" objects"
1045                         <<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
1046 }
1047
1048 void ServerEnvironment::step(float dtime)
1049 {
1050         DSTACK(__FUNCTION_NAME);
1051         
1052         //TimeTaker timer("ServerEnv step");
1053
1054         /* Step time of day */
1055         stepTimeOfDay(dtime);
1056
1057         // Update this one
1058         // NOTE: This is kind of funny on a singleplayer game, but doesn't
1059         // really matter that much.
1060         m_recommended_send_interval = g_settings->getFloat("dedicated_server_step");
1061
1062         /*
1063                 Increment game time
1064         */
1065         {
1066                 m_game_time_fraction_counter += dtime;
1067                 u32 inc_i = (u32)m_game_time_fraction_counter;
1068                 m_game_time += inc_i;
1069                 m_game_time_fraction_counter -= (float)inc_i;
1070         }
1071         
1072         /*
1073                 Handle players
1074         */
1075         {
1076                 ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
1077                 for(std::list<Player*>::iterator i = m_players.begin();
1078                                 i != m_players.end(); ++i)
1079                 {
1080                         Player *player = *i;
1081                         
1082                         // Ignore disconnected players
1083                         if(player->peer_id == 0)
1084                                 continue;
1085                         
1086                         // Move
1087                         player->move(dtime, *m_map, 100*BS);
1088                 }
1089         }
1090
1091         /*
1092                 Manage active block list
1093         */
1094         if(m_active_blocks_management_interval.step(dtime, 2.0))
1095         {
1096                 ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg /2s", SPT_AVG);
1097                 /*
1098                         Get player block positions
1099                 */
1100                 std::list<v3s16> players_blockpos;
1101                 for(std::list<Player*>::iterator
1102                                 i = m_players.begin();
1103                                 i != m_players.end(); ++i)
1104                 {
1105                         Player *player = *i;
1106                         // Ignore disconnected players
1107                         if(player->peer_id == 0)
1108                                 continue;
1109                         v3s16 blockpos = getNodeBlockPos(
1110                                         floatToInt(player->getPosition(), BS));
1111                         players_blockpos.push_back(blockpos);
1112                 }
1113                 
1114                 /*
1115                         Update list of active blocks, collecting changes
1116                 */
1117                 const s16 active_block_range = g_settings->getS16("active_block_range");
1118                 std::set<v3s16> blocks_removed;
1119                 std::set<v3s16> blocks_added;
1120                 m_active_blocks.update(players_blockpos, active_block_range,
1121                                 blocks_removed, blocks_added);
1122
1123                 /*
1124                         Handle removed blocks
1125                 */
1126
1127                 // Convert active objects that are no more in active blocks to static
1128                 deactivateFarObjects(false);
1129                 
1130                 for(std::set<v3s16>::iterator
1131                                 i = blocks_removed.begin();
1132                                 i != blocks_removed.end(); ++i)
1133                 {
1134                         v3s16 p = *i;
1135
1136                         /* infostream<<"Server: Block " << PP(p)
1137                                 << " became inactive"<<std::endl; */
1138                         
1139                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1140                         if(block==NULL)
1141                                 continue;
1142                         
1143                         // Set current time as timestamp (and let it set ChangedFlag)
1144                         block->setTimestamp(m_game_time);
1145                 }
1146
1147                 /*
1148                         Handle added blocks
1149                 */
1150
1151                 for(std::set<v3s16>::iterator
1152                                 i = blocks_added.begin();
1153                                 i != blocks_added.end(); ++i)
1154                 {
1155                         v3s16 p = *i;
1156
1157                         MapBlock *block = m_map->getBlockOrEmerge(p);
1158                         if(block==NULL){
1159                                 m_active_blocks.m_list.erase(p);
1160                                 continue;
1161                         }
1162
1163                         activateBlock(block);
1164                         /* infostream<<"Server: Block " << PP(p)
1165                                 << " became active"<<std::endl; */
1166                 }
1167         }
1168
1169         /*
1170                 Mess around in active blocks
1171         */
1172         if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
1173         {
1174                 ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg /1s", SPT_AVG);
1175                 
1176                 float dtime = 1.0;
1177
1178                 for(std::set<v3s16>::iterator
1179                                 i = m_active_blocks.m_list.begin();
1180                                 i != m_active_blocks.m_list.end(); ++i)
1181                 {
1182                         v3s16 p = *i;
1183                         
1184                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1185                                         <<") being handled"<<std::endl;*/
1186
1187                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1188                         if(block==NULL)
1189                                 continue;
1190
1191                         // Reset block usage timer
1192                         block->resetUsageTimer();
1193                         
1194                         // Set current time as timestamp
1195                         block->setTimestampNoChangedFlag(m_game_time);
1196                         // If time has changed much from the one on disk,
1197                         // set block to be saved when it is unloaded
1198                         if(block->getTimestamp() > block->getDiskTimestamp() + 60)
1199                                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1200                                                 "Timestamp older than 60s (step)");
1201
1202                         // Run node timers
1203                         std::map<v3s16, NodeTimer> elapsed_timers =
1204                                 block->m_node_timers.step((float)dtime);
1205                         if(!elapsed_timers.empty()){
1206                                 MapNode n;
1207                                 for(std::map<v3s16, NodeTimer>::iterator
1208                                                 i = elapsed_timers.begin();
1209                                                 i != elapsed_timers.end(); i++){
1210                                         n = block->getNodeNoEx(i->first);
1211                                         p = i->first + block->getPosRelative();
1212                                         if(m_script->node_on_timer(p,n,i->second.elapsed))
1213                                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
1214                                 }
1215                         }
1216                 }
1217         }
1218         
1219         const float abm_interval = 1.0;
1220         if(m_active_block_modifier_interval.step(dtime, abm_interval))
1221         do{ // breakable
1222                 if(m_active_block_interval_overload_skip > 0){
1223                         ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
1224                         m_active_block_interval_overload_skip--;
1225                         break;
1226                 }
1227                 ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg /1s", SPT_AVG);
1228                 TimeTaker timer("modify in active blocks");
1229                 
1230                 // Initialize handling of ActiveBlockModifiers
1231                 ABMHandler abmhandler(m_abms, abm_interval, this, true);
1232
1233                 for(std::set<v3s16>::iterator
1234                                 i = m_active_blocks.m_list.begin();
1235                                 i != m_active_blocks.m_list.end(); ++i)
1236                 {
1237                         v3s16 p = *i;
1238                         
1239                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1240                                         <<") being handled"<<std::endl;*/
1241
1242                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1243                         if(block==NULL)
1244                                 continue;
1245                         
1246                         // Set current time as timestamp
1247                         block->setTimestampNoChangedFlag(m_game_time);
1248
1249                         /* Handle ActiveBlockModifiers */
1250                         abmhandler.apply(block);
1251                 }
1252
1253                 u32 time_ms = timer.stop(true);
1254                 u32 max_time_ms = 200;
1255                 if(time_ms > max_time_ms){
1256                         infostream<<"WARNING: active block modifiers took "
1257                                         <<time_ms<<"ms (longer than "
1258                                         <<max_time_ms<<"ms)"<<std::endl;
1259                         m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
1260                 }
1261         }while(0);
1262         
1263         /*
1264                 Step script environment (run global on_step())
1265         */
1266         m_script->environment_Step(dtime);
1267
1268         /*
1269                 Step active objects
1270         */
1271         {
1272                 ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
1273                 //TimeTaker timer("Step active objects");
1274
1275                 g_profiler->avg("SEnv: num of objects", m_active_objects.size());
1276                 
1277                 // This helps the objects to send data at the same time
1278                 bool send_recommended = false;
1279                 m_send_recommended_timer += dtime;
1280                 if(m_send_recommended_timer > getSendRecommendedInterval())
1281                 {
1282                         m_send_recommended_timer -= getSendRecommendedInterval();
1283                         send_recommended = true;
1284                 }
1285
1286                 for(std::map<u16, ServerActiveObject*>::iterator
1287                                 i = m_active_objects.begin();
1288                                 i != m_active_objects.end(); ++i)
1289                 {
1290                         ServerActiveObject* obj = i->second;
1291                         // Remove non-peaceful mobs on peaceful mode
1292                         if(g_settings->getBool("only_peaceful_mobs")){
1293                                 if(!obj->isPeaceful())
1294                                         obj->m_removed = true;
1295                         }
1296                         // Don't step if is to be removed or stored statically
1297                         if(obj->m_removed || obj->m_pending_deactivation)
1298                                 continue;
1299                         // Step object
1300                         obj->step(dtime, send_recommended);
1301                         // Read messages from object
1302                         while(!obj->m_messages_out.empty())
1303                         {
1304                                 m_active_object_messages.push_back(
1305                                                 obj->m_messages_out.pop_front());
1306                         }
1307                 }
1308         }
1309         
1310         /*
1311                 Manage active objects
1312         */
1313         if(m_object_management_interval.step(dtime, 0.5))
1314         {
1315                 ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
1316                 /*
1317                         Remove objects that satisfy (m_removed && m_known_by_count==0)
1318                 */
1319                 removeRemovedObjects();
1320         }
1321 }
1322
1323 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
1324 {
1325         std::map<u16, ServerActiveObject*>::iterator n;
1326         n = m_active_objects.find(id);
1327         if(n == m_active_objects.end())
1328                 return NULL;
1329         return n->second;
1330 }
1331
1332 bool isFreeServerActiveObjectId(u16 id,
1333                 std::map<u16, ServerActiveObject*> &objects)
1334 {
1335         if(id == 0)
1336                 return false;
1337
1338         return objects.find(id) == objects.end();
1339 }
1340
1341 u16 getFreeServerActiveObjectId(
1342                 std::map<u16, ServerActiveObject*> &objects)
1343 {
1344         //try to reuse id's as late as possible
1345         static u16 last_used_id = 0;
1346         u16 startid = last_used_id;
1347         for(;;)
1348         {
1349                 last_used_id ++;
1350                 if(isFreeServerActiveObjectId(last_used_id, objects))
1351                         return last_used_id;
1352                 
1353                 if(last_used_id == startid)
1354                         return 0;
1355         }
1356 }
1357
1358 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1359 {
1360         assert(object);
1361         u16 id = addActiveObjectRaw(object, true, 0);
1362         return id;
1363 }
1364
1365 #if 0
1366 bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
1367 {
1368         assert(obj);
1369
1370         v3f objectpos = obj->getBasePosition(); 
1371
1372         // The block in which the object resides in
1373         v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1374
1375         /*
1376                 Update the static data
1377         */
1378
1379         // Create new static object
1380         std::string staticdata = obj->getStaticData();
1381         StaticObject s_obj(obj->getType(), objectpos, staticdata);
1382         // Add to the block where the object is located in
1383         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1384         // Get or generate the block
1385         MapBlock *block = m_map->emergeBlock(blockpos);
1386
1387         bool succeeded = false;
1388
1389         if(block)
1390         {
1391                 block->m_static_objects.insert(0, s_obj);
1392                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1393                                 "addActiveObjectAsStatic");
1394                 succeeded = true;
1395         }
1396         else{
1397                 infostream<<"ServerEnvironment::addActiveObjectAsStatic: "
1398                                 <<"Could not find or generate "
1399                                 <<"a block for storing static object"<<std::endl;
1400                 succeeded = false;
1401         }
1402
1403         if(obj->environmentDeletes())
1404                 delete obj;
1405
1406         return succeeded;
1407 }
1408 #endif
1409
1410 /*
1411         Finds out what new objects have been added to
1412         inside a radius around a position
1413 */
1414 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1415                 std::set<u16> &current_objects,
1416                 std::set<u16> &added_objects)
1417 {
1418         v3f pos_f = intToFloat(pos, BS);
1419         f32 radius_f = radius * BS;
1420         /*
1421                 Go through the object list,
1422                 - discard m_removed objects,
1423                 - discard objects that are too far away,
1424                 - discard objects that are found in current_objects.
1425                 - add remaining objects to added_objects
1426         */
1427         for(std::map<u16, ServerActiveObject*>::iterator
1428                         i = m_active_objects.begin();
1429                         i != m_active_objects.end(); ++i)
1430         {
1431                 u16 id = i->first;
1432                 // Get object
1433                 ServerActiveObject *object = i->second;
1434                 if(object == NULL)
1435                         continue;
1436                 // Discard if removed or deactivating
1437                 if(object->m_removed || object->m_pending_deactivation)
1438                         continue;
1439                 if(object->unlimitedTransferDistance() == false){
1440                         // Discard if too far
1441                         f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1442                         if(distance_f > radius_f)
1443                                 continue;
1444                 }
1445                 // Discard if already on current_objects
1446                 std::set<u16>::iterator n;
1447                 n = current_objects.find(id);
1448                 if(n != current_objects.end())
1449                         continue;
1450                 // Add to added_objects
1451                 added_objects.insert(id);
1452         }
1453 }
1454
1455 /*
1456         Finds out what objects have been removed from
1457         inside a radius around a position
1458 */
1459 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1460                 std::set<u16> &current_objects,
1461                 std::set<u16> &removed_objects)
1462 {
1463         v3f pos_f = intToFloat(pos, BS);
1464         f32 radius_f = radius * BS;
1465         /*
1466                 Go through current_objects; object is removed if:
1467                 - object is not found in m_active_objects (this is actually an
1468                   error condition; objects should be set m_removed=true and removed
1469                   only after all clients have been informed about removal), or
1470                 - object has m_removed=true, or
1471                 - object is too far away
1472         */
1473         for(std::set<u16>::iterator
1474                         i = current_objects.begin();
1475                         i != current_objects.end(); ++i)
1476         {
1477                 u16 id = *i;
1478                 ServerActiveObject *object = getActiveObject(id);
1479
1480                 if(object == NULL){
1481                         infostream<<"ServerEnvironment::getRemovedActiveObjects():"
1482                                         <<" object in current_objects is NULL"<<std::endl;
1483                         removed_objects.insert(id);
1484                         continue;
1485                 }
1486
1487                 if(object->m_removed || object->m_pending_deactivation)
1488                 {
1489                         removed_objects.insert(id);
1490                         continue;
1491                 }
1492                 
1493                 // If transfer distance is unlimited, don't remove
1494                 if(object->unlimitedTransferDistance())
1495                         continue;
1496
1497                 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1498
1499                 if(distance_f >= radius_f)
1500                 {
1501                         removed_objects.insert(id);
1502                         continue;
1503                 }
1504                 
1505                 // Not removed
1506         }
1507 }
1508
1509 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1510 {
1511         if(m_active_object_messages.empty())
1512                 return ActiveObjectMessage(0);
1513         
1514         ActiveObjectMessage message = m_active_object_messages.front();
1515         m_active_object_messages.pop_front();
1516         return message;
1517 }
1518
1519 /*
1520         ************ Private methods *************
1521 */
1522
1523 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1524                 bool set_changed, u32 dtime_s)
1525 {
1526         assert(object);
1527         if(object->getId() == 0){
1528                 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
1529                 if(new_id == 0)
1530                 {
1531                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1532                                         <<"no free ids available"<<std::endl;
1533                         if(object->environmentDeletes())
1534                                 delete object;
1535                         return 0;
1536                 }
1537                 object->setId(new_id);
1538         }
1539         else{
1540                 verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1541                                 <<"supplied with id "<<object->getId()<<std::endl;
1542         }
1543         if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
1544         {
1545                 errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1546                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1547                 if(object->environmentDeletes())
1548                         delete object;
1549                 return 0;
1550         }
1551         /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1552                         <<"added (id="<<object->getId()<<")"<<std::endl;*/
1553                         
1554         m_active_objects[object->getId()] = object;
1555   
1556         verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1557                         <<"Added id="<<object->getId()<<"; there are now "
1558                         <<m_active_objects.size()<<" active objects."
1559                         <<std::endl;
1560         
1561         // Register reference in scripting api (must be done before post-init)
1562         m_script->addObjectReference(object);
1563         // Post-initialize object
1564         object->addedToEnvironment(dtime_s);
1565         
1566         // Add static data to block
1567         if(object->isStaticAllowed())
1568         {
1569                 // Add static object to active static list of the block
1570                 v3f objectpos = object->getBasePosition();
1571                 std::string staticdata = object->getStaticData();
1572                 StaticObject s_obj(object->getType(), objectpos, staticdata);
1573                 // Add to the block where the object is located in
1574                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1575                 MapBlock *block = m_map->emergeBlock(blockpos);
1576                 if(block){
1577                         block->m_static_objects.m_active[object->getId()] = s_obj;
1578                         object->m_static_exists = true;
1579                         object->m_static_block = blockpos;
1580
1581                         if(set_changed)
1582                                 block->raiseModified(MOD_STATE_WRITE_NEEDED, 
1583                                                 "addActiveObjectRaw");
1584                 } else {
1585                         v3s16 p = floatToInt(objectpos, BS);
1586                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1587                                         <<"could not emerge block for storing id="<<object->getId()
1588                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1589                 }
1590         }
1591         
1592         return object->getId();
1593 }
1594
1595 /*
1596         Remove objects that satisfy (m_removed && m_known_by_count==0)
1597 */
1598 void ServerEnvironment::removeRemovedObjects()
1599 {
1600         std::list<u16> objects_to_remove;
1601         for(std::map<u16, ServerActiveObject*>::iterator
1602                         i = m_active_objects.begin();
1603                         i != m_active_objects.end(); ++i)
1604         {
1605                 u16 id = i->first;
1606                 ServerActiveObject* obj = i->second;
1607                 // This shouldn't happen but check it
1608                 if(obj == NULL)
1609                 {
1610                         infostream<<"NULL object found in ServerEnvironment"
1611                                         <<" while finding removed objects. id="<<id<<std::endl;
1612                         // Id to be removed from m_active_objects
1613                         objects_to_remove.push_back(id);
1614                         continue;
1615                 }
1616
1617                 /*
1618                         We will delete objects that are marked as removed or thatare
1619                         waiting for deletion after deactivation
1620                 */
1621                 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1622                         continue;
1623
1624                 /*
1625                         Delete static data from block if is marked as removed
1626                 */
1627                 if(obj->m_static_exists && obj->m_removed)
1628                 {
1629                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1630                         if (block) {
1631                                 block->m_static_objects.remove(id);
1632                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1633                                                 "removeRemovedObjects/remove");
1634                                 obj->m_static_exists = false;
1635                         } else {
1636                                 infostream<<"Failed to emerge block from which an object to "
1637                                                 <<"be removed was loaded from. id="<<id<<std::endl;
1638                         }
1639                 }
1640
1641                 // If m_known_by_count > 0, don't actually remove. On some future
1642                 // invocation this will be 0, which is when removal will continue.
1643                 if(obj->m_known_by_count > 0)
1644                         continue;
1645
1646                 /*
1647                         Move static data from active to stored if not marked as removed
1648                 */
1649                 if(obj->m_static_exists && !obj->m_removed){
1650                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1651                         if (block) {
1652                                 std::map<u16, StaticObject>::iterator i =
1653                                                 block->m_static_objects.m_active.find(id);
1654                                 if(i != block->m_static_objects.m_active.end()){
1655                                         block->m_static_objects.m_stored.push_back(i->second);
1656                                         block->m_static_objects.m_active.erase(id);
1657                                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1658                                                         "removeRemovedObjects/deactivate");
1659                                 }
1660                         } else {
1661                                 infostream<<"Failed to emerge block from which an object to "
1662                                                 <<"be deactivated was loaded from. id="<<id<<std::endl;
1663                         }
1664                 }
1665
1666                 // Tell the object about removal
1667                 obj->removingFromEnvironment();
1668                 // Deregister in scripting api
1669                 m_script->removeObjectReference(obj);
1670
1671                 // Delete
1672                 if(obj->environmentDeletes())
1673                         delete obj;
1674                 // Id to be removed from m_active_objects
1675                 objects_to_remove.push_back(id);
1676         }
1677         // Remove references from m_active_objects
1678         for(std::list<u16>::iterator i = objects_to_remove.begin();
1679                         i != objects_to_remove.end(); ++i)
1680         {
1681                 m_active_objects.erase(*i);
1682         }
1683 }
1684
1685 static void print_hexdump(std::ostream &o, const std::string &data)
1686 {
1687         const int linelength = 16;
1688         for(int l=0; ; l++){
1689                 int i0 = linelength * l;
1690                 bool at_end = false;
1691                 int thislinelength = linelength;
1692                 if(i0 + thislinelength > (int)data.size()){
1693                         thislinelength = data.size() - i0;
1694                         at_end = true;
1695                 }
1696                 for(int di=0; di<linelength; di++){
1697                         int i = i0 + di;
1698                         char buf[4];
1699                         if(di<thislinelength)
1700                                 snprintf(buf, 4, "%.2x ", data[i]);
1701                         else
1702                                 snprintf(buf, 4, "   ");
1703                         o<<buf;
1704                 }
1705                 o<<" ";
1706                 for(int di=0; di<thislinelength; di++){
1707                         int i = i0 + di;
1708                         if(data[i] >= 32)
1709                                 o<<data[i];
1710                         else
1711                                 o<<".";
1712                 }
1713                 o<<std::endl;
1714                 if(at_end)
1715                         break;
1716         }
1717 }
1718
1719 /*
1720         Convert stored objects from blocks near the players to active.
1721 */
1722 void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
1723 {
1724         if(block==NULL)
1725                 return;
1726         // Ignore if no stored objects (to not set changed flag)
1727         if(block->m_static_objects.m_stored.size() == 0)
1728                 return;
1729         verbosestream<<"ServerEnvironment::activateObjects(): "
1730                         <<"activating objects of block "<<PP(block->getPos())
1731                         <<" ("<<block->m_static_objects.m_stored.size()
1732                         <<" objects)"<<std::endl;
1733         bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
1734         if(large_amount){
1735                 errorstream<<"suspiciously large amount of objects detected: "
1736                                 <<block->m_static_objects.m_stored.size()<<" in "
1737                                 <<PP(block->getPos())
1738                                 <<"; removing all of them."<<std::endl;
1739                 // Clear stored list
1740                 block->m_static_objects.m_stored.clear();
1741                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1742                                 "stored list cleared in activateObjects due to "
1743                                 "large amount of objects");
1744                 return;
1745         }
1746
1747         // Activate stored objects
1748         std::list<StaticObject> new_stored;
1749         for(std::list<StaticObject>::iterator
1750                         i = block->m_static_objects.m_stored.begin();
1751                         i != block->m_static_objects.m_stored.end(); ++i)
1752         {
1753                 /*infostream<<"Server: Creating an active object from "
1754                                 <<"static data"<<std::endl;*/
1755                 StaticObject &s_obj = *i;
1756                 // Create an active object from the data
1757                 ServerActiveObject *obj = ServerActiveObject::create
1758                                 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1759                 // If couldn't create object, store static data back.
1760                 if(obj==NULL)
1761                 {
1762                         errorstream<<"ServerEnvironment::activateObjects(): "
1763                                         <<"failed to create active object from static object "
1764                                         <<"in block "<<PP(s_obj.pos/BS)
1765                                         <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
1766                         print_hexdump(verbosestream, s_obj.data);
1767                         
1768                         new_stored.push_back(s_obj);
1769                         continue;
1770                 }
1771                 verbosestream<<"ServerEnvironment::activateObjects(): "
1772                                 <<"activated static object pos="<<PP(s_obj.pos/BS)
1773                                 <<" type="<<(int)s_obj.type<<std::endl;
1774                 // This will also add the object to the active static list
1775                 addActiveObjectRaw(obj, false, dtime_s);
1776         }
1777         // Clear stored list
1778         block->m_static_objects.m_stored.clear();
1779         // Add leftover failed stuff to stored list
1780         for(std::list<StaticObject>::iterator
1781                         i = new_stored.begin();
1782                         i != new_stored.end(); ++i)
1783         {
1784                 StaticObject &s_obj = *i;
1785                 block->m_static_objects.m_stored.push_back(s_obj);
1786         }
1787
1788         // Turn the active counterparts of activated objects not pending for
1789         // deactivation
1790         for(std::map<u16, StaticObject>::iterator
1791                         i = block->m_static_objects.m_active.begin();
1792                         i != block->m_static_objects.m_active.end(); ++i)
1793         {
1794                 u16 id = i->first;
1795                 ServerActiveObject *object = getActiveObject(id);
1796                 assert(object);
1797                 object->m_pending_deactivation = false;
1798         }
1799
1800         /*
1801                 Note: Block hasn't really been modified here.
1802                 The objects have just been activated and moved from the stored
1803                 static list to the active static list.
1804                 As such, the block is essentially the same.
1805                 Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
1806                 Otherwise there would be a huge amount of unnecessary I/O.
1807         */
1808 }
1809
1810 /*
1811         Convert objects that are not standing inside active blocks to static.
1812
1813         If m_known_by_count != 0, active object is not deleted, but static
1814         data is still updated.
1815
1816         If force_delete is set, active object is deleted nevertheless. It
1817         shall only be set so in the destructor of the environment.
1818
1819         If block wasn't generated (not in memory or on disk), 
1820 */
1821 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1822 {
1823         std::list<u16> objects_to_remove;
1824         for(std::map<u16, ServerActiveObject*>::iterator
1825                         i = m_active_objects.begin();
1826                         i != m_active_objects.end(); ++i)
1827         {
1828                 ServerActiveObject* obj = i->second;
1829                 assert(obj);
1830                 
1831                 // Do not deactivate if static data creation not allowed
1832                 if(!force_delete && !obj->isStaticAllowed())
1833                         continue;
1834
1835                 // If pending deactivation, let removeRemovedObjects() do it
1836                 if(!force_delete && obj->m_pending_deactivation)
1837                         continue;
1838
1839                 u16 id = i->first;
1840                 v3f objectpos = obj->getBasePosition(); 
1841
1842                 // The block in which the object resides in
1843                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1844
1845                 // If object's static data is stored in a deactivated block and object
1846                 // is actually located in an active block, re-save to the block in
1847                 // which the object is actually located in.
1848                 if(!force_delete &&
1849                                 obj->m_static_exists &&
1850                                 !m_active_blocks.contains(obj->m_static_block) &&
1851                                  m_active_blocks.contains(blockpos_o))
1852                 {
1853                         v3s16 old_static_block = obj->m_static_block;
1854
1855                         // Save to block where object is located
1856                         MapBlock *block = m_map->emergeBlock(blockpos_o, false);
1857                         if(!block){
1858                                 errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1859                                                 <<"Could not save object id="<<id
1860                                                 <<" to it's current block "<<PP(blockpos_o)
1861                                                 <<std::endl;
1862                                 continue;
1863                         }
1864                         std::string staticdata_new = obj->getStaticData();
1865                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1866                         block->m_static_objects.insert(id, s_obj);
1867                         obj->m_static_block = blockpos_o;
1868                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1869                                         "deactivateFarObjects: Static data moved in");
1870
1871                         // Delete from block where object was located
1872                         block = m_map->emergeBlock(old_static_block, false);
1873                         if(!block){
1874                                 errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1875                                                 <<"Could not delete object id="<<id
1876                                                 <<" from it's previous block "<<PP(old_static_block)
1877                                                 <<std::endl;
1878                                 continue;
1879                         }
1880                         block->m_static_objects.remove(id);
1881                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1882                                         "deactivateFarObjects: Static data moved out");
1883                         continue;
1884                 }
1885
1886                 // If block is active, don't remove
1887                 if(!force_delete && m_active_blocks.contains(blockpos_o))
1888                         continue;
1889
1890                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1891                                 <<"deactivating object id="<<id<<" on inactive block "
1892                                 <<PP(blockpos_o)<<std::endl;
1893
1894                 // If known by some client, don't immediately delete.
1895                 bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
1896
1897                 /*
1898                         Update the static data
1899                 */
1900
1901                 if(obj->isStaticAllowed())
1902                 {
1903                         // Create new static object
1904                         std::string staticdata_new = obj->getStaticData();
1905                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1906                         
1907                         bool stays_in_same_block = false;
1908                         bool data_changed = true;
1909
1910                         if(obj->m_static_exists){
1911                                 if(obj->m_static_block == blockpos_o)
1912                                         stays_in_same_block = true;
1913
1914                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1915                                 
1916                                 std::map<u16, StaticObject>::iterator n =
1917                                                 block->m_static_objects.m_active.find(id);
1918                                 if(n != block->m_static_objects.m_active.end()){
1919                                         StaticObject static_old = n->second;
1920
1921                                         float save_movem = obj->getMinimumSavedMovement();
1922
1923                                         if(static_old.data == staticdata_new &&
1924                                                         (static_old.pos - objectpos).getLength() < save_movem)
1925                                                 data_changed = false;
1926                                 } else {
1927                                         errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1928                                                         <<"id="<<id<<" m_static_exists=true but "
1929                                                         <<"static data doesn't actually exist in "
1930                                                         <<PP(obj->m_static_block)<<std::endl;
1931                                 }
1932                         }
1933
1934                         bool shall_be_written = (!stays_in_same_block || data_changed);
1935                         
1936                         // Delete old static object
1937                         if(obj->m_static_exists)
1938                         {
1939                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1940                                 if(block)
1941                                 {
1942                                         block->m_static_objects.remove(id);
1943                                         obj->m_static_exists = false;
1944                                         // Only mark block as modified if data changed considerably
1945                                         if(shall_be_written)
1946                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1947                                                                 "deactivateFarObjects: Static data "
1948                                                                 "changed considerably");
1949                                 }
1950                         }
1951
1952                         // Add to the block where the object is located in
1953                         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1954                         // Get or generate the block
1955                         MapBlock *block = NULL;
1956                         try{
1957                                 block = m_map->emergeBlock(blockpos);
1958                         } catch(InvalidPositionException &e){
1959                                 // Handled via NULL pointer
1960                                 // NOTE: emergeBlock's failure is usually determined by it
1961                                 //       actually returning NULL
1962                         }
1963
1964                         if(block)
1965                         {
1966                                 if(block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")){
1967                                         errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
1968                                                         <<" statically but block "<<PP(blockpos)
1969                                                         <<" already contains "
1970                                                         <<block->m_static_objects.m_stored.size()
1971                                                         <<" objects."
1972                                                         <<" Forcing delete."<<std::endl;
1973                                         force_delete = true;
1974                                 } else {
1975                                         // If static counterpart already exists in target block,
1976                                         // remove it first.
1977                                         // This shouldn't happen because the object is removed from
1978                                         // the previous block before this according to
1979                                         // obj->m_static_block, but happens rarely for some unknown
1980                                         // reason. Unsuccessful attempts have been made to find
1981                                         // said reason.
1982                                         if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
1983                                                 infostream<<"ServerEnv: WARNING: Performing hack #83274"
1984                                                                 <<std::endl;
1985                                                 block->m_static_objects.remove(id);
1986                                         }
1987                                         // Store static data
1988                                         u16 store_id = pending_delete ? id : 0;
1989                                         block->m_static_objects.insert(store_id, s_obj);
1990                                         
1991                                         // Only mark block as modified if data changed considerably
1992                                         if(shall_be_written)
1993                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1994                                                                 "deactivateFarObjects: Static data "
1995                                                                 "changed considerably");
1996                                         
1997                                         obj->m_static_exists = true;
1998                                         obj->m_static_block = block->getPos();
1999                                 }
2000                         }
2001                         else{
2002                                 if(!force_delete){
2003                                         v3s16 p = floatToInt(objectpos, BS);
2004                                         errorstream<<"ServerEnv: Could not find or generate "
2005                                                         <<"a block for storing id="<<obj->getId()
2006                                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
2007                                         continue;
2008                                 }
2009                         }
2010                 }
2011
2012                 /*
2013                         If known by some client, set pending deactivation.
2014                         Otherwise delete it immediately.
2015                 */
2016
2017                 if(pending_delete && !force_delete)
2018                 {
2019                         verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
2020                                         <<"object id="<<id<<" is known by clients"
2021                                         <<"; not deleting yet"<<std::endl;
2022
2023                         obj->m_pending_deactivation = true;
2024                         continue;
2025                 }
2026                 
2027                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
2028                                 <<"object id="<<id<<" is not known by clients"
2029                                 <<"; deleting"<<std::endl;
2030
2031                 // Tell the object about removal
2032                 obj->removingFromEnvironment();
2033                 // Deregister in scripting api
2034                 m_script->removeObjectReference(obj);
2035
2036                 // Delete active object
2037                 if(obj->environmentDeletes())
2038                         delete obj;
2039                 // Id to be removed from m_active_objects
2040                 objects_to_remove.push_back(id);
2041         }
2042
2043         // Remove references from m_active_objects
2044         for(std::list<u16>::iterator i = objects_to_remove.begin();
2045                         i != objects_to_remove.end(); ++i)
2046         {
2047                 m_active_objects.erase(*i);
2048         }
2049 }
2050
2051
2052 #ifndef SERVER
2053
2054 #include "clientsimpleobject.h"
2055
2056 /*
2057         ClientEnvironment
2058 */
2059
2060 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
2061                 ITextureSource *texturesource, IGameDef *gamedef,
2062                 IrrlichtDevice *irr):
2063         m_map(map),
2064         m_smgr(smgr),
2065         m_texturesource(texturesource),
2066         m_gamedef(gamedef),
2067         m_irr(irr)
2068 {
2069 }
2070
2071 ClientEnvironment::~ClientEnvironment()
2072 {
2073         // delete active objects
2074         for(std::map<u16, ClientActiveObject*>::iterator
2075                         i = m_active_objects.begin();
2076                         i != m_active_objects.end(); ++i)
2077         {
2078                 delete i->second;
2079         }
2080
2081         for(std::list<ClientSimpleObject*>::iterator
2082                         i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i)
2083         {
2084                 delete *i;
2085         }
2086
2087         // Drop/delete map
2088         m_map->drop();
2089 }
2090
2091 Map & ClientEnvironment::getMap()
2092 {
2093         return *m_map;
2094 }
2095
2096 ClientMap & ClientEnvironment::getClientMap()
2097 {
2098         return *m_map;
2099 }
2100
2101 void ClientEnvironment::addPlayer(Player *player)
2102 {
2103         DSTACK(__FUNCTION_NAME);
2104         /*
2105                 It is a failure if player is local and there already is a local
2106                 player
2107         */
2108         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
2109
2110         Environment::addPlayer(player);
2111 }
2112
2113 LocalPlayer * ClientEnvironment::getLocalPlayer()
2114 {
2115         for(std::list<Player*>::iterator i = m_players.begin();
2116                         i != m_players.end(); ++i)
2117         {
2118                 Player *player = *i;
2119                 if(player->isLocal())
2120                         return (LocalPlayer*)player;
2121         }
2122         return NULL;
2123 }
2124
2125 void ClientEnvironment::step(float dtime)
2126 {
2127         DSTACK(__FUNCTION_NAME);
2128
2129         /* Step time of day */
2130         stepTimeOfDay(dtime);
2131
2132         // Get some settings
2133         bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
2134         bool free_move = fly_allowed && g_settings->getBool("free_move");
2135
2136         // Get local player
2137         LocalPlayer *lplayer = getLocalPlayer();
2138         assert(lplayer);
2139         // collision info queue
2140         std::list<CollisionInfo> player_collisions;
2141         
2142         /*
2143                 Get the speed the player is going
2144         */
2145         bool is_climbing = lplayer->is_climbing;
2146         
2147         f32 player_speed = lplayer->getSpeed().getLength();
2148         
2149         /*
2150                 Maximum position increment
2151         */
2152         //f32 position_max_increment = 0.05*BS;
2153         f32 position_max_increment = 0.1*BS;
2154
2155         // Maximum time increment (for collision detection etc)
2156         // time = distance / speed
2157         f32 dtime_max_increment = 1;
2158         if(player_speed > 0.001)
2159                 dtime_max_increment = position_max_increment / player_speed;
2160         
2161         // Maximum time increment is 10ms or lower
2162         if(dtime_max_increment > 0.01)
2163                 dtime_max_increment = 0.01;
2164         
2165         // Don't allow overly huge dtime
2166         if(dtime > 0.5)
2167                 dtime = 0.5;
2168         
2169         f32 dtime_downcount = dtime;
2170
2171         /*
2172                 Stuff that has a maximum time increment
2173         */
2174
2175         u32 loopcount = 0;
2176         do
2177         {
2178                 loopcount++;
2179
2180                 f32 dtime_part;
2181                 if(dtime_downcount > dtime_max_increment)
2182                 {
2183                         dtime_part = dtime_max_increment;
2184                         dtime_downcount -= dtime_part;
2185                 }
2186                 else
2187                 {
2188                         dtime_part = dtime_downcount;
2189                         /*
2190                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
2191                                 when dtime_part is so small that dtime_downcount -= dtime_part
2192                                 does nothing
2193                         */
2194                         dtime_downcount = 0;
2195                 }
2196                 
2197                 /*
2198                         Handle local player
2199                 */
2200                 
2201                 {
2202                         // Apply physics
2203                         if(free_move == false && is_climbing == false)
2204                         {
2205                                 // Gravity
2206                                 v3f speed = lplayer->getSpeed();
2207                                 if(lplayer->in_liquid == false)
2208                                         speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
2209
2210                                 // Liquid floating / sinking
2211                                 if(lplayer->in_liquid && !lplayer->swimming_vertical)
2212                                         speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
2213
2214                                 // Liquid resistance
2215                                 if(lplayer->in_liquid_stable || lplayer->in_liquid)
2216                                 {
2217                                         // How much the node's viscosity blocks movement, ranges between 0 and 1
2218                                         // Should match the scale at which viscosity increase affects other liquid attributes
2219                                         const f32 viscosity_factor = 0.3;
2220
2221                                         v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
2222                                         f32 dl = d_wanted.getLength();
2223                                         if(dl > lplayer->movement_liquid_fluidity_smooth)
2224                                                 dl = lplayer->movement_liquid_fluidity_smooth;
2225                                         dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
2226                                         
2227                                         v3f d = d_wanted.normalize() * dl;
2228                                         speed += d;
2229                                         
2230 #if 0 // old code
2231                                         if(speed.X > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.X -= lplayer->movement_liquid_fluidity_smooth;
2232                                         if(speed.X < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.X += lplayer->movement_liquid_fluidity_smooth;
2233                                         if(speed.Y > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Y -= lplayer->movement_liquid_fluidity_smooth;
2234                                         if(speed.Y < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Y += lplayer->movement_liquid_fluidity_smooth;
2235                                         if(speed.Z > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Z -= lplayer->movement_liquid_fluidity_smooth;
2236                                         if(speed.Z < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Z += lplayer->movement_liquid_fluidity_smooth;
2237 #endif
2238                                 }
2239
2240                                 lplayer->setSpeed(speed);
2241                         }
2242
2243                         /*
2244                                 Move the lplayer.
2245                                 This also does collision detection.
2246                         */
2247                         lplayer->move(dtime_part, this, position_max_increment,
2248                                         &player_collisions);
2249                 }
2250         }
2251         while(dtime_downcount > 0.001);
2252                 
2253         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
2254         
2255         for(std::list<CollisionInfo>::iterator
2256                         i = player_collisions.begin();
2257                         i != player_collisions.end(); ++i)
2258         {
2259                 CollisionInfo &info = *i;
2260                 v3f speed_diff = info.new_speed - info.old_speed;;
2261                 // Handle only fall damage
2262                 // (because otherwise walking against something in fast_move kills you)
2263                 if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
2264                         continue;
2265                 // Get rid of other components
2266                 speed_diff.X = 0;
2267                 speed_diff.Z = 0;
2268                 f32 pre_factor = 1; // 1 hp per node/s
2269                 f32 tolerance = BS*14; // 5 without damage
2270                 f32 post_factor = 1; // 1 hp per node/s
2271                 if(info.type == COLLISION_NODE)
2272                 {
2273                         const ContentFeatures &f = m_gamedef->ndef()->
2274                                         get(m_map->getNodeNoEx(info.node_p));
2275                         // Determine fall damage multiplier
2276                         int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
2277                         pre_factor = 1.0 + (float)addp/100.0;
2278                 }
2279                 float speed = pre_factor * speed_diff.getLength();
2280                 if(speed > tolerance)
2281                 {
2282                         f32 damage_f = (speed - tolerance)/BS * post_factor;
2283                         u16 damage = (u16)(damage_f+0.5);
2284                         if(damage != 0){
2285                                 damageLocalPlayer(damage, true);
2286                                 MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
2287                                 m_gamedef->event()->put(e);
2288                         }
2289                 }
2290         }
2291         
2292         /*
2293                 A quick draft of lava damage
2294         */
2295         if(m_lava_hurt_interval.step(dtime, 1.0))
2296         {
2297                 v3f pf = lplayer->getPosition();
2298                 
2299                 // Feet, middle and head
2300                 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
2301                 MapNode n1 = m_map->getNodeNoEx(p1);
2302                 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
2303                 MapNode n2 = m_map->getNodeNoEx(p2);
2304                 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2305                 MapNode n3 = m_map->getNodeNoEx(p3);
2306
2307                 u32 damage_per_second = 0;
2308                 damage_per_second = MYMAX(damage_per_second,
2309                                 m_gamedef->ndef()->get(n1).damage_per_second);
2310                 damage_per_second = MYMAX(damage_per_second,
2311                                 m_gamedef->ndef()->get(n2).damage_per_second);
2312                 damage_per_second = MYMAX(damage_per_second,
2313                                 m_gamedef->ndef()->get(n3).damage_per_second);
2314                 
2315                 if(damage_per_second != 0)
2316                 {
2317                         damageLocalPlayer(damage_per_second, true);
2318                 }
2319         }
2320
2321         /*
2322                 Drowning
2323         */
2324         if(m_drowning_interval.step(dtime, 2.0))
2325         {
2326                 v3f pf = lplayer->getPosition();
2327
2328                 // head
2329                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2330                 MapNode n = m_map->getNodeNoEx(p);
2331                 ContentFeatures c = m_gamedef->ndef()->get(n);
2332                 u8 drowning_damage = c.drowning;
2333                 if(drowning_damage > 0 && lplayer->hp > 0){
2334                         u16 breath = lplayer->getBreath();
2335                         if(breath > 10){
2336                                 breath = 11;
2337                         }
2338                         if(breath > 0){
2339                                 breath -= 1;
2340                         }
2341                         lplayer->setBreath(breath);
2342                         updateLocalPlayerBreath(breath);
2343                 }
2344
2345                 if(lplayer->getBreath() == 0 && drowning_damage > 0){
2346                         damageLocalPlayer(drowning_damage, true);
2347                 }
2348         }
2349         if(m_breathing_interval.step(dtime, 0.5))
2350         {
2351                 v3f pf = lplayer->getPosition();
2352
2353                 // head
2354                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2355                 MapNode n = m_map->getNodeNoEx(p);
2356                 ContentFeatures c = m_gamedef->ndef()->get(n);
2357                 if (!lplayer->hp){
2358                         lplayer->setBreath(11);
2359                 }
2360                 else if(c.drowning == 0){
2361                         u16 breath = lplayer->getBreath();
2362                         if(breath <= 10){
2363                                 breath += 1;
2364                                 lplayer->setBreath(breath);
2365                                 updateLocalPlayerBreath(breath);
2366                         }
2367                 }
2368         }
2369
2370         /*
2371                 Stuff that can be done in an arbitarily large dtime
2372         */
2373         for(std::list<Player*>::iterator i = m_players.begin();
2374                         i != m_players.end(); ++i)
2375         {
2376                 Player *player = *i;
2377                 
2378                 /*
2379                         Handle non-local players
2380                 */
2381                 if(player->isLocal() == false)
2382                 {
2383                         // Move
2384                         player->move(dtime, *m_map, 100*BS);
2385
2386                 }
2387                 
2388                 // Update lighting on all players on client
2389                 float light = 1.0;
2390                 try{
2391                         // Get node at head
2392                         v3s16 p = player->getLightPosition();
2393                         MapNode n = m_map->getNode(p);
2394                         light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
2395                 }
2396                 catch(InvalidPositionException &e){
2397                         light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
2398                 }
2399                 player->light = light;
2400         }
2401         
2402         /*
2403                 Step active objects and update lighting of them
2404         */
2405         
2406         g_profiler->avg("CEnv: num of objects", m_active_objects.size());
2407         bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
2408         for(std::map<u16, ClientActiveObject*>::iterator
2409                         i = m_active_objects.begin();
2410                         i != m_active_objects.end(); ++i)
2411         {
2412                 ClientActiveObject* obj = i->second;
2413                 // Step object
2414                 obj->step(dtime, this);
2415
2416                 if(update_lighting)
2417                 {
2418                         // Update lighting
2419                         u8 light = 0;
2420                         try{
2421                                 // Get node at head
2422                                 v3s16 p = obj->getLightPosition();
2423                                 MapNode n = m_map->getNode(p);
2424                                 light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2425                         }
2426                         catch(InvalidPositionException &e){
2427                                 light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2428                         }
2429                         obj->updateLight(light);
2430                 }
2431         }
2432
2433         /*
2434                 Step and handle simple objects
2435         */
2436         g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
2437         for(std::list<ClientSimpleObject*>::iterator
2438                         i = m_simple_objects.begin(); i != m_simple_objects.end();)
2439         {
2440                 ClientSimpleObject *simple = *i;
2441                 std::list<ClientSimpleObject*>::iterator cur = i;
2442                 ++i;
2443                 simple->step(dtime);
2444                 if(simple->m_to_be_removed){
2445                         delete simple;
2446                         m_simple_objects.erase(cur);
2447                 }
2448         }
2449 }
2450         
2451 void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
2452 {
2453         m_simple_objects.push_back(simple);
2454 }
2455
2456 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
2457 {
2458         std::map<u16, ClientActiveObject*>::iterator n;
2459         n = m_active_objects.find(id);
2460         if(n == m_active_objects.end())
2461                 return NULL;
2462         return n->second;
2463 }
2464
2465 bool isFreeClientActiveObjectId(u16 id,
2466                 std::map<u16, ClientActiveObject*> &objects)
2467 {
2468         if(id == 0)
2469                 return false;
2470
2471         return objects.find(id) == objects.end();
2472 }
2473
2474 u16 getFreeClientActiveObjectId(
2475                 std::map<u16, ClientActiveObject*> &objects)
2476 {
2477         //try to reuse id's as late as possible
2478         static u16 last_used_id = 0;
2479         u16 startid = last_used_id;
2480         for(;;)
2481         {
2482                 last_used_id ++;
2483                 if(isFreeClientActiveObjectId(last_used_id, objects))
2484                         return last_used_id;
2485                 
2486                 if(last_used_id == startid)
2487                         return 0;
2488         }
2489 }
2490
2491 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
2492 {
2493         assert(object);
2494         if(object->getId() == 0)
2495         {
2496                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
2497                 if(new_id == 0)
2498                 {
2499                         infostream<<"ClientEnvironment::addActiveObject(): "
2500                                         <<"no free ids available"<<std::endl;
2501                         delete object;
2502                         return 0;
2503                 }
2504                 object->setId(new_id);
2505         }
2506         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
2507         {
2508                 infostream<<"ClientEnvironment::addActiveObject(): "
2509                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
2510                 delete object;
2511                 return 0;
2512         }
2513         infostream<<"ClientEnvironment::addActiveObject(): "
2514                         <<"added (id="<<object->getId()<<")"<<std::endl;
2515         m_active_objects[object->getId()] = object;
2516         object->addToScene(m_smgr, m_texturesource, m_irr);
2517         { // Update lighting immediately
2518                 u8 light = 0;
2519                 try{
2520                         // Get node at head
2521                         v3s16 p = object->getLightPosition();
2522                         MapNode n = m_map->getNode(p);
2523                         light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2524                 }
2525                 catch(InvalidPositionException &e){
2526                         light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2527                 }
2528                 object->updateLight(light);
2529         }
2530         return object->getId();
2531 }
2532
2533 void ClientEnvironment::addActiveObject(u16 id, u8 type,
2534                 const std::string &init_data)
2535 {
2536         ClientActiveObject* obj =
2537                         ClientActiveObject::create(type, m_gamedef, this);
2538         if(obj == NULL)
2539         {
2540                 infostream<<"ClientEnvironment::addActiveObject(): "
2541                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
2542                                 <<std::endl;
2543                 return;
2544         }
2545         
2546         obj->setId(id);
2547
2548         try
2549         {
2550                 obj->initialize(init_data);
2551         }
2552         catch(SerializationError &e)
2553         {
2554                 errorstream<<"ClientEnvironment::addActiveObject():"
2555                                 <<" id="<<id<<" type="<<type
2556                                 <<": SerializationError in initialize(): "
2557                                 <<e.what()
2558                                 <<": init_data="<<serializeJsonString(init_data)
2559                                 <<std::endl;
2560         }
2561
2562         addActiveObject(obj);
2563 }
2564
2565 void ClientEnvironment::removeActiveObject(u16 id)
2566 {
2567         verbosestream<<"ClientEnvironment::removeActiveObject(): "
2568                         <<"id="<<id<<std::endl;
2569         ClientActiveObject* obj = getActiveObject(id);
2570         if(obj == NULL)
2571         {
2572                 infostream<<"ClientEnvironment::removeActiveObject(): "
2573                                 <<"id="<<id<<" not found"<<std::endl;
2574                 return;
2575         }
2576         obj->removeFromScene(true);
2577         delete obj;
2578         m_active_objects.erase(id);
2579 }
2580
2581 void ClientEnvironment::processActiveObjectMessage(u16 id,
2582                 const std::string &data)
2583 {
2584         ClientActiveObject* obj = getActiveObject(id);
2585         if(obj == NULL)
2586         {
2587                 infostream<<"ClientEnvironment::processActiveObjectMessage():"
2588                                 <<" got message for id="<<id<<", which doesn't exist."
2589                                 <<std::endl;
2590                 return;
2591         }
2592         try
2593         {
2594                 obj->processMessage(data);
2595         }
2596         catch(SerializationError &e)
2597         {
2598                 errorstream<<"ClientEnvironment::processActiveObjectMessage():"
2599                                 <<" id="<<id<<" type="<<obj->getType()
2600                                 <<" SerializationError in processMessage(),"
2601                                 <<" message="<<serializeJsonString(data)
2602                                 <<std::endl;
2603         }
2604 }
2605
2606 /*
2607         Callbacks for activeobjects
2608 */
2609
2610 void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
2611 {
2612         LocalPlayer *lplayer = getLocalPlayer();
2613         assert(lplayer);
2614         
2615         if(handle_hp){
2616                 if(lplayer->hp > damage)
2617                         lplayer->hp -= damage;
2618                 else
2619                         lplayer->hp = 0;
2620         }
2621
2622         ClientEnvEvent event;
2623         event.type = CEE_PLAYER_DAMAGE;
2624         event.player_damage.amount = damage;
2625         event.player_damage.send_to_server = handle_hp;
2626         m_client_event_queue.push_back(event);
2627 }
2628
2629 void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
2630 {
2631         ClientEnvEvent event;
2632         event.type = CEE_PLAYER_BREATH;
2633         event.player_breath.amount = breath;
2634         m_client_event_queue.push_back(event);
2635 }
2636
2637 /*
2638         Client likes to call these
2639 */
2640         
2641 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
2642                 std::vector<DistanceSortedActiveObject> &dest)
2643 {
2644         for(std::map<u16, ClientActiveObject*>::iterator
2645                         i = m_active_objects.begin();
2646                         i != m_active_objects.end(); ++i)
2647         {
2648                 ClientActiveObject* obj = i->second;
2649
2650                 f32 d = (obj->getPosition() - origin).getLength();
2651
2652                 if(d > max_d)
2653                         continue;
2654
2655                 DistanceSortedActiveObject dso(obj, d);
2656
2657                 dest.push_back(dso);
2658         }
2659 }
2660
2661 ClientEnvEvent ClientEnvironment::getClientEvent()
2662 {
2663         ClientEnvEvent event;
2664         if(m_client_event_queue.empty())
2665                 event.type = CEE_NONE;
2666         else {
2667                 event = m_client_event_queue.front();
2668                 m_client_event_queue.pop_front();
2669         }
2670         return event;
2671 }
2672
2673 #endif // #ifndef SERVER
2674
2675