]> git.lizzy.rs Git - minetest.git/blob - src/environment.cpp
df41dc63f24fc40feb39300b772853bd5799ce49
[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.d == CONTENT_IGNORE)
547                                 continue;
548                         if(content_features(n.d).liquid_type != LIQUID_NONE)
549                                 continue;
550                         if(content_features(n.d).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.d).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.d == 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.d).air_equivalent &&
633                                                 n_top.getLight(LIGHTBANK_DAY) >= 13)
634                                 {
635                                         n.d = 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.d == CONTENT_GRASS)
690                                 {
691                                         n.d = 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.d == CONTENT_MUD)
863                                 {
864                                         if(myrand()%20 == 0)
865                                         {
866                                                 MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
867                                                 if(content_features(n_top.d).air_equivalent &&
868                                                                 n_top.getLightBlend(getDayNightRatio()) >= 13)
869                                                 {
870                                                         n.d = 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.d == CONTENT_GRASS)
879                                 {
880                                         //if(myrand()%20 == 0)
881                                         {
882                                                 MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
883                                                 if(n_top.d != CONTENT_AIR
884                                                                 && n_top.d != CONTENT_IGNORE)
885                                                 {
886                                                         n.d = CONTENT_MUD;
887                                                         m_map->addNodeWithEvent(p, n);
888                                                 }
889                                         }
890                                 }
891                         }
892                 }
893         }
894         
895         /*
896                 Step active objects
897         */
898         {
899                 //TimeTaker timer("Step active objects");
900                 
901                 // This helps the objects to send data at the same time
902                 bool send_recommended = false;
903                 m_send_recommended_timer += dtime;
904                 if(m_send_recommended_timer > 0.15)
905                 {
906                         m_send_recommended_timer = 0;
907                         send_recommended = true;
908                 }
909
910                 for(core::map<u16, ServerActiveObject*>::Iterator
911                                 i = m_active_objects.getIterator();
912                                 i.atEnd()==false; i++)
913                 {
914                         ServerActiveObject* obj = i.getNode()->getValue();
915                         // Don't step if is to be removed or stored statically
916                         if(obj->m_removed || obj->m_pending_deactivation)
917                                 continue;
918                         // Step object
919                         obj->step(dtime, send_recommended);
920                         // Read messages from object
921                         while(obj->m_messages_out.size() > 0)
922                         {
923                                 m_active_object_messages.push_back(
924                                                 obj->m_messages_out.pop_front());
925                         }
926                 }
927         }
928         
929         /*
930                 Manage active objects
931         */
932         if(m_object_management_interval.step(dtime, 0.5))
933         {
934                 /*
935                         Remove objects that satisfy (m_removed && m_known_by_count==0)
936                 */
937                 removeRemovedObjects();
938         }
939
940         if(g_settings.getBool("enable_experimental"))
941         {
942
943         /*
944                 TEST CODE
945         */
946 #if 1
947         m_random_spawn_timer -= dtime;
948         if(m_random_spawn_timer < 0)
949         {
950                 //m_random_spawn_timer += myrand_range(2.0, 20.0);
951                 //m_random_spawn_timer += 2.0;
952                 m_random_spawn_timer += 200.0;
953
954                 /*
955                         Find some position
956                 */
957
958                 /*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
959                 s16 y = 1 + getServerMap().findGroundLevel(p2d);
960                 v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
961                 
962                 Player *player = getRandomConnectedPlayer();
963                 v3f pos(0,0,0);
964                 if(player)
965                         pos = player->getPosition();
966                 pos += v3f(
967                         myrand_range(-3,3)*BS,
968                         0,
969                         myrand_range(-3,3)*BS
970                 );
971
972                 /*
973                         Create a ServerActiveObject
974                 */
975
976                 //TestSAO *obj = new TestSAO(this, 0, pos);
977                 //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
978                 //ServerActiveObject *obj = new RatSAO(this, 0, pos);
979                 //ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
980                 ServerActiveObject *obj = new FireflySAO(this, 0, pos);
981                 addActiveObject(obj);
982         }
983 #endif
984
985         } // enable_experimental
986 }
987
988 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
989 {
990         core::map<u16, ServerActiveObject*>::Node *n;
991         n = m_active_objects.find(id);
992         if(n == NULL)
993                 return NULL;
994         return n->getValue();
995 }
996
997 bool isFreeServerActiveObjectId(u16 id,
998                 core::map<u16, ServerActiveObject*> &objects)
999 {
1000         if(id == 0)
1001                 return false;
1002         
1003         for(core::map<u16, ServerActiveObject*>::Iterator
1004                         i = objects.getIterator();
1005                         i.atEnd()==false; i++)
1006         {
1007                 if(i.getNode()->getKey() == id)
1008                         return false;
1009         }
1010         return true;
1011 }
1012
1013 u16 getFreeServerActiveObjectId(
1014                 core::map<u16, ServerActiveObject*> &objects)
1015 {
1016         u16 new_id = 1;
1017         for(;;)
1018         {
1019                 if(isFreeServerActiveObjectId(new_id, objects))
1020                         return new_id;
1021                 
1022                 if(new_id == 65535)
1023                         return 0;
1024
1025                 new_id++;
1026         }
1027 }
1028
1029 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1030 {
1031         assert(object);
1032         u16 id = addActiveObjectRaw(object, true);
1033         return id;
1034 }
1035
1036 /*
1037         Finds out what new objects have been added to
1038         inside a radius around a position
1039 */
1040 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1041                 core::map<u16, bool> &current_objects,
1042                 core::map<u16, bool> &added_objects)
1043 {
1044         v3f pos_f = intToFloat(pos, BS);
1045         f32 radius_f = radius * BS;
1046         /*
1047                 Go through the object list,
1048                 - discard m_removed objects,
1049                 - discard objects that are too far away,
1050                 - discard objects that are found in current_objects.
1051                 - add remaining objects to added_objects
1052         */
1053         for(core::map<u16, ServerActiveObject*>::Iterator
1054                         i = m_active_objects.getIterator();
1055                         i.atEnd()==false; i++)
1056         {
1057                 u16 id = i.getNode()->getKey();
1058                 // Get object
1059                 ServerActiveObject *object = i.getNode()->getValue();
1060                 if(object == NULL)
1061                         continue;
1062                 // Discard if removed
1063                 if(object->m_removed)
1064                         continue;
1065                 // Discard if too far
1066                 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1067                 if(distance_f > radius_f)
1068                         continue;
1069                 // Discard if already on current_objects
1070                 core::map<u16, bool>::Node *n;
1071                 n = current_objects.find(id);
1072                 if(n != NULL)
1073                         continue;
1074                 // Add to added_objects
1075                 added_objects.insert(id, false);
1076         }
1077 }
1078
1079 /*
1080         Finds out what objects have been removed from
1081         inside a radius around a position
1082 */
1083 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1084                 core::map<u16, bool> &current_objects,
1085                 core::map<u16, bool> &removed_objects)
1086 {
1087         v3f pos_f = intToFloat(pos, BS);
1088         f32 radius_f = radius * BS;
1089         /*
1090                 Go through current_objects; object is removed if:
1091                 - object is not found in m_active_objects (this is actually an
1092                   error condition; objects should be set m_removed=true and removed
1093                   only after all clients have been informed about removal), or
1094                 - object has m_removed=true, or
1095                 - object is too far away
1096         */
1097         for(core::map<u16, bool>::Iterator
1098                         i = current_objects.getIterator();
1099                         i.atEnd()==false; i++)
1100         {
1101                 u16 id = i.getNode()->getKey();
1102                 ServerActiveObject *object = getActiveObject(id);
1103                 if(object == NULL)
1104                 {
1105                         dstream<<"WARNING: ServerEnvironment::getRemovedActiveObjects():"
1106                                         <<" object in current_objects is NULL"<<std::endl;
1107                 }
1108                 else if(object->m_removed == false)
1109                 {
1110                         f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1111                         /*dstream<<"removed == false"
1112                                         <<"distance_f = "<<distance_f
1113                                         <<", radius_f = "<<radius_f<<std::endl;*/
1114                         if(distance_f < radius_f)
1115                         {
1116                                 // Not removed
1117                                 continue;
1118                         }
1119                 }
1120                 removed_objects.insert(id, false);
1121         }
1122 }
1123
1124 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1125 {
1126         if(m_active_object_messages.size() == 0)
1127                 return ActiveObjectMessage(0);
1128         
1129         return m_active_object_messages.pop_front();
1130 }
1131
1132 /*
1133         ************ Private methods *************
1134 */
1135
1136 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1137                 bool set_changed)
1138 {
1139         assert(object);
1140         if(object->getId() == 0)
1141         {
1142                 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
1143                 if(new_id == 0)
1144                 {
1145                         dstream<<"WARNING: ServerEnvironment::addActiveObjectRaw(): "
1146                                         <<"no free ids available"<<std::endl;
1147                         delete object;
1148                         return 0;
1149                 }
1150                 object->setId(new_id);
1151         }
1152         if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
1153         {
1154                 dstream<<"WARNING: ServerEnvironment::addActiveObjectRaw(): "
1155                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1156                 delete object;
1157                 return 0;
1158         }
1159         /*dstream<<"INGO: ServerEnvironment::addActiveObjectRaw(): "
1160                         <<"added (id="<<object->getId()<<")"<<std::endl;*/
1161                         
1162         m_active_objects.insert(object->getId(), object);
1163
1164         // Add static object to active static list of the block
1165         v3f objectpos = object->getBasePosition();
1166         std::string staticdata = object->getStaticData();
1167         StaticObject s_obj(object->getType(), objectpos, staticdata);
1168         // Add to the block where the object is located in
1169         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1170         MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1171         if(block)
1172         {
1173                 block->m_static_objects.m_active.insert(object->getId(), s_obj);
1174                 object->m_static_exists = true;
1175                 object->m_static_block = blockpos;
1176
1177                 if(set_changed)
1178                         block->setChangedFlag();
1179         }
1180         else{
1181                 dstream<<"WARNING: ServerEnv: Could not find a block for "
1182                                 <<"storing newly added static active object"<<std::endl;
1183         }
1184
1185         return object->getId();
1186 }
1187
1188 /*
1189         Remove objects that satisfy (m_removed && m_known_by_count==0)
1190 */
1191 void ServerEnvironment::removeRemovedObjects()
1192 {
1193         core::list<u16> objects_to_remove;
1194         for(core::map<u16, ServerActiveObject*>::Iterator
1195                         i = m_active_objects.getIterator();
1196                         i.atEnd()==false; i++)
1197         {
1198                 u16 id = i.getNode()->getKey();
1199                 ServerActiveObject* obj = i.getNode()->getValue();
1200                 // This shouldn't happen but check it
1201                 if(obj == NULL)
1202                 {
1203                         dstream<<"WARNING: NULL object found in ServerEnvironment"
1204                                         <<" while finding removed objects. id="<<id<<std::endl;
1205                         // Id to be removed from m_active_objects
1206                         objects_to_remove.push_back(id);
1207                         continue;
1208                 }
1209
1210                 /*
1211                         We will delete objects that are marked as removed or thatare
1212                         waiting for deletion after deactivation
1213                 */
1214                 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1215                         continue;
1216
1217                 /*
1218                         Delete static data from block if is marked as removed
1219                 */
1220                 if(obj->m_static_exists && obj->m_removed)
1221                 {
1222                         MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
1223                         if(block)
1224                         {
1225                                 block->m_static_objects.remove(id);
1226                                 block->setChangedFlag();
1227                         }
1228                 }
1229
1230                 // If m_known_by_count > 0, don't actually remove.
1231                 if(obj->m_known_by_count > 0)
1232                         continue;
1233                 
1234                 // Delete
1235                 delete obj;
1236                 // Id to be removed from m_active_objects
1237                 objects_to_remove.push_back(id);
1238         }
1239         // Remove references from m_active_objects
1240         for(core::list<u16>::Iterator i = objects_to_remove.begin();
1241                         i != objects_to_remove.end(); i++)
1242         {
1243                 m_active_objects.remove(*i);
1244         }
1245 }
1246
1247 /*
1248         Convert stored objects from blocks near the players to active.
1249 */
1250 void ServerEnvironment::activateObjects(MapBlock *block)
1251 {
1252         if(block==NULL)
1253                 return;
1254         // Ignore if no stored objects (to not set changed flag)
1255         if(block->m_static_objects.m_stored.size() == 0)
1256                 return;
1257         // A list for objects that couldn't be converted to static for some
1258         // reason. They will be stored back.
1259         core::list<StaticObject> new_stored;
1260         // Loop through stored static objects
1261         for(core::list<StaticObject>::Iterator
1262                         i = block->m_static_objects.m_stored.begin();
1263                         i != block->m_static_objects.m_stored.end(); i++)
1264         {
1265                 /*dstream<<"INFO: Server: Creating an active object from "
1266                                 <<"static data"<<std::endl;*/
1267                 StaticObject &s_obj = *i;
1268                 // Create an active object from the data
1269                 ServerActiveObject *obj = ServerActiveObject::create
1270                                 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1271                 // If couldn't create object, store static data back.
1272                 if(obj==NULL)
1273                 {
1274                         new_stored.push_back(s_obj);
1275                         continue;
1276                 }
1277                 // This will also add the object to the active static list
1278                 addActiveObjectRaw(obj, false);
1279                 //u16 id = addActiveObjectRaw(obj, false);
1280         }
1281         // Clear stored list
1282         block->m_static_objects.m_stored.clear();
1283         // Add leftover failed stuff to stored list
1284         for(core::list<StaticObject>::Iterator
1285                         i = new_stored.begin();
1286                         i != new_stored.end(); i++)
1287         {
1288                 StaticObject &s_obj = *i;
1289                 block->m_static_objects.m_stored.push_back(s_obj);
1290         }
1291         // Block has been modified
1292         // NOTE: No it has not really. Save I/O here.
1293         //block->setChangedFlag();
1294 }
1295
1296 /*
1297         Convert objects that are not in active blocks to static.
1298
1299         If m_known_by_count != 0, active object is not deleted, but static
1300         data is still updated.
1301
1302         If force_delete is set, active object is deleted nevertheless. It
1303         shall only be set so in the destructor of the environment.
1304 */
1305 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1306 {
1307         core::list<u16> objects_to_remove;
1308         for(core::map<u16, ServerActiveObject*>::Iterator
1309                         i = m_active_objects.getIterator();
1310                         i.atEnd()==false; i++)
1311         {
1312                 ServerActiveObject* obj = i.getNode()->getValue();
1313                 u16 id = i.getNode()->getKey();
1314                 v3f objectpos = obj->getBasePosition();
1315
1316                 // This shouldn't happen but check it
1317                 if(obj == NULL)
1318                 {
1319                         dstream<<"WARNING: NULL object found in ServerEnvironment"
1320                                         <<std::endl;
1321                         assert(0);
1322                         continue;
1323                 }
1324
1325                 // The block in which the object resides in
1326                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1327                 
1328                 // If block is active, don't remove
1329                 if(m_active_blocks.contains(blockpos_o))
1330                         continue;
1331
1332                 /*
1333                         Update the static data
1334                 */
1335
1336                 // Delete old static object
1337                 MapBlock *oldblock = NULL;
1338                 if(obj->m_static_exists)
1339                 {
1340                         MapBlock *block = m_map->getBlockNoCreateNoEx
1341                                         (obj->m_static_block);
1342                         if(block)
1343                         {
1344                                 block->m_static_objects.remove(id);
1345                                 oldblock = block;
1346                         }
1347                 }
1348                 // Create new static object
1349                 std::string staticdata = obj->getStaticData();
1350                 StaticObject s_obj(obj->getType(), objectpos, staticdata);
1351                 // Add to the block where the object is located in
1352                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1353                 // Get or generate the block
1354                 MapBlock *block = m_map->emergeBlock(blockpos);
1355
1356                 /*MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1357                 if(block == NULL)
1358                 {
1359                         // Block not found. Is the old block still ok?
1360                         if(oldblock)
1361                                 block = oldblock;
1362                         // Load from disk or generate
1363                         else
1364                                 block = m_map->emergeBlock(blockpos);
1365                 }*/
1366
1367                 if(block)
1368                 {
1369                         block->m_static_objects.insert(0, s_obj);
1370                         block->setChangedFlag();
1371                         obj->m_static_exists = true;
1372                         obj->m_static_block = block->getPos();
1373                 }
1374                 else{
1375                         dstream<<"WARNING: ServerEnv: Could not find or generate "
1376                                         <<"a block for storing static object"<<std::endl;
1377                         obj->m_static_exists = false;
1378                         continue;
1379                 }
1380
1381                 /*
1382                         Delete active object if not known by some client,
1383                         else set pending deactivation
1384                 */
1385
1386                 // If known by some client, don't delete.
1387                 if(obj->m_known_by_count > 0 && force_delete == false)
1388                 {
1389                         obj->m_pending_deactivation = true;
1390                         continue;
1391                 }
1392                 
1393                 /*dstream<<"INFO: Server: Stored static data. Deleting object."
1394                                 <<std::endl;*/
1395                 // Delete active object
1396                 delete obj;
1397                 // Id to be removed from m_active_objects
1398                 objects_to_remove.push_back(id);
1399         }
1400
1401         // Remove references from m_active_objects
1402         for(core::list<u16>::Iterator i = objects_to_remove.begin();
1403                         i != objects_to_remove.end(); i++)
1404         {
1405                 m_active_objects.remove(*i);
1406         }
1407 }
1408
1409
1410 #ifndef SERVER
1411
1412 /*
1413         ClientEnvironment
1414 */
1415
1416 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr):
1417         m_map(map),
1418         m_smgr(smgr)
1419 {
1420         assert(m_map);
1421         assert(m_smgr);
1422 }
1423
1424 ClientEnvironment::~ClientEnvironment()
1425 {
1426         // delete active objects
1427         for(core::map<u16, ClientActiveObject*>::Iterator
1428                         i = m_active_objects.getIterator();
1429                         i.atEnd()==false; i++)
1430         {
1431                 delete i.getNode()->getValue();
1432         }
1433
1434         // Drop/delete map
1435         m_map->drop();
1436 }
1437
1438 void ClientEnvironment::addPlayer(Player *player)
1439 {
1440         DSTACK(__FUNCTION_NAME);
1441         /*
1442                 It is a failure if player is local and there already is a local
1443                 player
1444         */
1445         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
1446
1447         Environment::addPlayer(player);
1448 }
1449
1450 LocalPlayer * ClientEnvironment::getLocalPlayer()
1451 {
1452         for(core::list<Player*>::Iterator i = m_players.begin();
1453                         i != m_players.end(); i++)
1454         {
1455                 Player *player = *i;
1456                 if(player->isLocal())
1457                         return (LocalPlayer*)player;
1458         }
1459         return NULL;
1460 }
1461
1462 void ClientEnvironment::step(float dtime)
1463 {
1464         DSTACK(__FUNCTION_NAME);
1465
1466         // Get some settings
1467         bool free_move = g_settings.getBool("free_move");
1468         bool footprints = g_settings.getBool("footprints");
1469
1470         // Get local player
1471         LocalPlayer *lplayer = getLocalPlayer();
1472         assert(lplayer);
1473         // collision info queue
1474         core::list<CollisionInfo> player_collisions;
1475         
1476         /*
1477                 Get the speed the player is going
1478         */
1479         f32 player_speed = 0.001; // just some small value
1480         player_speed = lplayer->getSpeed().getLength();
1481         
1482         /*
1483                 Maximum position increment
1484         */
1485         //f32 position_max_increment = 0.05*BS;
1486         f32 position_max_increment = 0.1*BS;
1487
1488         // Maximum time increment (for collision detection etc)
1489         // time = distance / speed
1490         f32 dtime_max_increment = position_max_increment / player_speed;
1491         
1492         // Maximum time increment is 10ms or lower
1493         if(dtime_max_increment > 0.01)
1494                 dtime_max_increment = 0.01;
1495         
1496         // Don't allow overly huge dtime
1497         if(dtime > 0.5)
1498                 dtime = 0.5;
1499         
1500         f32 dtime_downcount = dtime;
1501
1502         /*
1503                 Stuff that has a maximum time increment
1504         */
1505
1506         u32 loopcount = 0;
1507         do
1508         {
1509                 loopcount++;
1510
1511                 f32 dtime_part;
1512                 if(dtime_downcount > dtime_max_increment)
1513                 {
1514                         dtime_part = dtime_max_increment;
1515                         dtime_downcount -= dtime_part;
1516                 }
1517                 else
1518                 {
1519                         dtime_part = dtime_downcount;
1520                         /*
1521                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
1522                                 when dtime_part is so small that dtime_downcount -= dtime_part
1523                                 does nothing
1524                         */
1525                         dtime_downcount = 0;
1526                 }
1527                 
1528                 /*
1529                         Handle local player
1530                 */
1531                 
1532                 {
1533                         v3f lplayerpos = lplayer->getPosition();
1534                         
1535                         // Apply physics
1536                         if(free_move == false)
1537                         {
1538                                 // Gravity
1539                                 v3f speed = lplayer->getSpeed();
1540                                 if(lplayer->swimming_up == false)
1541                                         speed.Y -= 9.81 * BS * dtime_part * 2;
1542
1543                                 // Water resistance
1544                                 if(lplayer->in_water_stable || lplayer->in_water)
1545                                 {
1546                                         f32 max_down = 2.0*BS;
1547                                         if(speed.Y < -max_down) speed.Y = -max_down;
1548
1549                                         f32 max = 2.5*BS;
1550                                         if(speed.getLength() > max)
1551                                         {
1552                                                 speed = speed / speed.getLength() * max;
1553                                         }
1554                                 }
1555
1556                                 lplayer->setSpeed(speed);
1557                         }
1558
1559                         /*
1560                                 Move the lplayer.
1561                                 This also does collision detection.
1562                         */
1563                         lplayer->move(dtime_part, *m_map, position_max_increment,
1564                                         &player_collisions);
1565                 }
1566         }
1567         while(dtime_downcount > 0.001);
1568                 
1569         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
1570
1571         for(core::list<CollisionInfo>::Iterator
1572                         i = player_collisions.begin();
1573                         i != player_collisions.end(); i++)
1574         {
1575                 CollisionInfo &info = *i;
1576                 if(info.t == COLLISION_FALL)
1577                 {
1578                         //f32 tolerance = BS*10; // 2 without damage
1579                         f32 tolerance = BS*12; // 3 without damage
1580                         f32 factor = 1;
1581                         if(info.speed > tolerance)
1582                         {
1583                                 f32 damage_f = (info.speed - tolerance)/BS*factor;
1584                                 u16 damage = (u16)(damage_f+0.5);
1585                                 if(lplayer->hp > damage)
1586                                         lplayer->hp -= damage;
1587                                 else
1588                                         lplayer->hp = 0;
1589
1590                                 ClientEnvEvent event;
1591                                 event.type = CEE_PLAYER_DAMAGE;
1592                                 event.player_damage.amount = damage;
1593                                 m_client_event_queue.push_back(event);
1594                         }
1595                 }
1596         }
1597         
1598         /*
1599                 Stuff that can be done in an arbitarily large dtime
1600         */
1601         for(core::list<Player*>::Iterator i = m_players.begin();
1602                         i != m_players.end(); i++)
1603         {
1604                 Player *player = *i;
1605                 v3f playerpos = player->getPosition();
1606                 
1607                 /*
1608                         Handle non-local players
1609                 */
1610                 if(player->isLocal() == false)
1611                 {
1612                         // Move
1613                         player->move(dtime, *m_map, 100*BS);
1614
1615                         // Update lighting on remote players on client
1616                         u8 light = LIGHT_MAX;
1617                         try{
1618                                 // Get node at head
1619                                 v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS);
1620                                 MapNode n = m_map->getNode(p);
1621                                 light = n.getLightBlend(getDayNightRatio());
1622                         }
1623                         catch(InvalidPositionException &e) {}
1624                         player->updateLight(light);
1625                 }
1626                 
1627                 /*
1628                         Add footsteps to grass
1629                 */
1630                 if(footprints)
1631                 {
1632                         // Get node that is at BS/4 under player
1633                         v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
1634                         try{
1635                                 MapNode n = m_map->getNode(bottompos);
1636                                 if(n.d == CONTENT_GRASS)
1637                                 {
1638                                         n.d = CONTENT_GRASS_FOOTSTEPS;
1639                                         m_map->setNode(bottompos, n);
1640                                         // Update mesh on client
1641                                         if(m_map->mapType() == MAPTYPE_CLIENT)
1642                                         {
1643                                                 v3s16 p_blocks = getNodeBlockPos(bottompos);
1644                                                 MapBlock *b = m_map->getBlockNoCreate(p_blocks);
1645                                                 //b->updateMesh(getDayNightRatio());
1646                                                 b->setMeshExpired(true);
1647                                         }
1648                                 }
1649                         }
1650                         catch(InvalidPositionException &e)
1651                         {
1652                         }
1653                 }
1654         }
1655         
1656         /*
1657                 Step active objects and update lighting of them
1658         */
1659         
1660         for(core::map<u16, ClientActiveObject*>::Iterator
1661                         i = m_active_objects.getIterator();
1662                         i.atEnd()==false; i++)
1663         {
1664                 ClientActiveObject* obj = i.getNode()->getValue();
1665                 // Step object
1666                 obj->step(dtime, this);
1667
1668                 if(m_active_object_light_update_interval.step(dtime, 0.21))
1669                 {
1670                         // Update lighting
1671                         //u8 light = LIGHT_MAX;
1672                         u8 light = 0;
1673                         try{
1674                                 // Get node at head
1675                                 v3s16 p = obj->getLightPosition();
1676                                 MapNode n = m_map->getNode(p);
1677                                 light = n.getLightBlend(getDayNightRatio());
1678                         }
1679                         catch(InvalidPositionException &e) {}
1680                         obj->updateLight(light);
1681                 }
1682         }
1683 }
1684
1685 void ClientEnvironment::updateMeshes(v3s16 blockpos)
1686 {
1687         m_map->updateMeshes(blockpos, getDayNightRatio());
1688 }
1689
1690 void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
1691 {
1692         m_map->expireMeshes(only_daynight_diffed);
1693 }
1694
1695 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
1696 {
1697         core::map<u16, ClientActiveObject*>::Node *n;
1698         n = m_active_objects.find(id);
1699         if(n == NULL)
1700                 return NULL;
1701         return n->getValue();
1702 }
1703
1704 bool isFreeClientActiveObjectId(u16 id,
1705                 core::map<u16, ClientActiveObject*> &objects)
1706 {
1707         if(id == 0)
1708                 return false;
1709         
1710         for(core::map<u16, ClientActiveObject*>::Iterator
1711                         i = objects.getIterator();
1712                         i.atEnd()==false; i++)
1713         {
1714                 if(i.getNode()->getKey() == id)
1715                         return false;
1716         }
1717         return true;
1718 }
1719
1720 u16 getFreeClientActiveObjectId(
1721                 core::map<u16, ClientActiveObject*> &objects)
1722 {
1723         u16 new_id = 1;
1724         for(;;)
1725         {
1726                 if(isFreeClientActiveObjectId(new_id, objects))
1727                         return new_id;
1728                 
1729                 if(new_id == 65535)
1730                         return 0;
1731
1732                 new_id++;
1733         }
1734 }
1735
1736 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
1737 {
1738         assert(object);
1739         if(object->getId() == 0)
1740         {
1741                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
1742                 if(new_id == 0)
1743                 {
1744                         dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1745                                         <<"no free ids available"<<std::endl;
1746                         delete object;
1747                         return 0;
1748                 }
1749                 object->setId(new_id);
1750         }
1751         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
1752         {
1753                 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1754                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1755                 delete object;
1756                 return 0;
1757         }
1758         dstream<<"INGO: ClientEnvironment::addActiveObject(): "
1759                         <<"added (id="<<object->getId()<<")"<<std::endl;
1760         m_active_objects.insert(object->getId(), object);
1761         object->addToScene(m_smgr);
1762         return object->getId();
1763 }
1764
1765 void ClientEnvironment::addActiveObject(u16 id, u8 type,
1766                 const std::string &init_data)
1767 {
1768         ClientActiveObject* obj = ClientActiveObject::create(type);
1769         if(obj == NULL)
1770         {
1771                 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1772                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
1773                                 <<std::endl;
1774                 return;
1775         }
1776         
1777         obj->setId(id);
1778
1779         addActiveObject(obj);
1780
1781         obj->initialize(init_data);
1782 }
1783
1784 void ClientEnvironment::removeActiveObject(u16 id)
1785 {
1786         dstream<<"ClientEnvironment::removeActiveObject(): "
1787                         <<"id="<<id<<std::endl;
1788         ClientActiveObject* obj = getActiveObject(id);
1789         if(obj == NULL)
1790         {
1791                 dstream<<"WARNING: ClientEnvironment::removeActiveObject(): "
1792                                 <<"id="<<id<<" not found"<<std::endl;
1793                 return;
1794         }
1795         obj->removeFromScene();
1796         delete obj;
1797         m_active_objects.remove(id);
1798 }
1799
1800 void ClientEnvironment::processActiveObjectMessage(u16 id,
1801                 const std::string &data)
1802 {
1803         ClientActiveObject* obj = getActiveObject(id);
1804         if(obj == NULL)
1805         {
1806                 dstream<<"WARNING: ClientEnvironment::processActiveObjectMessage():"
1807                                 <<" got message for id="<<id<<", which doesn't exist."
1808                                 <<std::endl;
1809                 return;
1810         }
1811         obj->processMessage(data);
1812 }
1813
1814 /*
1815         Callbacks for activeobjects
1816 */
1817
1818 void ClientEnvironment::damageLocalPlayer(u8 damage)
1819 {
1820         LocalPlayer *lplayer = getLocalPlayer();
1821         assert(lplayer);
1822
1823         if(lplayer->hp > damage)
1824                 lplayer->hp -= damage;
1825         else
1826                 lplayer->hp = 0;
1827
1828         ClientEnvEvent event;
1829         event.type = CEE_PLAYER_DAMAGE;
1830         event.player_damage.amount = damage;
1831         m_client_event_queue.push_back(event);
1832 }
1833
1834 /*
1835         Client likes to call these
1836 */
1837         
1838 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
1839                 core::array<DistanceSortedActiveObject> &dest)
1840 {
1841         for(core::map<u16, ClientActiveObject*>::Iterator
1842                         i = m_active_objects.getIterator();
1843                         i.atEnd()==false; i++)
1844         {
1845                 ClientActiveObject* obj = i.getNode()->getValue();
1846
1847                 f32 d = (obj->getPosition() - origin).getLength();
1848
1849                 if(d > max_d)
1850                         continue;
1851
1852                 DistanceSortedActiveObject dso(obj, d);
1853
1854                 dest.push_back(dso);
1855         }
1856 }
1857
1858 ClientEnvEvent ClientEnvironment::getClientEvent()
1859 {
1860         if(m_client_event_queue.size() == 0)
1861         {
1862                 ClientEnvEvent event;
1863                 event.type = CEE_NONE;
1864                 return event;
1865         }
1866         return m_client_event_queue.pop_front();
1867 }
1868
1869 void ClientEnvironment::drawPostFx(video::IVideoDriver* driver, v3f camera_pos)
1870 {
1871         /*LocalPlayer *player = getLocalPlayer();
1872         assert(player);
1873         v3f pos_f = player->getPosition() + v3f(0,BS*1.625,0);*/
1874         v3f pos_f = camera_pos;
1875         v3s16 p_nodes = floatToInt(pos_f, BS);
1876         MapNode n = m_map->getNodeNoEx(p_nodes);
1877         if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
1878         {
1879                 v2u32 ss = driver->getScreenSize();
1880                 core::rect<s32> rect(0,0, ss.X, ss.Y);
1881                 driver->draw2DRectangle(video::SColor(64, 100, 100, 200), rect);
1882         }
1883 }
1884
1885 #endif // #ifndef SERVER
1886
1887