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