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