1d684129d18dc27869a83246aac2c81a117ee791
[oweals/minetest.git] / src / environment.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 "mapgen.h"
29 #include "settings.h"
30 #include "log.h"
31
32 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
33
34 Environment::Environment():
35         m_time_of_day(9000)
36 {
37 }
38
39 Environment::~Environment()
40 {
41         // Deallocate players
42         for(core::list<Player*>::Iterator i = m_players.begin();
43                         i != m_players.end(); i++)
44         {
45                 delete (*i);
46         }
47 }
48
49 void Environment::addPlayer(Player *player)
50 {
51         DSTACK(__FUNCTION_NAME);
52         /*
53                 Check that peer_ids are unique.
54                 Also check that names are unique.
55                 Exception: there can be multiple players with peer_id=0
56         */
57         // If peer id is non-zero, it has to be unique.
58         if(player->peer_id != 0)
59                 assert(getPlayer(player->peer_id) == NULL);
60         // Name has to be unique.
61         assert(getPlayer(player->getName()) == NULL);
62         // Add.
63         m_players.push_back(player);
64 }
65
66 void Environment::removePlayer(u16 peer_id)
67 {
68         DSTACK(__FUNCTION_NAME);
69 re_search:
70         for(core::list<Player*>::Iterator i = m_players.begin();
71                         i != m_players.end(); i++)
72         {
73                 Player *player = *i;
74                 if(player->peer_id != peer_id)
75                         continue;
76                 
77                 delete player;
78                 m_players.erase(i);
79                 // See if there is an another one
80                 // (shouldn't be, but just to be sure)
81                 goto re_search;
82         }
83 }
84
85 Player * Environment::getPlayer(u16 peer_id)
86 {
87         for(core::list<Player*>::Iterator i = m_players.begin();
88                         i != m_players.end(); i++)
89         {
90                 Player *player = *i;
91                 if(player->peer_id == peer_id)
92                         return player;
93         }
94         return NULL;
95 }
96
97 Player * Environment::getPlayer(const char *name)
98 {
99         for(core::list<Player*>::Iterator i = m_players.begin();
100                         i != m_players.end(); i++)
101         {
102                 Player *player = *i;
103                 if(strcmp(player->getName(), name) == 0)
104                         return player;
105         }
106         return NULL;
107 }
108
109 Player * Environment::getRandomConnectedPlayer()
110 {
111         core::list<Player*> connected_players = getPlayers(true);
112         u32 chosen_one = myrand() % connected_players.size();
113         u32 j = 0;
114         for(core::list<Player*>::Iterator
115                         i = connected_players.begin();
116                         i != connected_players.end(); i++)
117         {
118                 if(j == chosen_one)
119                 {
120                         Player *player = *i;
121                         return player;
122                 }
123                 j++;
124         }
125         return NULL;
126 }
127
128 Player * Environment::getNearestConnectedPlayer(v3f pos)
129 {
130         core::list<Player*> connected_players = getPlayers(true);
131         f32 nearest_d = 0;
132         Player *nearest_player = NULL;
133         for(core::list<Player*>::Iterator
134                         i = connected_players.begin();
135                         i != connected_players.end(); i++)
136         {
137                 Player *player = *i;
138                 f32 d = player->getPosition().getDistanceFrom(pos);
139                 if(d < nearest_d || nearest_player == NULL)
140                 {
141                         nearest_d = d;
142                         nearest_player = player;
143                 }
144         }
145         return nearest_player;
146 }
147
148 core::list<Player*> Environment::getPlayers()
149 {
150         return m_players;
151 }
152
153 core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
154 {
155         core::list<Player*> newlist;
156         for(core::list<Player*>::Iterator
157                         i = m_players.begin();
158                         i != m_players.end(); i++)
159         {
160                 Player *player = *i;
161                 
162                 if(ignore_disconnected)
163                 {
164                         // Ignore disconnected players
165                         if(player->peer_id == 0)
166                                 continue;
167                 }
168
169                 newlist.push_back(player);
170         }
171         return newlist;
172 }
173
174 void Environment::printPlayers(std::ostream &o)
175 {
176         o<<"Players in environment:"<<std::endl;
177         for(core::list<Player*>::Iterator i = m_players.begin();
178                         i != m_players.end(); i++)
179         {
180                 Player *player = *i;
181                 o<<"Player peer_id="<<player->peer_id<<std::endl;
182         }
183 }
184
185 /*void Environment::setDayNightRatio(u32 r)
186 {
187         getDayNightRatio() = r;
188 }*/
189
190 u32 Environment::getDayNightRatio()
191 {
192         //return getDayNightRatio();
193         return time_to_daynight_ratio(m_time_of_day);
194 }
195
196 /*
197         ActiveBlockList
198 */
199
200 void fillRadiusBlock(v3s16 p0, s16 r, core::map<v3s16, bool> &list)
201 {
202         v3s16 p;
203         for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
204         for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
205         for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
206         {
207                 // Set in list
208                 list[p] = true;
209         }
210 }
211
212 void ActiveBlockList::update(core::list<v3s16> &active_positions,
213                 s16 radius,
214                 core::map<v3s16, bool> &blocks_removed,
215                 core::map<v3s16, bool> &blocks_added)
216 {
217         /*
218                 Create the new list
219         */
220         core::map<v3s16, bool> newlist;
221         for(core::list<v3s16>::Iterator i = active_positions.begin();
222                         i != active_positions.end(); i++)
223         {
224                 fillRadiusBlock(*i, radius, newlist);
225         }
226
227         /*
228                 Find out which blocks on the old list are not on the new list
229         */
230         // Go through old list
231         for(core::map<v3s16, bool>::Iterator i = m_list.getIterator();
232                         i.atEnd()==false; i++)
233         {
234                 v3s16 p = i.getNode()->getKey();
235                 // If not on new list, it's been removed
236                 if(newlist.find(p) == NULL)
237                         blocks_removed.insert(p, true);
238         }
239
240         /*
241                 Find out which blocks on the new list are not on the old list
242         */
243         // Go through new list
244         for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
245                         i.atEnd()==false; i++)
246         {
247                 v3s16 p = i.getNode()->getKey();
248                 // If not on old list, it's been added
249                 if(m_list.find(p) == NULL)
250                         blocks_added.insert(p, true);
251         }
252
253         /*
254                 Update m_list
255         */
256         m_list.clear();
257         for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
258                         i.atEnd()==false; i++)
259         {
260                 v3s16 p = i.getNode()->getKey();
261                 m_list.insert(p, true);
262         }
263 }
264
265 /*
266         ServerEnvironment
267 */
268
269 ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server):
270         m_map(map),
271         m_server(server),
272         m_random_spawn_timer(3),
273         m_send_recommended_timer(0),
274         m_game_time(0),
275         m_game_time_fraction_counter(0)
276 {
277 }
278
279 ServerEnvironment::~ServerEnvironment()
280 {
281         // Clear active block list.
282         // This makes the next one delete all active objects.
283         m_active_blocks.clear();
284
285         // Convert all objects to static and delete the active objects
286         deactivateFarObjects(true);
287
288         // Drop/delete map
289         m_map->drop();
290 }
291
292 void ServerEnvironment::serializePlayers(const std::string &savedir)
293 {
294         std::string players_path = savedir + "/players";
295         fs::CreateDir(players_path);
296
297         core::map<Player*, bool> saved_players;
298
299         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
300         for(u32 i=0; i<player_files.size(); i++)
301         {
302                 if(player_files[i].dir)
303                         continue;
304                 
305                 // Full path to this file
306                 std::string path = players_path + "/" + player_files[i].name;
307
308                 //infostream<<"Checking player file "<<path<<std::endl;
309
310                 // Load player to see what is its name
311                 ServerRemotePlayer testplayer;
312                 {
313                         // Open file and deserialize
314                         std::ifstream is(path.c_str(), std::ios_base::binary);
315                         if(is.good() == false)
316                         {
317                                 infostream<<"Failed to read "<<path<<std::endl;
318                                 continue;
319                         }
320                         testplayer.deSerialize(is);
321                 }
322
323                 //infostream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
324                 
325                 // Search for the player
326                 std::string playername = testplayer.getName();
327                 Player *player = getPlayer(playername.c_str());
328                 if(player == NULL)
329                 {
330                         infostream<<"Didn't find matching player, ignoring file "<<path<<std::endl;
331                         continue;
332                 }
333
334                 //infostream<<"Found matching player, overwriting."<<std::endl;
335
336                 // OK, found. Save player there.
337                 {
338                         // Open file and serialize
339                         std::ofstream os(path.c_str(), std::ios_base::binary);
340                         if(os.good() == false)
341                         {
342                                 infostream<<"Failed to overwrite "<<path<<std::endl;
343                                 continue;
344                         }
345                         player->serialize(os);
346                         saved_players.insert(player, true);
347                 }
348         }
349
350         for(core::list<Player*>::Iterator i = m_players.begin();
351                         i != m_players.end(); i++)
352         {
353                 Player *player = *i;
354                 if(saved_players.find(player) != NULL)
355                 {
356                         /*infostream<<"Player "<<player->getName()
357                                         <<" was already saved."<<std::endl;*/
358                         continue;
359                 }
360                 std::string playername = player->getName();
361                 // Don't save unnamed player
362                 if(playername == "")
363                 {
364                         //infostream<<"Not saving unnamed player."<<std::endl;
365                         continue;
366                 }
367                 /*
368                         Find a sane filename
369                 */
370                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
371                         playername = "player";
372                 std::string path = players_path + "/" + playername;
373                 bool found = false;
374                 for(u32 i=0; i<1000; i++)
375                 {
376                         if(fs::PathExists(path) == false)
377                         {
378                                 found = true;
379                                 break;
380                         }
381                         path = players_path + "/" + playername + itos(i);
382                 }
383                 if(found == false)
384                 {
385                         infostream<<"Didn't find free file for player"<<std::endl;
386                         continue;
387                 }
388
389                 {
390                         /*infostream<<"Saving player "<<player->getName()<<" to "
391                                         <<path<<std::endl;*/
392                         // Open file and serialize
393                         std::ofstream os(path.c_str(), std::ios_base::binary);
394                         if(os.good() == false)
395                         {
396                                 infostream<<"Failed to overwrite "<<path<<std::endl;
397                                 continue;
398                         }
399                         player->serialize(os);
400                         saved_players.insert(player, true);
401                 }
402         }
403
404         //infostream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
405 }
406
407 void ServerEnvironment::deSerializePlayers(const std::string &savedir)
408 {
409         std::string players_path = savedir + "/players";
410
411         core::map<Player*, bool> saved_players;
412
413         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
414         for(u32 i=0; i<player_files.size(); i++)
415         {
416                 if(player_files[i].dir)
417                         continue;
418                 
419                 // Full path to this file
420                 std::string path = players_path + "/" + player_files[i].name;
421
422                 infostream<<"Checking player file "<<path<<std::endl;
423
424                 // Load player to see what is its name
425                 ServerRemotePlayer testplayer;
426                 {
427                         // Open file and deserialize
428                         std::ifstream is(path.c_str(), std::ios_base::binary);
429                         if(is.good() == false)
430                         {
431                                 infostream<<"Failed to read "<<path<<std::endl;
432                                 continue;
433                         }
434                         testplayer.deSerialize(is);
435                 }
436
437                 if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS))
438                 {
439                         infostream<<"Not loading player with invalid name: "
440                                         <<testplayer.getName()<<std::endl;
441                 }
442
443                 infostream<<"Loaded test player with name "<<testplayer.getName()
444                                 <<std::endl;
445                 
446                 // Search for the player
447                 std::string playername = testplayer.getName();
448                 Player *player = getPlayer(playername.c_str());
449                 bool newplayer = false;
450                 if(player == NULL)
451                 {
452                         infostream<<"Is a new player"<<std::endl;
453                         player = new ServerRemotePlayer();
454                         newplayer = true;
455                 }
456
457                 // Load player
458                 {
459                         infostream<<"Reading player "<<testplayer.getName()<<" from "
460                                         <<path<<std::endl;
461                         // Open file and deserialize
462                         std::ifstream is(path.c_str(), std::ios_base::binary);
463                         if(is.good() == false)
464                         {
465                                 infostream<<"Failed to read "<<path<<std::endl;
466                                 continue;
467                         }
468                         player->deSerialize(is);
469                 }
470
471                 if(newplayer)
472                         addPlayer(player);
473         }
474 }
475
476 void ServerEnvironment::saveMeta(const std::string &savedir)
477 {
478         std::string path = savedir + "/env_meta.txt";
479
480         // Open file and serialize
481         std::ofstream os(path.c_str(), std::ios_base::binary);
482         if(os.good() == false)
483         {
484                 infostream<<"ServerEnvironment::saveMeta(): Failed to open "
485                                 <<path<<std::endl;
486                 throw SerializationError("Couldn't save env meta");
487         }
488
489         Settings args;
490         args.setU64("game_time", m_game_time);
491         args.setU64("time_of_day", getTimeOfDay());
492         args.writeLines(os);
493         os<<"EnvArgsEnd\n";
494 }
495
496 void ServerEnvironment::loadMeta(const std::string &savedir)
497 {
498         std::string path = savedir + "/env_meta.txt";
499
500         // Open file and deserialize
501         std::ifstream is(path.c_str(), std::ios_base::binary);
502         if(is.good() == false)
503         {
504                 infostream<<"ServerEnvironment::loadMeta(): Failed to open "
505                                 <<path<<std::endl;
506                 throw SerializationError("Couldn't load env meta");
507         }
508
509         Settings args;
510         
511         for(;;)
512         {
513                 if(is.eof())
514                         throw SerializationError
515                                         ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
516                 std::string line;
517                 std::getline(is, line);
518                 std::string trimmedline = trim(line);
519                 if(trimmedline == "EnvArgsEnd")
520                         break;
521                 args.parseConfigLine(line);
522         }
523         
524         try{
525                 m_game_time = args.getU64("game_time");
526         }catch(SettingNotFoundException &e){
527                 // Getting this is crucial, otherwise timestamps are useless
528                 throw SerializationError("Couldn't load env meta game_time");
529         }
530
531         try{
532                 m_time_of_day = args.getU64("time_of_day");
533         }catch(SettingNotFoundException &e){
534                 // This is not as important
535                 m_time_of_day = 9000;
536         }
537 }
538
539 #if 0
540 // This is probably very useless
541 void spawnRandomObjects(MapBlock *block)
542 {
543         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
544         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
545         {
546                 bool last_node_walkable = false;
547                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
548                 {
549                         v3s16 p(x0,y0,z0);
550                         MapNode n = block->getNodeNoEx(p);
551                         if(n.getContent() == CONTENT_IGNORE)
552                                 continue;
553                         if(content_features(n).liquid_type != LIQUID_NONE)
554                                 continue;
555                         if(content_features(n).walkable)
556                         {
557                                 last_node_walkable = true;
558                                 continue;
559                         }
560                         if(last_node_walkable)
561                         {
562                                 // If block contains light information
563                                 if(content_features(n).param_type == CPT_LIGHT)
564                                 {
565                                         if(n.getLight(LIGHTBANK_DAY) <= 5)
566                                         {
567                                                 if(myrand() % 1000 == 0)
568                                                 {
569                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
570                                                         pos_f.Y -= BS*0.4;
571                                                         ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
572                                                         std::string data = obj->getStaticData();
573                                                         StaticObject s_obj(obj->getType(),
574                                                                         obj->getBasePosition(), data);
575                                                         // Add one
576                                                         block->m_static_objects.insert(0, s_obj);
577                                                         delete obj;
578                                                         block->setChangedFlag();
579                                                 }
580                                         }
581                                 }
582                         }
583                         last_node_walkable = false;
584                 }
585         }
586 }
587 #endif
588
589 void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
590 {
591         // Get time difference
592         u32 dtime_s = 0;
593         u32 stamp = block->getTimestamp();
594         if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
595                 dtime_s = m_game_time - block->getTimestamp();
596         dtime_s += additional_dtime;
597
598         // Set current time as timestamp (and let it set ChangedFlag)
599         block->setTimestamp(m_game_time);
600
601         //infostream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
602         
603         // Activate stored objects
604         activateObjects(block);
605
606         // Run node metadata
607         bool changed = block->m_node_metadata.step((float)dtime_s);
608         if(changed)
609         {
610                 MapEditEvent event;
611                 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
612                 event.p = block->getPos();
613                 m_map->dispatchEvent(&event);
614
615                 block->setChangedFlag();
616         }
617
618         // TODO: Do something
619         // TODO: Implement usage of ActiveBlockModifier
620         
621         // Here's a quick demonstration
622         v3s16 p0;
623         for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
624         for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
625         for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
626         {
627                 v3s16 p = p0 + block->getPosRelative();
628                 MapNode n = block->getNodeNoEx(p0);
629 #if 1
630                 // Test something:
631                 // Convert all mud under proper day lighting to grass
632                 if(n.getContent() == CONTENT_MUD)
633                 {
634                         if(dtime_s > 300)
635                         {
636                                 MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
637                                 if(content_features(n_top).air_equivalent &&
638                                                 n_top.getLight(LIGHTBANK_DAY) >= 13)
639                                 {
640                                         n.setContent(CONTENT_GRASS);
641                                         m_map->addNodeWithEvent(p, n);
642                                 }
643                         }
644                 }
645 #endif
646         }
647 }
648
649 static void getMob_dungeon_master(Settings &properties)
650 {
651         properties.set("looks", "dungeon_master");
652         properties.setFloat("yaw", 1.57);
653         properties.setFloat("hp", 30);
654         properties.setBool("bright_shooting", true);
655         properties.set("shoot_type", "fireball");
656         properties.set("shoot_y", "0.7");
657         properties.set("player_hit_damage", "1");
658         properties.set("player_hit_distance", "1.0");
659         properties.set("player_hit_interval", "0.5");
660 }
661
662 void ServerEnvironment::step(float dtime)
663 {
664         DSTACK(__FUNCTION_NAME);
665         
666         //TimeTaker timer("ServerEnv step");
667
668         // Get some settings
669         bool footprints = g_settings->getBool("footprints");
670
671         /*
672                 Increment game time
673         */
674         {
675                 m_game_time_fraction_counter += dtime;
676                 u32 inc_i = (u32)m_game_time_fraction_counter;
677                 m_game_time += inc_i;
678                 m_game_time_fraction_counter -= (float)inc_i;
679         }
680         
681         /*
682                 Handle players
683         */
684         for(core::list<Player*>::Iterator i = m_players.begin();
685                         i != m_players.end(); i++)
686         {
687                 Player *player = *i;
688                 
689                 // Ignore disconnected players
690                 if(player->peer_id == 0)
691                         continue;
692
693                 v3f playerpos = player->getPosition();
694                 
695                 // Move
696                 player->move(dtime, *m_map, 100*BS);
697                 
698                 /*
699                         Add footsteps to grass
700                 */
701                 if(footprints)
702                 {
703                         // Get node that is at BS/4 under player
704                         v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
705                         try{
706                                 MapNode n = m_map->getNode(bottompos);
707                                 if(n.getContent() == CONTENT_GRASS)
708                                 {
709                                         n.setContent(CONTENT_GRASS_FOOTSTEPS);
710                                         m_map->setNode(bottompos, n);
711                                 }
712                         }
713                         catch(InvalidPositionException &e)
714                         {
715                         }
716                 }
717         }
718
719         /*
720                 Manage active block list
721         */
722         if(m_active_blocks_management_interval.step(dtime, 2.0))
723         {
724                 /*
725                         Get player block positions
726                 */
727                 core::list<v3s16> players_blockpos;
728                 for(core::list<Player*>::Iterator
729                                 i = m_players.begin();
730                                 i != m_players.end(); i++)
731                 {
732                         Player *player = *i;
733                         // Ignore disconnected players
734                         if(player->peer_id == 0)
735                                 continue;
736                         v3s16 blockpos = getNodeBlockPos(
737                                         floatToInt(player->getPosition(), BS));
738                         players_blockpos.push_back(blockpos);
739                 }
740                 
741                 /*
742                         Update list of active blocks, collecting changes
743                 */
744                 const s16 active_block_range = g_settings->getS16("active_block_range");
745                 core::map<v3s16, bool> blocks_removed;
746                 core::map<v3s16, bool> blocks_added;
747                 m_active_blocks.update(players_blockpos, active_block_range,
748                                 blocks_removed, blocks_added);
749
750                 /*
751                         Handle removed blocks
752                 */
753
754                 // Convert active objects that are no more in active blocks to static
755                 deactivateFarObjects(false);
756                 
757                 for(core::map<v3s16, bool>::Iterator
758                                 i = blocks_removed.getIterator();
759                                 i.atEnd()==false; i++)
760                 {
761                         v3s16 p = i.getNode()->getKey();
762
763                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
764                                         <<") became inactive"<<std::endl;*/
765                         
766                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
767                         if(block==NULL)
768                                 continue;
769                         
770                         // Set current time as timestamp (and let it set ChangedFlag)
771                         block->setTimestamp(m_game_time);
772                 }
773
774                 /*
775                         Handle added blocks
776                 */
777
778                 for(core::map<v3s16, bool>::Iterator
779                                 i = blocks_added.getIterator();
780                                 i.atEnd()==false; i++)
781                 {
782                         v3s16 p = i.getNode()->getKey();
783                         
784                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
785                                         <<") became active"<<std::endl;*/
786
787                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
788                         if(block==NULL)
789                                 continue;
790
791                         activateBlock(block);
792                 }
793         }
794
795         /*
796                 Mess around in active blocks
797         */
798         if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
799         {
800                 float dtime = 1.0;
801
802                 for(core::map<v3s16, bool>::Iterator
803                                 i = m_active_blocks.m_list.getIterator();
804                                 i.atEnd()==false; i++)
805                 {
806                         v3s16 p = i.getNode()->getKey();
807                         
808                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
809                                         <<") being handled"<<std::endl;*/
810
811                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
812                         if(block==NULL)
813                                 continue;
814
815                         // Reset block usage timer
816                         block->resetUsageTimer();
817                         
818                         // Set current time as timestamp
819                         block->setTimestampNoChangedFlag(m_game_time);
820
821                         // Run node metadata
822                         bool changed = block->m_node_metadata.step(dtime);
823                         if(changed)
824                         {
825                                 MapEditEvent event;
826                                 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
827                                 event.p = p;
828                                 m_map->dispatchEvent(&event);
829
830                                 block->setChangedFlag();
831                         }
832                 }
833         }
834         if(m_active_blocks_test_interval.step(dtime, 10.0))
835         {
836                 //float dtime = 10.0;
837                 
838                 for(core::map<v3s16, bool>::Iterator
839                                 i = m_active_blocks.m_list.getIterator();
840                                 i.atEnd()==false; i++)
841                 {
842                         v3s16 p = i.getNode()->getKey();
843                         
844                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
845                                         <<") being handled"<<std::endl;*/
846
847                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
848                         if(block==NULL)
849                                 continue;
850                         
851                         // Set current time as timestamp
852                         block->setTimestampNoChangedFlag(m_game_time);
853
854                         /*
855                                 Do stuff!
856
857                                 Note that map modifications should be done using the event-
858                                 making map methods so that the server gets information
859                                 about them.
860
861                                 Reading can be done quickly directly from the block.
862
863                                 Everything should bind to inside this single content
864                                 searching loop to keep things fast.
865                         */
866                         // TODO: Implement usage of ActiveBlockModifier
867                         
868                         // Find out how many objects the block contains
869                         u32 active_object_count = block->m_static_objects.m_active.size();
870                         // Find out how many objects this and all the neighbors contain
871                         u32 active_object_count_wider = 0;
872                         for(s16 x=-1; x<=1; x++)
873                         for(s16 y=-1; y<=1; y++)
874                         for(s16 z=-1; z<=1; z++)
875                         {
876                                 MapBlock *block = m_map->getBlockNoCreateNoEx(p+v3s16(x,y,z));
877                                 if(block==NULL)
878                                         continue;
879                                 active_object_count_wider +=
880                                                 block->m_static_objects.m_active.size();
881                         }
882
883                         v3s16 p0;
884                         for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
885                         for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
886                         for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
887                         {
888                                 v3s16 p = p0 + block->getPosRelative();
889                                 MapNode n = block->getNodeNoEx(p0);
890
891                                 /*
892                                         Test something:
893                                         Convert mud under proper lighting to grass
894                                 */
895                                 if(n.getContent() == CONTENT_MUD)
896                                 {
897                                         if(myrand()%20 == 0)
898                                         {
899                                                 MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
900                                                 if(content_features(n_top).air_equivalent &&
901                                                                 n_top.getLightBlend(getDayNightRatio()) >= 13)
902                                                 {
903                                                         n.setContent(CONTENT_GRASS);
904                                                         m_map->addNodeWithEvent(p, n);
905                                                 }
906                                         }
907                                 }
908                                 /*
909                                         Convert grass into mud if under something else than air
910                                 */
911                                 if(n.getContent() == CONTENT_GRASS)
912                                 {
913                                         //if(myrand()%20 == 0)
914                                         {
915                                                 MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
916                                                 if(content_features(n_top).air_equivalent == false)
917                                                 {
918                                                         n.setContent(CONTENT_MUD);
919                                                         m_map->addNodeWithEvent(p, n);
920                                                 }
921                                         }
922                                 }
923                                 /*
924                                         Rats spawn around regular trees
925                                 */
926                                 if(n.getContent() == CONTENT_TREE ||
927                                                 n.getContent() == CONTENT_JUNGLETREE)
928                                 {
929                                         if(myrand()%200 == 0 && active_object_count_wider == 0)
930                                         {
931                                                 v3s16 p1 = p + v3s16(myrand_range(-2, 2),
932                                                                 0, myrand_range(-2, 2));
933                                                 MapNode n1 = m_map->getNodeNoEx(p1);
934                                                 MapNode n1b = m_map->getNodeNoEx(p1+v3s16(0,-1,0));
935                                                 if(n1b.getContent() == CONTENT_GRASS &&
936                                                                 n1.getContent() == CONTENT_AIR)
937                                                 {
938                                                         v3f pos = intToFloat(p1, BS);
939                                                         ServerActiveObject *obj = new RatSAO(this, 0, pos);
940                                                         addActiveObject(obj);
941                                                 }
942                                         }
943                                 }
944                                 /*
945                                         Fun things spawn in caves and dungeons
946                                 */
947                                 if(n.getContent() == CONTENT_STONE ||
948                                                 n.getContent() == CONTENT_MOSSYCOBBLE)
949                                 {
950                                         if(myrand()%200 == 0 && active_object_count_wider == 0)
951                                         {
952                                                 v3s16 p1 = p + v3s16(0,1,0);
953                                                 MapNode n1a = m_map->getNodeNoEx(p1+v3s16(0,0,0));
954                                                 if(n1a.getLightBlend(getDayNightRatio()) <= 3){
955                                                         MapNode n1b = m_map->getNodeNoEx(p1+v3s16(0,1,0));
956                                                         if(n1a.getContent() == CONTENT_AIR &&
957                                                                         n1b.getContent() == CONTENT_AIR)
958                                                         {
959                                                                 v3f pos = intToFloat(p1, BS);
960                                                                 int i = myrand()%5;
961                                                                 if(i == 0 || i == 1){
962                                                                         actionstream<<"A dungeon master spawns at "
963                                                                                         <<PP(p1)<<std::endl;
964                                                                         Settings properties;
965                                                                         getMob_dungeon_master(properties);
966                                                                         ServerActiveObject *obj = new MobV2SAO(
967                                                                                         this, 0, pos, &properties);
968                                                                         addActiveObject(obj);
969                                                                 } else if(i == 2 || i == 3){
970                                                                         actionstream<<"Rats spawn at "
971                                                                                         <<PP(p1)<<std::endl;
972                                                                         for(int j=0; j<3; j++){
973                                                                                 ServerActiveObject *obj = new RatSAO(
974                                                                                                 this, 0, pos);
975                                                                                 addActiveObject(obj);
976                                                                         }
977                                                                 } else {
978                                                                         actionstream<<"An oerkki spawns at "
979                                                                                         <<PP(p1)<<std::endl;
980                                                                         ServerActiveObject *obj = new Oerkki1SAO(
981                                                                                         this, 0, pos);
982                                                                         addActiveObject(obj);
983                                                                 }
984                                                         }
985                                                 }
986                                         }
987                                 }
988                                 /*
989                                         Make trees from saplings!
990                                 */
991                                 if(n.getContent() == CONTENT_SAPLING)
992                                 {
993                                         if(myrand()%50 == 0)
994                                         {
995                                                 actionstream<<"A sapling grows into a tree at "
996                                                                 <<PP(p)<<std::endl;
997
998                                                 core::map<v3s16, MapBlock*> modified_blocks;
999                                                 v3s16 tree_p = p;
1000                                                 ManualMapVoxelManipulator vmanip(m_map);
1001                                                 v3s16 tree_blockp = getNodeBlockPos(tree_p);
1002                                                 vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
1003                                                 bool is_apple_tree = myrand()%4 == 0;
1004                                                 mapgen::make_tree(vmanip, tree_p, is_apple_tree);
1005                                                 vmanip.blitBackAll(&modified_blocks);
1006
1007                                                 // update lighting
1008                                                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1009                                                 for(core::map<v3s16, MapBlock*>::Iterator
1010                                                         i = modified_blocks.getIterator();
1011                                                         i.atEnd() == false; i++)
1012                                                 {
1013                                                         lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
1014                                                 }
1015                                                 m_map->updateLighting(lighting_modified_blocks, modified_blocks);
1016
1017                                                 // Send a MEET_OTHER event
1018                                                 MapEditEvent event;
1019                                                 event.type = MEET_OTHER;
1020                                                 for(core::map<v3s16, MapBlock*>::Iterator
1021                                                         i = modified_blocks.getIterator();
1022                                                         i.atEnd() == false; i++)
1023                                                 {
1024                                                         v3s16 p = i.getNode()->getKey();
1025                                                         event.modified_blocks.insert(p, true);
1026                                                 }
1027                                                 m_map->dispatchEvent(&event);
1028                                         }
1029                                 }
1030                         }
1031                 }
1032         }
1033         
1034         /*
1035                 Step active objects
1036         */
1037         {
1038                 //TimeTaker timer("Step active objects");
1039                 
1040                 // This helps the objects to send data at the same time
1041                 bool send_recommended = false;
1042                 m_send_recommended_timer += dtime;
1043                 if(m_send_recommended_timer > 0.10)
1044                 {
1045                         m_send_recommended_timer = 0;
1046                         send_recommended = true;
1047                 }
1048
1049                 for(core::map<u16, ServerActiveObject*>::Iterator
1050                                 i = m_active_objects.getIterator();
1051                                 i.atEnd()==false; i++)
1052                 {
1053                         ServerActiveObject* obj = i.getNode()->getValue();
1054                         // Remove non-peaceful mobs on peaceful mode
1055                         if(g_settings->getBool("only_peaceful_mobs")){
1056                                 if(!obj->isPeaceful())
1057                                         obj->m_removed = true;
1058                         }
1059                         // Don't step if is to be removed or stored statically
1060                         if(obj->m_removed || obj->m_pending_deactivation)
1061                                 continue;
1062                         // Step object
1063                         obj->step(dtime, send_recommended);
1064                         // Read messages from object
1065                         while(obj->m_messages_out.size() > 0)
1066                         {
1067                                 m_active_object_messages.push_back(
1068                                                 obj->m_messages_out.pop_front());
1069                         }
1070                 }
1071         }
1072         
1073         /*
1074                 Manage active objects
1075         */
1076         if(m_object_management_interval.step(dtime, 0.5))
1077         {
1078                 /*
1079                         Remove objects that satisfy (m_removed && m_known_by_count==0)
1080                 */
1081                 removeRemovedObjects();
1082         }
1083
1084         if(g_settings->getBool("enable_experimental"))
1085         {
1086
1087         /*
1088                 TEST CODE
1089         */
1090 #if 0
1091         m_random_spawn_timer -= dtime;
1092         if(m_random_spawn_timer < 0)
1093         {
1094                 //m_random_spawn_timer += myrand_range(2.0, 20.0);
1095                 //m_random_spawn_timer += 2.0;
1096                 m_random_spawn_timer += 200.0;
1097
1098                 /*
1099                         Find some position
1100                 */
1101
1102                 /*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
1103                 s16 y = 1 + getServerMap().findGroundLevel(p2d);
1104                 v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
1105                 
1106                 Player *player = getRandomConnectedPlayer();
1107                 v3f pos(0,0,0);
1108                 if(player)
1109                         pos = player->getPosition();
1110                 pos += v3f(
1111                         myrand_range(-3,3)*BS,
1112                         5,
1113                         myrand_range(-3,3)*BS
1114                 );
1115
1116                 /*
1117                         Create a ServerActiveObject
1118                 */
1119
1120                 //TestSAO *obj = new TestSAO(this, 0, pos);
1121                 //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
1122                 //ServerActiveObject *obj = new RatSAO(this, 0, pos);
1123                 //ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
1124                 //ServerActiveObject *obj = new FireflySAO(this, 0, pos);
1125
1126                 infostream<<"Server: Spawning MobV2SAO at "
1127                                 <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
1128                 
1129                 Settings properties;
1130                 getMob_dungeon_master(properties);
1131                 ServerActiveObject *obj = new MobV2SAO(this, 0, pos, &properties);
1132                 addActiveObject(obj);
1133         }
1134 #endif
1135
1136         } // enable_experimental
1137 }
1138
1139 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
1140 {
1141         core::map<u16, ServerActiveObject*>::Node *n;
1142         n = m_active_objects.find(id);
1143         if(n == NULL)
1144                 return NULL;
1145         return n->getValue();
1146 }
1147
1148 bool isFreeServerActiveObjectId(u16 id,
1149                 core::map<u16, ServerActiveObject*> &objects)
1150 {
1151         if(id == 0)
1152                 return false;
1153         
1154         for(core::map<u16, ServerActiveObject*>::Iterator
1155                         i = objects.getIterator();
1156                         i.atEnd()==false; i++)
1157         {
1158                 if(i.getNode()->getKey() == id)
1159                         return false;
1160         }
1161         return true;
1162 }
1163
1164 u16 getFreeServerActiveObjectId(
1165                 core::map<u16, ServerActiveObject*> &objects)
1166 {
1167         u16 new_id = 1;
1168         for(;;)
1169         {
1170                 if(isFreeServerActiveObjectId(new_id, objects))
1171                         return new_id;
1172                 
1173                 if(new_id == 65535)
1174                         return 0;
1175
1176                 new_id++;
1177         }
1178 }
1179
1180 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1181 {
1182         assert(object);
1183         u16 id = addActiveObjectRaw(object, true);
1184         return id;
1185 }
1186
1187 bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
1188 {
1189         assert(obj);
1190
1191         v3f objectpos = obj->getBasePosition(); 
1192
1193         // The block in which the object resides in
1194         v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1195
1196         /*
1197                 Update the static data
1198         */
1199
1200         // Create new static object
1201         std::string staticdata = obj->getStaticData();
1202         StaticObject s_obj(obj->getType(), objectpos, staticdata);
1203         // Add to the block where the object is located in
1204         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1205         // Get or generate the block
1206         MapBlock *block = m_map->emergeBlock(blockpos);
1207
1208         bool succeeded = false;
1209
1210         if(block)
1211         {
1212                 block->m_static_objects.insert(0, s_obj);
1213                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD);
1214                 succeeded = true;
1215         }
1216         else{
1217                 infostream<<"ServerEnvironment::addActiveObjectAsStatic: "
1218                                 <<"Could not find or generate "
1219                                 <<"a block for storing static object"<<std::endl;
1220                 succeeded = false;
1221         }
1222
1223         delete obj;
1224
1225         return succeeded;
1226 }
1227
1228 /*
1229         Finds out what new objects have been added to
1230         inside a radius around a position
1231 */
1232 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1233                 core::map<u16, bool> &current_objects,
1234                 core::map<u16, bool> &added_objects)
1235 {
1236         v3f pos_f = intToFloat(pos, BS);
1237         f32 radius_f = radius * BS;
1238         /*
1239                 Go through the object list,
1240                 - discard m_removed objects,
1241                 - discard objects that are too far away,
1242                 - discard objects that are found in current_objects.
1243                 - add remaining objects to added_objects
1244         */
1245         for(core::map<u16, ServerActiveObject*>::Iterator
1246                         i = m_active_objects.getIterator();
1247                         i.atEnd()==false; i++)
1248         {
1249                 u16 id = i.getNode()->getKey();
1250                 // Get object
1251                 ServerActiveObject *object = i.getNode()->getValue();
1252                 if(object == NULL)
1253                         continue;
1254                 // Discard if removed
1255                 if(object->m_removed)
1256                         continue;
1257                 // Discard if too far
1258                 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1259                 if(distance_f > radius_f)
1260                         continue;
1261                 // Discard if already on current_objects
1262                 core::map<u16, bool>::Node *n;
1263                 n = current_objects.find(id);
1264                 if(n != NULL)
1265                         continue;
1266                 // Add to added_objects
1267                 added_objects.insert(id, false);
1268         }
1269 }
1270
1271 /*
1272         Finds out what objects have been removed from
1273         inside a radius around a position
1274 */
1275 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1276                 core::map<u16, bool> &current_objects,
1277                 core::map<u16, bool> &removed_objects)
1278 {
1279         v3f pos_f = intToFloat(pos, BS);
1280         f32 radius_f = radius * BS;
1281         /*
1282                 Go through current_objects; object is removed if:
1283                 - object is not found in m_active_objects (this is actually an
1284                   error condition; objects should be set m_removed=true and removed
1285                   only after all clients have been informed about removal), or
1286                 - object has m_removed=true, or
1287                 - object is too far away
1288         */
1289         for(core::map<u16, bool>::Iterator
1290                         i = current_objects.getIterator();
1291                         i.atEnd()==false; i++)
1292         {
1293                 u16 id = i.getNode()->getKey();
1294                 ServerActiveObject *object = getActiveObject(id);
1295                 if(object == NULL)
1296                 {
1297                         infostream<<"ServerEnvironment::getRemovedActiveObjects():"
1298                                         <<" object in current_objects is NULL"<<std::endl;
1299                 }
1300                 else if(object->m_removed == false)
1301                 {
1302                         f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1303                         /*infostream<<"removed == false"
1304                                         <<"distance_f = "<<distance_f
1305                                         <<", radius_f = "<<radius_f<<std::endl;*/
1306                         if(distance_f < radius_f)
1307                         {
1308                                 // Not removed
1309                                 continue;
1310                         }
1311                 }
1312                 removed_objects.insert(id, false);
1313         }
1314 }
1315
1316 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1317 {
1318         if(m_active_object_messages.size() == 0)
1319                 return ActiveObjectMessage(0);
1320         
1321         return m_active_object_messages.pop_front();
1322 }
1323
1324 /*
1325         ************ Private methods *************
1326 */
1327
1328 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1329                 bool set_changed)
1330 {
1331         assert(object);
1332         if(object->getId() == 0)
1333         {
1334                 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
1335                 if(new_id == 0)
1336                 {
1337                         infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1338                                         <<"no free ids available"<<std::endl;
1339                         delete object;
1340                         return 0;
1341                 }
1342                 object->setId(new_id);
1343         }
1344         if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
1345         {
1346                 infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1347                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1348                 delete object;
1349                 return 0;
1350         }
1351         /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1352                         <<"added (id="<<object->getId()<<")"<<std::endl;*/
1353                         
1354         m_active_objects.insert(object->getId(), object);
1355
1356         // Add static object to active static list of the block
1357         v3f objectpos = object->getBasePosition();
1358         std::string staticdata = object->getStaticData();
1359         StaticObject s_obj(object->getType(), objectpos, staticdata);
1360         // Add to the block where the object is located in
1361         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1362         MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1363         if(block)
1364         {
1365                 block->m_static_objects.m_active.insert(object->getId(), s_obj);
1366                 object->m_static_exists = true;
1367                 object->m_static_block = blockpos;
1368
1369                 if(set_changed)
1370                         block->setChangedFlag();
1371         }
1372         else{
1373                 infostream<<"ServerEnv: Could not find a block for "
1374                                 <<"storing newly added static active object"<<std::endl;
1375         }
1376
1377         return object->getId();
1378 }
1379
1380 /*
1381         Remove objects that satisfy (m_removed && m_known_by_count==0)
1382 */
1383 void ServerEnvironment::removeRemovedObjects()
1384 {
1385         core::list<u16> objects_to_remove;
1386         for(core::map<u16, ServerActiveObject*>::Iterator
1387                         i = m_active_objects.getIterator();
1388                         i.atEnd()==false; i++)
1389         {
1390                 u16 id = i.getNode()->getKey();
1391                 ServerActiveObject* obj = i.getNode()->getValue();
1392                 // This shouldn't happen but check it
1393                 if(obj == NULL)
1394                 {
1395                         infostream<<"NULL object found in ServerEnvironment"
1396                                         <<" while finding removed objects. id="<<id<<std::endl;
1397                         // Id to be removed from m_active_objects
1398                         objects_to_remove.push_back(id);
1399                         continue;
1400                 }
1401
1402                 /*
1403                         We will delete objects that are marked as removed or thatare
1404                         waiting for deletion after deactivation
1405                 */
1406                 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1407                         continue;
1408
1409                 /*
1410                         Delete static data from block if is marked as removed
1411                 */
1412                 if(obj->m_static_exists && obj->m_removed)
1413                 {
1414                         MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
1415                         if(block)
1416                         {
1417                                 block->m_static_objects.remove(id);
1418                                 block->setChangedFlag();
1419                         }
1420                 }
1421
1422                 // If m_known_by_count > 0, don't actually remove.
1423                 if(obj->m_known_by_count > 0)
1424                         continue;
1425                 
1426                 // Delete
1427                 delete obj;
1428                 // Id to be removed from m_active_objects
1429                 objects_to_remove.push_back(id);
1430         }
1431         // Remove references from m_active_objects
1432         for(core::list<u16>::Iterator i = objects_to_remove.begin();
1433                         i != objects_to_remove.end(); i++)
1434         {
1435                 m_active_objects.remove(*i);
1436         }
1437 }
1438
1439 /*
1440         Convert stored objects from blocks near the players to active.
1441 */
1442 void ServerEnvironment::activateObjects(MapBlock *block)
1443 {
1444         if(block==NULL)
1445                 return;
1446         // Ignore if no stored objects (to not set changed flag)
1447         if(block->m_static_objects.m_stored.size() == 0)
1448                 return;
1449         // A list for objects that couldn't be converted to static for some
1450         // reason. They will be stored back.
1451         core::list<StaticObject> new_stored;
1452         // Loop through stored static objects
1453         for(core::list<StaticObject>::Iterator
1454                         i = block->m_static_objects.m_stored.begin();
1455                         i != block->m_static_objects.m_stored.end(); i++)
1456         {
1457                 /*infostream<<"Server: Creating an active object from "
1458                                 <<"static data"<<std::endl;*/
1459                 StaticObject &s_obj = *i;
1460                 // Create an active object from the data
1461                 ServerActiveObject *obj = ServerActiveObject::create
1462                                 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1463                 // If couldn't create object, store static data back.
1464                 if(obj==NULL)
1465                 {
1466                         new_stored.push_back(s_obj);
1467                         continue;
1468                 }
1469                 // This will also add the object to the active static list
1470                 addActiveObjectRaw(obj, false);
1471                 //u16 id = addActiveObjectRaw(obj, false);
1472         }
1473         // Clear stored list
1474         block->m_static_objects.m_stored.clear();
1475         // Add leftover failed stuff to stored list
1476         for(core::list<StaticObject>::Iterator
1477                         i = new_stored.begin();
1478                         i != new_stored.end(); i++)
1479         {
1480                 StaticObject &s_obj = *i;
1481                 block->m_static_objects.m_stored.push_back(s_obj);
1482         }
1483         // Block has been modified
1484         // NOTE: No it has not really. Save I/O here.
1485         //block->setChangedFlag();
1486 }
1487
1488 /*
1489         Convert objects that are not in active blocks to static.
1490
1491         If m_known_by_count != 0, active object is not deleted, but static
1492         data is still updated.
1493
1494         If force_delete is set, active object is deleted nevertheless. It
1495         shall only be set so in the destructor of the environment.
1496 */
1497 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1498 {
1499         core::list<u16> objects_to_remove;
1500         for(core::map<u16, ServerActiveObject*>::Iterator
1501                         i = m_active_objects.getIterator();
1502                         i.atEnd()==false; i++)
1503         {
1504                 ServerActiveObject* obj = i.getNode()->getValue();
1505
1506                 // This shouldn't happen but check it
1507                 if(obj == NULL)
1508                 {
1509                         infostream<<"NULL object found in ServerEnvironment"
1510                                         <<std::endl;
1511                         assert(0);
1512                         continue;
1513                 }
1514
1515                 u16 id = i.getNode()->getKey();         
1516                 v3f objectpos = obj->getBasePosition(); 
1517
1518                 // The block in which the object resides in
1519                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1520
1521                 // If block is active, don't remove
1522                 if(m_active_blocks.contains(blockpos_o))
1523                         continue;
1524
1525                 /*
1526                         Update the static data
1527                 */
1528
1529                 // Delete old static object
1530                 MapBlock *oldblock = NULL;
1531                 if(obj->m_static_exists)
1532                 {
1533                         MapBlock *block = m_map->getBlockNoCreateNoEx
1534                                         (obj->m_static_block);
1535                         if(block)
1536                         {
1537                                 block->m_static_objects.remove(id);
1538                                 oldblock = block;
1539                         }
1540                 }
1541                 // Create new static object
1542                 std::string staticdata = obj->getStaticData();
1543                 StaticObject s_obj(obj->getType(), objectpos, staticdata);
1544                 // Add to the block where the object is located in
1545                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1546                 // Get or generate the block
1547                 MapBlock *block = m_map->emergeBlock(blockpos);
1548
1549                 /*MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1550                 if(block == NULL)
1551                 {
1552                         // Block not found. Is the old block still ok?
1553                         if(oldblock)
1554                                 block = oldblock;
1555                         // Load from disk or generate
1556                         else
1557                                 block = m_map->emergeBlock(blockpos);
1558                 }*/
1559
1560                 if(block)
1561                 {
1562                         block->m_static_objects.insert(0, s_obj);
1563                         block->setChangedFlag();
1564                         obj->m_static_exists = true;
1565                         obj->m_static_block = block->getPos();
1566                 }
1567                 else{
1568                         infostream<<"ServerEnv: Could not find or generate "
1569                                         <<"a block for storing static object"<<std::endl;
1570                         obj->m_static_exists = false;
1571                         continue;
1572                 }
1573
1574                 /*
1575                         Delete active object if not known by some client,
1576                         else set pending deactivation
1577                 */
1578
1579                 // If known by some client, don't delete.
1580                 if(obj->m_known_by_count > 0 && force_delete == false)
1581                 {
1582                         obj->m_pending_deactivation = true;
1583                         continue;
1584                 }
1585                 
1586                 /*infostream<<"Server: Stored static data. Deleting object."
1587                                 <<std::endl;*/
1588                 // Delete active object
1589                 delete obj;
1590                 // Id to be removed from m_active_objects
1591                 objects_to_remove.push_back(id);
1592         }
1593
1594         // Remove references from m_active_objects
1595         for(core::list<u16>::Iterator i = objects_to_remove.begin();
1596                         i != objects_to_remove.end(); i++)
1597         {
1598                 m_active_objects.remove(*i);
1599         }
1600 }
1601
1602
1603 #ifndef SERVER
1604
1605 /*
1606         ClientEnvironment
1607 */
1608
1609 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr):
1610         m_map(map),
1611         m_smgr(smgr)
1612 {
1613         assert(m_map);
1614         assert(m_smgr);
1615 }
1616
1617 ClientEnvironment::~ClientEnvironment()
1618 {
1619         // delete active objects
1620         for(core::map<u16, ClientActiveObject*>::Iterator
1621                         i = m_active_objects.getIterator();
1622                         i.atEnd()==false; i++)
1623         {
1624                 delete i.getNode()->getValue();
1625         }
1626
1627         // Drop/delete map
1628         m_map->drop();
1629 }
1630
1631 void ClientEnvironment::addPlayer(Player *player)
1632 {
1633         DSTACK(__FUNCTION_NAME);
1634         /*
1635                 It is a failure if player is local and there already is a local
1636                 player
1637         */
1638         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
1639
1640         Environment::addPlayer(player);
1641 }
1642
1643 LocalPlayer * ClientEnvironment::getLocalPlayer()
1644 {
1645         for(core::list<Player*>::Iterator i = m_players.begin();
1646                         i != m_players.end(); i++)
1647         {
1648                 Player *player = *i;
1649                 if(player->isLocal())
1650                         return (LocalPlayer*)player;
1651         }
1652         return NULL;
1653 }
1654
1655 void ClientEnvironment::step(float dtime)
1656 {
1657         DSTACK(__FUNCTION_NAME);
1658
1659         // Get some settings
1660         bool free_move = g_settings->getBool("free_move");
1661         bool footprints = g_settings->getBool("footprints");
1662
1663         // Get local player
1664         LocalPlayer *lplayer = getLocalPlayer();
1665         assert(lplayer);
1666         // collision info queue
1667         core::list<CollisionInfo> player_collisions;
1668         
1669         /*
1670                 Get the speed the player is going
1671         */
1672         bool is_climbing = lplayer->is_climbing;
1673         
1674         f32 player_speed = 0.001; // just some small value
1675         player_speed = lplayer->getSpeed().getLength();
1676         
1677         /*
1678                 Maximum position increment
1679         */
1680         //f32 position_max_increment = 0.05*BS;
1681         f32 position_max_increment = 0.1*BS;
1682
1683         // Maximum time increment (for collision detection etc)
1684         // time = distance / speed
1685         f32 dtime_max_increment = position_max_increment / player_speed;
1686         
1687         // Maximum time increment is 10ms or lower
1688         if(dtime_max_increment > 0.01)
1689                 dtime_max_increment = 0.01;
1690         
1691         // Don't allow overly huge dtime
1692         if(dtime > 0.5)
1693                 dtime = 0.5;
1694         
1695         f32 dtime_downcount = dtime;
1696
1697         /*
1698                 Stuff that has a maximum time increment
1699         */
1700
1701         u32 loopcount = 0;
1702         do
1703         {
1704                 loopcount++;
1705
1706                 f32 dtime_part;
1707                 if(dtime_downcount > dtime_max_increment)
1708                 {
1709                         dtime_part = dtime_max_increment;
1710                         dtime_downcount -= dtime_part;
1711                 }
1712                 else
1713                 {
1714                         dtime_part = dtime_downcount;
1715                         /*
1716                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
1717                                 when dtime_part is so small that dtime_downcount -= dtime_part
1718                                 does nothing
1719                         */
1720                         dtime_downcount = 0;
1721                 }
1722                 
1723                 /*
1724                         Handle local player
1725                 */
1726                 
1727                 {
1728                         v3f lplayerpos = lplayer->getPosition();
1729                         
1730                         // Apply physics
1731                         if(free_move == false && is_climbing == false)
1732                         {
1733                                 // Gravity
1734                                 v3f speed = lplayer->getSpeed();
1735                                 if(lplayer->swimming_up == false)
1736                                         speed.Y -= 9.81 * BS * dtime_part * 2;
1737
1738                                 // Water resistance
1739                                 if(lplayer->in_water_stable || lplayer->in_water)
1740                                 {
1741                                         f32 max_down = 2.0*BS;
1742                                         if(speed.Y < -max_down) speed.Y = -max_down;
1743
1744                                         f32 max = 2.5*BS;
1745                                         if(speed.getLength() > max)
1746                                         {
1747                                                 speed = speed / speed.getLength() * max;
1748                                         }
1749                                 }
1750
1751                                 lplayer->setSpeed(speed);
1752                         }
1753
1754                         /*
1755                                 Move the lplayer.
1756                                 This also does collision detection.
1757                         */
1758                         lplayer->move(dtime_part, *m_map, position_max_increment,
1759                                         &player_collisions);
1760                 }
1761         }
1762         while(dtime_downcount > 0.001);
1763                 
1764         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
1765         
1766         for(core::list<CollisionInfo>::Iterator
1767                         i = player_collisions.begin();
1768                         i != player_collisions.end(); i++)
1769         {
1770                 CollisionInfo &info = *i;
1771                 if(info.t == COLLISION_FALL)
1772                 {
1773                         //f32 tolerance = BS*10; // 2 without damage
1774                         f32 tolerance = BS*12; // 3 without damage
1775                         f32 factor = 1;
1776                         if(info.speed > tolerance)
1777                         {
1778                                 f32 damage_f = (info.speed - tolerance)/BS*factor;
1779                                 u16 damage = (u16)(damage_f+0.5);
1780                                 if(lplayer->hp > damage)
1781                                         lplayer->hp -= damage;
1782                                 else
1783                                         lplayer->hp = 0;
1784
1785                                 ClientEnvEvent event;
1786                                 event.type = CEE_PLAYER_DAMAGE;
1787                                 event.player_damage.amount = damage;
1788                                 m_client_event_queue.push_back(event);
1789                         }
1790                 }
1791         }
1792         
1793         /*
1794                 A quick draft of lava damage
1795         */
1796         if(m_lava_hurt_interval.step(dtime, 1.0))
1797         {
1798                 v3f pf = lplayer->getPosition();
1799                 
1800                 // Feet, middle and head
1801                 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
1802                 MapNode n1 = m_map->getNodeNoEx(p1);
1803                 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
1804                 MapNode n2 = m_map->getNodeNoEx(p2);
1805                 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
1806                 MapNode n3 = m_map->getNodeNoEx(p2);
1807
1808                 u32 damage_per_second = 0;
1809                 damage_per_second = MYMAX(damage_per_second,
1810                                 content_features(n1).damage_per_second);
1811                 damage_per_second = MYMAX(damage_per_second,
1812                                 content_features(n2).damage_per_second);
1813                 damage_per_second = MYMAX(damage_per_second,
1814                                 content_features(n3).damage_per_second);
1815                 
1816                 if(damage_per_second != 0)
1817                 {
1818                         ClientEnvEvent event;
1819                         event.type = CEE_PLAYER_DAMAGE;
1820                         event.player_damage.amount = damage_per_second;
1821                         m_client_event_queue.push_back(event);
1822                 }
1823         }
1824         
1825         /*
1826                 Stuff that can be done in an arbitarily large dtime
1827         */
1828         for(core::list<Player*>::Iterator i = m_players.begin();
1829                         i != m_players.end(); i++)
1830         {
1831                 Player *player = *i;
1832                 v3f playerpos = player->getPosition();
1833                 
1834                 /*
1835                         Handle non-local players
1836                 */
1837                 if(player->isLocal() == false)
1838                 {
1839                         // Move
1840                         player->move(dtime, *m_map, 100*BS);
1841
1842                 }
1843                 
1844                 // Update lighting on all players on client
1845                 u8 light = LIGHT_MAX;
1846                 try{
1847                         // Get node at head
1848                         v3s16 p = player->getLightPosition();
1849                         MapNode n = m_map->getNode(p);
1850                         light = n.getLightBlend(getDayNightRatio());
1851                 }
1852                 catch(InvalidPositionException &e) {}
1853                 player->updateLight(light);
1854
1855                 /*
1856                         Add footsteps to grass
1857                 */
1858                 if(footprints)
1859                 {
1860                         // Get node that is at BS/4 under player
1861                         v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
1862                         try{
1863                                 MapNode n = m_map->getNode(bottompos);
1864                                 if(n.getContent() == CONTENT_GRASS)
1865                                 {
1866                                         n.setContent(CONTENT_GRASS_FOOTSTEPS);
1867                                         m_map->setNode(bottompos, n);
1868                                         // Update mesh on client
1869                                         if(m_map->mapType() == MAPTYPE_CLIENT)
1870                                         {
1871                                                 v3s16 p_blocks = getNodeBlockPos(bottompos);
1872                                                 MapBlock *b = m_map->getBlockNoCreate(p_blocks);
1873                                                 //b->updateMesh(getDayNightRatio());
1874                                                 b->setMeshExpired(true);
1875                                         }
1876                                 }
1877                         }
1878                         catch(InvalidPositionException &e)
1879                         {
1880                         }
1881                 }
1882         }
1883         
1884         /*
1885                 Step active objects and update lighting of them
1886         */
1887         
1888         for(core::map<u16, ClientActiveObject*>::Iterator
1889                         i = m_active_objects.getIterator();
1890                         i.atEnd()==false; i++)
1891         {
1892                 ClientActiveObject* obj = i.getNode()->getValue();
1893                 // Step object
1894                 obj->step(dtime, this);
1895
1896                 if(m_active_object_light_update_interval.step(dtime, 0.21))
1897                 {
1898                         // Update lighting
1899                         //u8 light = LIGHT_MAX;
1900                         u8 light = 0;
1901                         try{
1902                                 // Get node at head
1903                                 v3s16 p = obj->getLightPosition();
1904                                 MapNode n = m_map->getNode(p);
1905                                 light = n.getLightBlend(getDayNightRatio());
1906                         }
1907                         catch(InvalidPositionException &e) {}
1908                         obj->updateLight(light);
1909                 }
1910         }
1911 }
1912
1913 void ClientEnvironment::updateMeshes(v3s16 blockpos)
1914 {
1915         m_map->updateMeshes(blockpos, getDayNightRatio());
1916 }
1917
1918 void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
1919 {
1920         m_map->expireMeshes(only_daynight_diffed);
1921 }
1922
1923 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
1924 {
1925         core::map<u16, ClientActiveObject*>::Node *n;
1926         n = m_active_objects.find(id);
1927         if(n == NULL)
1928                 return NULL;
1929         return n->getValue();
1930 }
1931
1932 bool isFreeClientActiveObjectId(u16 id,
1933                 core::map<u16, ClientActiveObject*> &objects)
1934 {
1935         if(id == 0)
1936                 return false;
1937         
1938         for(core::map<u16, ClientActiveObject*>::Iterator
1939                         i = objects.getIterator();
1940                         i.atEnd()==false; i++)
1941         {
1942                 if(i.getNode()->getKey() == id)
1943                         return false;
1944         }
1945         return true;
1946 }
1947
1948 u16 getFreeClientActiveObjectId(
1949                 core::map<u16, ClientActiveObject*> &objects)
1950 {
1951         u16 new_id = 1;
1952         for(;;)
1953         {
1954                 if(isFreeClientActiveObjectId(new_id, objects))
1955                         return new_id;
1956                 
1957                 if(new_id == 65535)
1958                         return 0;
1959
1960                 new_id++;
1961         }
1962 }
1963
1964 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
1965 {
1966         assert(object);
1967         if(object->getId() == 0)
1968         {
1969                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
1970                 if(new_id == 0)
1971                 {
1972                         infostream<<"ClientEnvironment::addActiveObject(): "
1973                                         <<"no free ids available"<<std::endl;
1974                         delete object;
1975                         return 0;
1976                 }
1977                 object->setId(new_id);
1978         }
1979         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
1980         {
1981                 infostream<<"ClientEnvironment::addActiveObject(): "
1982                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1983                 delete object;
1984                 return 0;
1985         }
1986         infostream<<"ClientEnvironment::addActiveObject(): "
1987                         <<"added (id="<<object->getId()<<")"<<std::endl;
1988         m_active_objects.insert(object->getId(), object);
1989         object->addToScene(m_smgr);
1990         return object->getId();
1991 }
1992
1993 void ClientEnvironment::addActiveObject(u16 id, u8 type,
1994                 const std::string &init_data)
1995 {
1996         ClientActiveObject* obj = ClientActiveObject::create(type);
1997         if(obj == NULL)
1998         {
1999                 infostream<<"ClientEnvironment::addActiveObject(): "
2000                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
2001                                 <<std::endl;
2002                 return;
2003         }
2004         
2005         obj->setId(id);
2006
2007         obj->initialize(init_data);
2008         
2009         addActiveObject(obj);
2010 }
2011
2012 void ClientEnvironment::removeActiveObject(u16 id)
2013 {
2014         infostream<<"ClientEnvironment::removeActiveObject(): "
2015                         <<"id="<<id<<std::endl;
2016         ClientActiveObject* obj = getActiveObject(id);
2017         if(obj == NULL)
2018         {
2019                 infostream<<"ClientEnvironment::removeActiveObject(): "
2020                                 <<"id="<<id<<" not found"<<std::endl;
2021                 return;
2022         }
2023         obj->removeFromScene();
2024         delete obj;
2025         m_active_objects.remove(id);
2026 }
2027
2028 void ClientEnvironment::processActiveObjectMessage(u16 id,
2029                 const std::string &data)
2030 {
2031         ClientActiveObject* obj = getActiveObject(id);
2032         if(obj == NULL)
2033         {
2034                 infostream<<"ClientEnvironment::processActiveObjectMessage():"
2035                                 <<" got message for id="<<id<<", which doesn't exist."
2036                                 <<std::endl;
2037                 return;
2038         }
2039         obj->processMessage(data);
2040 }
2041
2042 /*
2043         Callbacks for activeobjects
2044 */
2045
2046 void ClientEnvironment::damageLocalPlayer(u8 damage)
2047 {
2048         LocalPlayer *lplayer = getLocalPlayer();
2049         assert(lplayer);
2050
2051         if(lplayer->hp > damage)
2052                 lplayer->hp -= damage;
2053         else
2054                 lplayer->hp = 0;
2055
2056         ClientEnvEvent event;
2057         event.type = CEE_PLAYER_DAMAGE;
2058         event.player_damage.amount = damage;
2059         m_client_event_queue.push_back(event);
2060 }
2061
2062 /*
2063         Client likes to call these
2064 */
2065         
2066 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
2067                 core::array<DistanceSortedActiveObject> &dest)
2068 {
2069         for(core::map<u16, ClientActiveObject*>::Iterator
2070                         i = m_active_objects.getIterator();
2071                         i.atEnd()==false; i++)
2072         {
2073                 ClientActiveObject* obj = i.getNode()->getValue();
2074
2075                 f32 d = (obj->getPosition() - origin).getLength();
2076
2077                 if(d > max_d)
2078                         continue;
2079
2080                 DistanceSortedActiveObject dso(obj, d);
2081
2082                 dest.push_back(dso);
2083         }
2084 }
2085
2086 ClientEnvEvent ClientEnvironment::getClientEvent()
2087 {
2088         if(m_client_event_queue.size() == 0)
2089         {
2090                 ClientEnvEvent event;
2091                 event.type = CEE_NONE;
2092                 return event;
2093         }
2094         return m_client_event_queue.pop_front();
2095 }
2096
2097 #endif // #ifndef SERVER
2098
2099