]> git.lizzy.rs Git - dragonfireclient.git/blob - src/environment.cpp
Use the logger; also, default to not showing much crap in console. Use --info-on...
[dragonfireclient.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         /*
1675                 Check if the player is frozen (don't apply physics)
1676         */
1677         bool is_frozen = lplayer->is_frozen;
1678
1679         f32 player_speed = 0.001; // just some small value
1680         player_speed = lplayer->getSpeed().getLength();
1681         
1682         /*
1683                 Maximum position increment
1684         */
1685         //f32 position_max_increment = 0.05*BS;
1686         f32 position_max_increment = 0.1*BS;
1687
1688         // Maximum time increment (for collision detection etc)
1689         // time = distance / speed
1690         f32 dtime_max_increment = position_max_increment / player_speed;
1691         
1692         // Maximum time increment is 10ms or lower
1693         if(dtime_max_increment > 0.01)
1694                 dtime_max_increment = 0.01;
1695         
1696         // Don't allow overly huge dtime
1697         if(dtime > 0.5)
1698                 dtime = 0.5;
1699         
1700         f32 dtime_downcount = dtime;
1701
1702         /*
1703                 Stuff that has a maximum time increment
1704         */
1705
1706         u32 loopcount = 0;
1707         do
1708         {
1709                 loopcount++;
1710
1711                 f32 dtime_part;
1712                 if(dtime_downcount > dtime_max_increment)
1713                 {
1714                         dtime_part = dtime_max_increment;
1715                         dtime_downcount -= dtime_part;
1716                 }
1717                 else
1718                 {
1719                         dtime_part = dtime_downcount;
1720                         /*
1721                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
1722                                 when dtime_part is so small that dtime_downcount -= dtime_part
1723                                 does nothing
1724                         */
1725                         dtime_downcount = 0;
1726                 }
1727                 
1728                 /*
1729                         Handle local player
1730                 */
1731                 
1732                 {
1733                         v3f lplayerpos = lplayer->getPosition();
1734                         
1735                         // Apply physics
1736                         if(free_move == false && is_climbing == false && is_frozen == false)
1737                         {
1738                                 // Gravity
1739                                 v3f speed = lplayer->getSpeed();
1740                                 if(lplayer->swimming_up == false)
1741                                         speed.Y -= 9.81 * BS * dtime_part * 2;
1742
1743                                 // Water resistance
1744                                 if(lplayer->in_water_stable || lplayer->in_water)
1745                                 {
1746                                         f32 max_down = 2.0*BS;
1747                                         if(speed.Y < -max_down) speed.Y = -max_down;
1748
1749                                         f32 max = 2.5*BS;
1750                                         if(speed.getLength() > max)
1751                                         {
1752                                                 speed = speed / speed.getLength() * max;
1753                                         }
1754                                 }
1755
1756                                 lplayer->setSpeed(speed);
1757                         }
1758
1759                         /*
1760                                 Move the lplayer.
1761                                 This also does collision detection.
1762                         */
1763                         lplayer->move(dtime_part, *m_map, position_max_increment,
1764                                         &player_collisions);
1765                 }
1766         }
1767         while(dtime_downcount > 0.001);
1768                 
1769         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
1770
1771         for(core::list<CollisionInfo>::Iterator
1772                         i = player_collisions.begin();
1773                         i != player_collisions.end(); i++)
1774         {
1775                 CollisionInfo &info = *i;
1776                 if(info.t == COLLISION_FALL)
1777                 {
1778                         //f32 tolerance = BS*10; // 2 without damage
1779                         f32 tolerance = BS*12; // 3 without damage
1780                         f32 factor = 1;
1781                         if(info.speed > tolerance)
1782                         {
1783                                 f32 damage_f = (info.speed - tolerance)/BS*factor;
1784                                 u16 damage = (u16)(damage_f+0.5);
1785                                 if(lplayer->hp > damage)
1786                                         lplayer->hp -= damage;
1787                                 else
1788                                         lplayer->hp = 0;
1789
1790                                 ClientEnvEvent event;
1791                                 event.type = CEE_PLAYER_DAMAGE;
1792                                 event.player_damage.amount = damage;
1793                                 m_client_event_queue.push_back(event);
1794                         }
1795                 }
1796         }
1797         
1798         /*
1799                 A quick draft of lava damage
1800         */
1801         if(m_lava_hurt_interval.step(dtime, 1.0))
1802         {
1803                 v3f pf = lplayer->getPosition();
1804                 
1805                 // Feet, middle and head
1806                 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
1807                 MapNode n1 = m_map->getNodeNoEx(p1);
1808                 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
1809                 MapNode n2 = m_map->getNodeNoEx(p2);
1810                 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
1811                 MapNode n3 = m_map->getNodeNoEx(p2);
1812
1813                 u32 damage_per_second = 0;
1814                 damage_per_second = MYMAX(damage_per_second,
1815                                 content_features(n1).damage_per_second);
1816                 damage_per_second = MYMAX(damage_per_second,
1817                                 content_features(n2).damage_per_second);
1818                 damage_per_second = MYMAX(damage_per_second,
1819                                 content_features(n3).damage_per_second);
1820                 
1821                 if(damage_per_second != 0)
1822                 {
1823                         ClientEnvEvent event;
1824                         event.type = CEE_PLAYER_DAMAGE;
1825                         event.player_damage.amount = damage_per_second;
1826                         m_client_event_queue.push_back(event);
1827                 }
1828         }
1829         
1830         /*
1831                 Stuff that can be done in an arbitarily large dtime
1832         */
1833         for(core::list<Player*>::Iterator i = m_players.begin();
1834                         i != m_players.end(); i++)
1835         {
1836                 Player *player = *i;
1837                 v3f playerpos = player->getPosition();
1838                 
1839                 /*
1840                         Handle non-local players
1841                 */
1842                 if(player->isLocal() == false)
1843                 {
1844                         // Move
1845                         player->move(dtime, *m_map, 100*BS);
1846
1847                 }
1848                 
1849                 // Update lighting on all players on client
1850                 u8 light = LIGHT_MAX;
1851                 try{
1852                         // Get node at head
1853                         v3s16 p = player->getLightPosition();
1854                         MapNode n = m_map->getNode(p);
1855                         light = n.getLightBlend(getDayNightRatio());
1856                 }
1857                 catch(InvalidPositionException &e) {}
1858                 player->updateLight(light);
1859
1860                 /*
1861                         Add footsteps to grass
1862                 */
1863                 if(footprints)
1864                 {
1865                         // Get node that is at BS/4 under player
1866                         v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
1867                         try{
1868                                 MapNode n = m_map->getNode(bottompos);
1869                                 if(n.getContent() == CONTENT_GRASS)
1870                                 {
1871                                         n.setContent(CONTENT_GRASS_FOOTSTEPS);
1872                                         m_map->setNode(bottompos, n);
1873                                         // Update mesh on client
1874                                         if(m_map->mapType() == MAPTYPE_CLIENT)
1875                                         {
1876                                                 v3s16 p_blocks = getNodeBlockPos(bottompos);
1877                                                 MapBlock *b = m_map->getBlockNoCreate(p_blocks);
1878                                                 //b->updateMesh(getDayNightRatio());
1879                                                 b->setMeshExpired(true);
1880                                         }
1881                                 }
1882                         }
1883                         catch(InvalidPositionException &e)
1884                         {
1885                         }
1886                 }
1887         }
1888         
1889         /*
1890                 Step active objects and update lighting of them
1891         */
1892         
1893         for(core::map<u16, ClientActiveObject*>::Iterator
1894                         i = m_active_objects.getIterator();
1895                         i.atEnd()==false; i++)
1896         {
1897                 ClientActiveObject* obj = i.getNode()->getValue();
1898                 // Step object
1899                 obj->step(dtime, this);
1900
1901                 if(m_active_object_light_update_interval.step(dtime, 0.21))
1902                 {
1903                         // Update lighting
1904                         //u8 light = LIGHT_MAX;
1905                         u8 light = 0;
1906                         try{
1907                                 // Get node at head
1908                                 v3s16 p = obj->getLightPosition();
1909                                 MapNode n = m_map->getNode(p);
1910                                 light = n.getLightBlend(getDayNightRatio());
1911                         }
1912                         catch(InvalidPositionException &e) {}
1913                         obj->updateLight(light);
1914                 }
1915         }
1916 }
1917
1918 void ClientEnvironment::updateMeshes(v3s16 blockpos)
1919 {
1920         m_map->updateMeshes(blockpos, getDayNightRatio());
1921 }
1922
1923 void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
1924 {
1925         m_map->expireMeshes(only_daynight_diffed);
1926 }
1927
1928 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
1929 {
1930         core::map<u16, ClientActiveObject*>::Node *n;
1931         n = m_active_objects.find(id);
1932         if(n == NULL)
1933                 return NULL;
1934         return n->getValue();
1935 }
1936
1937 bool isFreeClientActiveObjectId(u16 id,
1938                 core::map<u16, ClientActiveObject*> &objects)
1939 {
1940         if(id == 0)
1941                 return false;
1942         
1943         for(core::map<u16, ClientActiveObject*>::Iterator
1944                         i = objects.getIterator();
1945                         i.atEnd()==false; i++)
1946         {
1947                 if(i.getNode()->getKey() == id)
1948                         return false;
1949         }
1950         return true;
1951 }
1952
1953 u16 getFreeClientActiveObjectId(
1954                 core::map<u16, ClientActiveObject*> &objects)
1955 {
1956         u16 new_id = 1;
1957         for(;;)
1958         {
1959                 if(isFreeClientActiveObjectId(new_id, objects))
1960                         return new_id;
1961                 
1962                 if(new_id == 65535)
1963                         return 0;
1964
1965                 new_id++;
1966         }
1967 }
1968
1969 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
1970 {
1971         assert(object);
1972         if(object->getId() == 0)
1973         {
1974                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
1975                 if(new_id == 0)
1976                 {
1977                         infostream<<"ClientEnvironment::addActiveObject(): "
1978                                         <<"no free ids available"<<std::endl;
1979                         delete object;
1980                         return 0;
1981                 }
1982                 object->setId(new_id);
1983         }
1984         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
1985         {
1986                 infostream<<"ClientEnvironment::addActiveObject(): "
1987                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1988                 delete object;
1989                 return 0;
1990         }
1991         infostream<<"ClientEnvironment::addActiveObject(): "
1992                         <<"added (id="<<object->getId()<<")"<<std::endl;
1993         m_active_objects.insert(object->getId(), object);
1994         object->addToScene(m_smgr);
1995         return object->getId();
1996 }
1997
1998 void ClientEnvironment::addActiveObject(u16 id, u8 type,
1999                 const std::string &init_data)
2000 {
2001         ClientActiveObject* obj = ClientActiveObject::create(type);
2002         if(obj == NULL)
2003         {
2004                 infostream<<"ClientEnvironment::addActiveObject(): "
2005                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
2006                                 <<std::endl;
2007                 return;
2008         }
2009         
2010         obj->setId(id);
2011
2012         obj->initialize(init_data);
2013         
2014         addActiveObject(obj);
2015 }
2016
2017 void ClientEnvironment::removeActiveObject(u16 id)
2018 {
2019         infostream<<"ClientEnvironment::removeActiveObject(): "
2020                         <<"id="<<id<<std::endl;
2021         ClientActiveObject* obj = getActiveObject(id);
2022         if(obj == NULL)
2023         {
2024                 infostream<<"ClientEnvironment::removeActiveObject(): "
2025                                 <<"id="<<id<<" not found"<<std::endl;
2026                 return;
2027         }
2028         obj->removeFromScene();
2029         delete obj;
2030         m_active_objects.remove(id);
2031 }
2032
2033 void ClientEnvironment::processActiveObjectMessage(u16 id,
2034                 const std::string &data)
2035 {
2036         ClientActiveObject* obj = getActiveObject(id);
2037         if(obj == NULL)
2038         {
2039                 infostream<<"ClientEnvironment::processActiveObjectMessage():"
2040                                 <<" got message for id="<<id<<", which doesn't exist."
2041                                 <<std::endl;
2042                 return;
2043         }
2044         obj->processMessage(data);
2045 }
2046
2047 /*
2048         Callbacks for activeobjects
2049 */
2050
2051 void ClientEnvironment::damageLocalPlayer(u8 damage)
2052 {
2053         LocalPlayer *lplayer = getLocalPlayer();
2054         assert(lplayer);
2055
2056         if(lplayer->hp > damage)
2057                 lplayer->hp -= damage;
2058         else
2059                 lplayer->hp = 0;
2060
2061         ClientEnvEvent event;
2062         event.type = CEE_PLAYER_DAMAGE;
2063         event.player_damage.amount = damage;
2064         m_client_event_queue.push_back(event);
2065 }
2066
2067 /*
2068         Client likes to call these
2069 */
2070         
2071 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
2072                 core::array<DistanceSortedActiveObject> &dest)
2073 {
2074         for(core::map<u16, ClientActiveObject*>::Iterator
2075                         i = m_active_objects.getIterator();
2076                         i.atEnd()==false; i++)
2077         {
2078                 ClientActiveObject* obj = i.getNode()->getValue();
2079
2080                 f32 d = (obj->getPosition() - origin).getLength();
2081
2082                 if(d > max_d)
2083                         continue;
2084
2085                 DistanceSortedActiveObject dso(obj, d);
2086
2087                 dest.push_back(dso);
2088         }
2089 }
2090
2091 ClientEnvEvent ClientEnvironment::getClientEvent()
2092 {
2093         if(m_client_event_queue.size() == 0)
2094         {
2095                 ClientEnvEvent event;
2096                 event.type = CEE_NONE;
2097                 return event;
2098         }
2099         return m_client_event_queue.pop_front();
2100 }
2101
2102 #endif // #ifndef SERVER
2103
2104