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