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