]> git.lizzy.rs Git - dragonfireclient.git/blob - src/environment.cpp
Fix my name.
[dragonfireclient.git] / src / environment.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 <set>
21 #include <list>
22 #include <map>
23 #include "environment.h"
24 #include "filesys.h"
25 #include "porting.h"
26 #include "collision.h"
27 #include "content_mapnode.h"
28 #include "mapblock.h"
29 #include "serverobject.h"
30 #include "content_sao.h"
31 #include "settings.h"
32 #include "log.h"
33 #include "profiler.h"
34 #include "cpp_api/scriptapi.h"
35 #include "nodedef.h"
36 #include "nodemetadata.h"
37 #include "main.h" // For g_settings, g_profiler
38 #include "gamedef.h"
39 #ifndef SERVER
40 #include "clientmap.h"
41 #include "localplayer.h"
42 #include "event.h"
43 #endif
44 #include "daynightratio.h"
45 #include "map.h"
46 #include "util/serialize.h"
47
48 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
49
50 Environment::Environment():
51         m_time_of_day(9000),
52         m_time_of_day_f(9000./24000),
53         m_time_of_day_speed(0),
54         m_time_counter(0)
55 {
56 }
57
58 Environment::~Environment()
59 {
60         // Deallocate players
61         for(std::list<Player*>::iterator i = m_players.begin();
62                         i != m_players.end(); ++i)
63         {
64                 delete (*i);
65         }
66 }
67
68 void Environment::addPlayer(Player *player)
69 {
70         DSTACK(__FUNCTION_NAME);
71         /*
72                 Check that peer_ids are unique.
73                 Also check that names are unique.
74                 Exception: there can be multiple players with peer_id=0
75         */
76         // If peer id is non-zero, it has to be unique.
77         if(player->peer_id != 0)
78                 assert(getPlayer(player->peer_id) == NULL);
79         // Name has to be unique.
80         assert(getPlayer(player->getName()) == NULL);
81         // Add.
82         m_players.push_back(player);
83 }
84
85 void Environment::removePlayer(u16 peer_id)
86 {
87         DSTACK(__FUNCTION_NAME);
88 re_search:
89         for(std::list<Player*>::iterator i = m_players.begin();
90                         i != m_players.end(); ++i)
91         {
92                 Player *player = *i;
93                 if(player->peer_id != peer_id)
94                         continue;
95                 
96                 delete player;
97                 m_players.erase(i);
98                 // See if there is an another one
99                 // (shouldn't be, but just to be sure)
100                 goto re_search;
101         }
102 }
103
104 Player * Environment::getPlayer(u16 peer_id)
105 {
106         for(std::list<Player*>::iterator i = m_players.begin();
107                         i != m_players.end(); ++i)
108         {
109                 Player *player = *i;
110                 if(player->peer_id == peer_id)
111                         return player;
112         }
113         return NULL;
114 }
115
116 Player * Environment::getPlayer(const char *name)
117 {
118         for(std::list<Player*>::iterator i = m_players.begin();
119                         i != m_players.end(); ++i)
120         {
121                 Player *player = *i;
122                 if(strcmp(player->getName(), name) == 0)
123                         return player;
124         }
125         return NULL;
126 }
127
128 Player * Environment::getRandomConnectedPlayer()
129 {
130         std::list<Player*> connected_players = getPlayers(true);
131         u32 chosen_one = myrand() % connected_players.size();
132         u32 j = 0;
133         for(std::list<Player*>::iterator
134                         i = connected_players.begin();
135                         i != connected_players.end(); ++i)
136         {
137                 if(j == chosen_one)
138                 {
139                         Player *player = *i;
140                         return player;
141                 }
142                 j++;
143         }
144         return NULL;
145 }
146
147 Player * Environment::getNearestConnectedPlayer(v3f pos)
148 {
149         std::list<Player*> connected_players = getPlayers(true);
150         f32 nearest_d = 0;
151         Player *nearest_player = NULL;
152         for(std::list<Player*>::iterator
153                         i = connected_players.begin();
154                         i != connected_players.end(); ++i)
155         {
156                 Player *player = *i;
157                 f32 d = player->getPosition().getDistanceFrom(pos);
158                 if(d < nearest_d || nearest_player == NULL)
159                 {
160                         nearest_d = d;
161                         nearest_player = player;
162                 }
163         }
164         return nearest_player;
165 }
166
167 std::list<Player*> Environment::getPlayers()
168 {
169         return m_players;
170 }
171
172 std::list<Player*> Environment::getPlayers(bool ignore_disconnected)
173 {
174         std::list<Player*> newlist;
175         for(std::list<Player*>::iterator
176                         i = m_players.begin();
177                         i != m_players.end(); ++i)
178         {
179                 Player *player = *i;
180                 
181                 if(ignore_disconnected)
182                 {
183                         // Ignore disconnected players
184                         if(player->peer_id == 0)
185                                 continue;
186                 }
187
188                 newlist.push_back(player);
189         }
190         return newlist;
191 }
192
193 void Environment::printPlayers(std::ostream &o)
194 {
195         o<<"Players in environment:"<<std::endl;
196         for(std::list<Player*>::iterator i = m_players.begin();
197                         i != m_players.end(); i++)
198         {
199                 Player *player = *i;
200                 o<<"Player peer_id="<<player->peer_id<<std::endl;
201         }
202 }
203
204 u32 Environment::getDayNightRatio()
205 {
206         bool smooth = g_settings->getBool("enable_shaders");
207         return time_to_daynight_ratio(m_time_of_day_f*24000, smooth);
208 }
209
210 void Environment::stepTimeOfDay(float dtime)
211 {
212         m_time_counter += dtime;
213         f32 speed = m_time_of_day_speed * 24000./(24.*3600);
214         u32 units = (u32)(m_time_counter*speed);
215         m_time_counter -= (f32)units / speed;
216         bool sync_f = false;
217         if(units > 0){
218                 // Sync at overflow
219                 if(m_time_of_day + units >= 24000)
220                         sync_f = true;
221                 m_time_of_day = (m_time_of_day + units) % 24000;
222                 if(sync_f)
223                         m_time_of_day_f = (float)m_time_of_day / 24000.0;
224         }
225         if(!sync_f){
226                 m_time_of_day_f += m_time_of_day_speed/24/3600*dtime;
227                 if(m_time_of_day_f > 1.0)
228                         m_time_of_day_f -= 1.0;
229                 if(m_time_of_day_f < 0.0)
230                         m_time_of_day_f += 1.0;
231         }
232 }
233
234 /*
235         ABMWithState
236 */
237
238 ABMWithState::ABMWithState(ActiveBlockModifier *abm_):
239         abm(abm_),
240         timer(0)
241 {
242         // Initialize timer to random value to spread processing
243         float itv = abm->getTriggerInterval();
244         itv = MYMAX(0.001, itv); // No less than 1ms
245         int minval = MYMAX(-0.51*itv, -60); // Clamp to
246         int maxval = MYMIN(0.51*itv, 60);   // +-60 seconds
247         timer = myrand_range(minval, maxval);
248 }
249
250 /*
251         ActiveBlockList
252 */
253
254 void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
255 {
256         v3s16 p;
257         for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
258         for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
259         for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
260         {
261                 // Set in list
262                 list.insert(p);
263         }
264 }
265
266 void ActiveBlockList::update(std::list<v3s16> &active_positions,
267                 s16 radius,
268                 std::set<v3s16> &blocks_removed,
269                 std::set<v3s16> &blocks_added)
270 {
271         /*
272                 Create the new list
273         */
274         std::set<v3s16> newlist;
275         for(std::list<v3s16>::iterator i = active_positions.begin();
276                         i != active_positions.end(); ++i)
277         {
278                 fillRadiusBlock(*i, radius, newlist);
279         }
280
281         /*
282                 Find out which blocks on the old list are not on the new list
283         */
284         // Go through old list
285         for(std::set<v3s16>::iterator i = m_list.begin();
286                         i != m_list.end(); ++i)
287         {
288                 v3s16 p = *i;
289                 // If not on new list, it's been removed
290                 if(newlist.find(p) == newlist.end())
291                         blocks_removed.insert(p);
292         }
293
294         /*
295                 Find out which blocks on the new list are not on the old list
296         */
297         // Go through new list
298         for(std::set<v3s16>::iterator i = newlist.begin();
299                         i != newlist.end(); ++i)
300         {
301                 v3s16 p = *i;
302                 // If not on old list, it's been added
303                 if(m_list.find(p) == m_list.end())
304                         blocks_added.insert(p);
305         }
306
307         /*
308                 Update m_list
309         */
310         m_list.clear();
311         for(std::set<v3s16>::iterator i = newlist.begin();
312                         i != newlist.end(); ++i)
313         {
314                 v3s16 p = *i;
315                 m_list.insert(p);
316         }
317 }
318
319 /*
320         ServerEnvironment
321 */
322
323 ServerEnvironment::ServerEnvironment(ServerMap *map, ScriptApi *scriptIface,
324                 IGameDef *gamedef, IBackgroundBlockEmerger *emerger):
325         m_map(map),
326         m_script(scriptIface),
327         m_gamedef(gamedef),
328         m_emerger(emerger),
329         m_random_spawn_timer(3),
330         m_send_recommended_timer(0),
331         m_active_block_interval_overload_skip(0),
332         m_game_time(0),
333         m_game_time_fraction_counter(0),
334         m_recommended_send_interval(0.1),
335         m_max_lag_estimate(0.1)
336 {
337 }
338
339 ServerEnvironment::~ServerEnvironment()
340 {
341         // Clear active block list.
342         // This makes the next one delete all active objects.
343         m_active_blocks.clear();
344
345         // Convert all objects to static and delete the active objects
346         deactivateFarObjects(true);
347
348         // Drop/delete map
349         m_map->drop();
350
351         // Delete ActiveBlockModifiers
352         for(std::list<ABMWithState>::iterator
353                         i = m_abms.begin(); i != m_abms.end(); ++i){
354                 delete i->abm;
355         }
356 }
357
358 Map & ServerEnvironment::getMap()
359 {
360         return *m_map;
361 }
362
363 ServerMap & ServerEnvironment::getServerMap()
364 {
365         return *m_map;
366 }
367
368 bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize)
369 {
370         float distance = pos1.getDistanceFrom(pos2);
371
372         //calculate normalized direction vector
373         v3f normalized_vector = v3f((pos2.X - pos1.X)/distance,
374                                                                 (pos2.Y - pos1.Y)/distance,
375                                                                 (pos2.Z - pos1.Z)/distance);
376
377         //find out if there's a node on path between pos1 and pos2
378         for (float i = 1; i < distance; i += stepsize) {
379                 v3s16 pos = floatToInt(v3f(normalized_vector.X * i,
380                                 normalized_vector.Y * i,
381                                 normalized_vector.Z * i) +pos1,BS);
382
383                 MapNode n = getMap().getNodeNoEx(pos);
384
385                 if(n.param0 != CONTENT_AIR) {
386                         return false;
387                 }
388         }
389         return true;
390 }
391
392 void ServerEnvironment::serializePlayers(const std::string &savedir)
393 {
394         std::string players_path = savedir + "/players";
395         fs::CreateDir(players_path);
396
397         std::set<Player*> saved_players;
398
399         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
400         for(u32 i=0; i<player_files.size(); i++)
401         {
402                 if(player_files[i].dir || player_files[i].name[0] == '.')
403                         continue;
404                 
405                 // Full path to this file
406                 std::string path = players_path + "/" + player_files[i].name;
407
408                 //infostream<<"Checking player file "<<path<<std::endl;
409
410                 // Load player to see what is its name
411                 RemotePlayer testplayer(m_gamedef);
412                 {
413                         // Open file and deserialize
414                         std::ifstream is(path.c_str(), std::ios_base::binary);
415                         if(is.good() == false)
416                         {
417                                 infostream<<"Failed to read "<<path<<std::endl;
418                                 continue;
419                         }
420                         testplayer.deSerialize(is, player_files[i].name);
421                 }
422
423                 //infostream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
424                 
425                 // Search for the player
426                 std::string playername = testplayer.getName();
427                 Player *player = getPlayer(playername.c_str());
428                 if(player == NULL)
429                 {
430                         infostream<<"Didn't find matching player, ignoring file "<<path<<std::endl;
431                         continue;
432                 }
433
434                 //infostream<<"Found matching player, overwriting."<<std::endl;
435
436                 // OK, found. Save player there.
437                 if(player->checkModified())
438                 {
439                         // Open file and serialize
440                         std::ostringstream ss(std::ios_base::binary);
441                         player->serialize(ss);
442                         if(!fs::safeWriteToFile(path, ss.str()))
443                         {
444                                 infostream<<"Failed to write "<<path<<std::endl;
445                                 continue;
446                         }
447                         saved_players.insert(player);
448                 } else {
449                         saved_players.insert(player);
450                 }
451         }
452
453         for(std::list<Player*>::iterator i = m_players.begin();
454                         i != m_players.end(); ++i)
455         {
456                 Player *player = *i;
457                 if(saved_players.find(player) != saved_players.end())
458                 {
459                         /*infostream<<"Player "<<player->getName()
460                                         <<" was already saved."<<std::endl;*/
461                         continue;
462                 }
463                 std::string playername = player->getName();
464                 // Don't save unnamed player
465                 if(playername == "")
466                 {
467                         //infostream<<"Not saving unnamed player."<<std::endl;
468                         continue;
469                 }
470                 /*
471                         Find a sane filename
472                 */
473                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
474                         playername = "player";
475                 std::string path = players_path + "/" + playername;
476                 bool found = false;
477                 for(u32 i=0; i<1000; i++)
478                 {
479                         if(fs::PathExists(path) == false)
480                         {
481                                 found = true;
482                                 break;
483                         }
484                         path = players_path + "/" + playername + itos(i);
485                 }
486                 if(found == false)
487                 {
488                         infostream<<"Didn't find free file for player"<<std::endl;
489                         continue;
490                 }
491
492                 {
493                         /*infostream<<"Saving player "<<player->getName()<<" to "
494                                         <<path<<std::endl;*/
495                         // Open file and serialize
496                         std::ostringstream ss(std::ios_base::binary);
497                         player->serialize(ss);
498                         if(!fs::safeWriteToFile(path, ss.str()))
499                         {
500                                 infostream<<"Failed to write "<<path<<std::endl;
501                                 continue;
502                         }
503                         saved_players.insert(player);
504                 }
505         }
506
507         //infostream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
508 }
509
510 void ServerEnvironment::deSerializePlayers(const std::string &savedir)
511 {
512         std::string players_path = savedir + "/players";
513
514         std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
515         for(u32 i=0; i<player_files.size(); i++)
516         {
517                 if(player_files[i].dir)
518                         continue;
519                 
520                 // Full path to this file
521                 std::string path = players_path + "/" + player_files[i].name;
522
523                 //infostream<<"Checking player file "<<path<<std::endl;
524
525                 // Load player to see what is its name
526                 RemotePlayer testplayer(m_gamedef);
527                 {
528                         // Open file and deserialize
529                         std::ifstream is(path.c_str(), std::ios_base::binary);
530                         if(is.good() == false)
531                         {
532                                 infostream<<"Failed to read "<<path<<std::endl;
533                                 continue;
534                         }
535                         testplayer.deSerialize(is, player_files[i].name);
536                 }
537
538                 if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS))
539                 {
540                         infostream<<"Not loading player with invalid name: "
541                                         <<testplayer.getName()<<std::endl;
542                 }
543
544                 /*infostream<<"Loaded test player with name "<<testplayer.getName()
545                                 <<std::endl;*/
546                 
547                 // Search for the player
548                 std::string playername = testplayer.getName();
549                 Player *player = getPlayer(playername.c_str());
550                 bool newplayer = false;
551                 if(player == NULL)
552                 {
553                         //infostream<<"Is a new player"<<std::endl;
554                         player = new RemotePlayer(m_gamedef);
555                         newplayer = true;
556                 }
557
558                 // Load player
559                 {
560                         verbosestream<<"Reading player "<<testplayer.getName()<<" from "
561                                         <<path<<std::endl;
562                         // Open file and deserialize
563                         std::ifstream is(path.c_str(), std::ios_base::binary);
564                         if(is.good() == false)
565                         {
566                                 infostream<<"Failed to read "<<path<<std::endl;
567                                 continue;
568                         }
569                         player->deSerialize(is, player_files[i].name);
570                 }
571
572                 if(newplayer)
573                 {
574                         addPlayer(player);
575                 }
576         }
577 }
578
579 void ServerEnvironment::saveMeta(const std::string &savedir)
580 {
581         std::string path = savedir + "/env_meta.txt";
582
583         // Open file and serialize
584         std::ostringstream ss(std::ios_base::binary);
585
586         Settings args;
587         args.setU64("game_time", m_game_time);
588         args.setU64("time_of_day", getTimeOfDay());
589         args.writeLines(ss);
590         ss<<"EnvArgsEnd\n";
591
592         if(!fs::safeWriteToFile(path, ss.str()))
593         {
594                 infostream<<"ServerEnvironment::saveMeta(): Failed to write "
595                                 <<path<<std::endl;
596                 throw SerializationError("Couldn't save env meta");
597         }
598 }
599
600 void ServerEnvironment::loadMeta(const std::string &savedir)
601 {
602         std::string path = savedir + "/env_meta.txt";
603
604         // Open file and deserialize
605         std::ifstream is(path.c_str(), std::ios_base::binary);
606         if(is.good() == false)
607         {
608                 infostream<<"ServerEnvironment::loadMeta(): Failed to open "
609                                 <<path<<std::endl;
610                 throw SerializationError("Couldn't load env meta");
611         }
612
613         Settings args;
614         
615         for(;;)
616         {
617                 if(is.eof())
618                         throw SerializationError
619                                         ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
620                 std::string line;
621                 std::getline(is, line);
622                 std::string trimmedline = trim(line);
623                 if(trimmedline == "EnvArgsEnd")
624                         break;
625                 args.parseConfigLine(line);
626         }
627         
628         try{
629                 m_game_time = args.getU64("game_time");
630         }catch(SettingNotFoundException &e){
631                 // Getting this is crucial, otherwise timestamps are useless
632                 throw SerializationError("Couldn't load env meta game_time");
633         }
634
635         try{
636                 m_time_of_day = args.getU64("time_of_day");
637         }catch(SettingNotFoundException &e){
638                 // This is not as important
639                 m_time_of_day = 9000;
640         }
641 }
642
643 struct ActiveABM
644 {
645         ActiveBlockModifier *abm;
646         int chance;
647         std::set<content_t> required_neighbors;
648 };
649
650 class ABMHandler
651 {
652 private:
653         ServerEnvironment *m_env;
654         std::map<content_t, std::list<ActiveABM> > m_aabms;
655 public:
656         ABMHandler(std::list<ABMWithState> &abms,
657                         float dtime_s, ServerEnvironment *env,
658                         bool use_timers):
659                 m_env(env)
660         {
661                 if(dtime_s < 0.001)
662                         return;
663                 INodeDefManager *ndef = env->getGameDef()->ndef();
664                 for(std::list<ABMWithState>::iterator
665                                 i = abms.begin(); i != abms.end(); ++i){
666                         ActiveBlockModifier *abm = i->abm;
667                         float trigger_interval = abm->getTriggerInterval();
668                         if(trigger_interval < 0.001)
669                                 trigger_interval = 0.001;
670                         float actual_interval = dtime_s;
671                         if(use_timers){
672                                 i->timer += dtime_s;
673                                 if(i->timer < trigger_interval)
674                                         continue;
675                                 i->timer -= trigger_interval;
676                                 actual_interval = trigger_interval;
677                         }
678                         float intervals = actual_interval / trigger_interval;
679                         if(intervals == 0)
680                                 continue;
681                         float chance = abm->getTriggerChance();
682                         if(chance == 0)
683                                 chance = 1;
684                         ActiveABM aabm;
685                         aabm.abm = abm;
686                         aabm.chance = chance / intervals;
687                         if(aabm.chance == 0)
688                                 aabm.chance = 1;
689                         // Trigger neighbors
690                         std::set<std::string> required_neighbors_s
691                                         = abm->getRequiredNeighbors();
692                         for(std::set<std::string>::iterator
693                                         i = required_neighbors_s.begin();
694                                         i != required_neighbors_s.end(); i++)
695                         {
696                                 ndef->getIds(*i, aabm.required_neighbors);
697                         }
698                         // Trigger contents
699                         std::set<std::string> contents_s = abm->getTriggerContents();
700                         for(std::set<std::string>::iterator
701                                         i = contents_s.begin(); i != contents_s.end(); i++)
702                         {
703                                 std::set<content_t> ids;
704                                 ndef->getIds(*i, ids);
705                                 for(std::set<content_t>::const_iterator k = ids.begin();
706                                                 k != ids.end(); k++)
707                                 {
708                                         content_t c = *k;
709                                         std::map<content_t, std::list<ActiveABM> >::iterator j;
710                                         j = m_aabms.find(c);
711                                         if(j == m_aabms.end()){
712                                                 std::list<ActiveABM> aabmlist;
713                                                 m_aabms[c] = aabmlist;
714                                                 j = m_aabms.find(c);
715                                         }
716                                         j->second.push_back(aabm);
717                                 }
718                         }
719                 }
720         }
721         void apply(MapBlock *block)
722         {
723                 if(m_aabms.empty())
724                         return;
725
726                 ServerMap *map = &m_env->getServerMap();
727
728                 v3s16 p0;
729                 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
730                 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
731                 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
732                 {
733                         MapNode n = block->getNodeNoEx(p0);
734                         content_t c = n.getContent();
735                         v3s16 p = p0 + block->getPosRelative();
736
737                         std::map<content_t, std::list<ActiveABM> >::iterator j;
738                         j = m_aabms.find(c);
739                         if(j == m_aabms.end())
740                                 continue;
741
742                         for(std::list<ActiveABM>::iterator
743                                         i = j->second.begin(); i != j->second.end(); i++)
744                         {
745                                 if(myrand() % i->chance != 0)
746                                         continue;
747
748                                 // Check neighbors
749                                 if(!i->required_neighbors.empty())
750                                 {
751                                         v3s16 p1;
752                                         for(p1.X = p.X-1; p1.X <= p.X+1; p1.X++)
753                                         for(p1.Y = p.Y-1; p1.Y <= p.Y+1; p1.Y++)
754                                         for(p1.Z = p.Z-1; p1.Z <= p.Z+1; p1.Z++)
755                                         {
756                                                 if(p1 == p)
757                                                         continue;
758                                                 MapNode n = map->getNodeNoEx(p1);
759                                                 content_t c = n.getContent();
760                                                 std::set<content_t>::const_iterator k;
761                                                 k = i->required_neighbors.find(c);
762                                                 if(k != i->required_neighbors.end()){
763                                                         goto neighbor_found;
764                                                 }
765                                         }
766                                         // No required neighbor found
767                                         continue;
768                                 }
769 neighbor_found:
770
771                                 // Find out how many objects the block contains
772                                 u32 active_object_count = block->m_static_objects.m_active.size();
773                                 // Find out how many objects this and all the neighbors contain
774                                 u32 active_object_count_wider = 0;
775                                 u32 wider_unknown_count = 0;
776                                 for(s16 x=-1; x<=1; x++)
777                                 for(s16 y=-1; y<=1; y++)
778                                 for(s16 z=-1; z<=1; z++)
779                                 {
780                                         MapBlock *block2 = map->getBlockNoCreateNoEx(
781                                                         block->getPos() + v3s16(x,y,z));
782                                         if(block2==NULL){
783                                                 wider_unknown_count = 0;
784                                                 continue;
785                                         }
786                                         active_object_count_wider +=
787                                                         block2->m_static_objects.m_active.size()
788                                                         + block2->m_static_objects.m_stored.size();
789                                 }
790                                 // Extrapolate
791                                 u32 wider_known_count = 3*3*3 - wider_unknown_count;
792                                 active_object_count_wider += wider_unknown_count * active_object_count_wider / wider_known_count;
793                                 
794                                 // Call all the trigger variations
795                                 i->abm->trigger(m_env, p, n);
796                                 i->abm->trigger(m_env, p, n,
797                                                 active_object_count, active_object_count_wider);
798                         }
799                 }
800         }
801 };
802
803 void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
804 {
805         // Get time difference
806         u32 dtime_s = 0;
807         u32 stamp = block->getTimestamp();
808         if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
809                 dtime_s = m_game_time - block->getTimestamp();
810         dtime_s += additional_dtime;
811
812         /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
813                         <<stamp<<", game time: "<<m_game_time<<std::endl;*/
814
815         // Set current time as timestamp
816         block->setTimestampNoChangedFlag(m_game_time);
817
818         /*infostream<<"ServerEnvironment::activateBlock(): block is "
819                         <<dtime_s<<" seconds old."<<std::endl;*/
820         
821         // Activate stored objects
822         activateObjects(block, dtime_s);
823
824         // Run node timers
825         std::map<v3s16, NodeTimer> elapsed_timers =
826                 block->m_node_timers.step((float)dtime_s);
827         if(!elapsed_timers.empty()){
828                 MapNode n;
829                 for(std::map<v3s16, NodeTimer>::iterator
830                                 i = elapsed_timers.begin();
831                                 i != elapsed_timers.end(); i++){
832                         n = block->getNodeNoEx(i->first);
833                         v3s16 p = i->first + block->getPosRelative();
834                         if(m_script->node_on_timer(p,n,i->second.elapsed))
835                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
836                 }
837         }
838
839         /* Handle ActiveBlockModifiers */
840         ABMHandler abmhandler(m_abms, dtime_s, this, false);
841         abmhandler.apply(block);
842 }
843
844 void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
845 {
846         m_abms.push_back(ABMWithState(abm));
847 }
848
849 bool ServerEnvironment::setNode(v3s16 p, const MapNode &n)
850 {
851         INodeDefManager *ndef = m_gamedef->ndef();
852         MapNode n_old = m_map->getNodeNoEx(p);
853         // Call destructor
854         if(ndef->get(n_old).has_on_destruct)
855                 m_script->node_on_destruct(p, n_old);
856         // Replace node
857         bool succeeded = m_map->addNodeWithEvent(p, n);
858         if(!succeeded)
859                 return false;
860         // Call post-destructor
861         if(ndef->get(n_old).has_after_destruct)
862                 m_script->node_after_destruct(p, n_old);
863         // Call constructor
864         if(ndef->get(n).has_on_construct)
865                 m_script->node_on_construct(p, n);
866         return true;
867 }
868
869 bool ServerEnvironment::removeNode(v3s16 p)
870 {
871         INodeDefManager *ndef = m_gamedef->ndef();
872         MapNode n_old = m_map->getNodeNoEx(p);
873         // Call destructor
874         if(ndef->get(n_old).has_on_destruct)
875                 m_script->node_on_destruct(p, n_old);
876         // Replace with air
877         // This is slightly optimized compared to addNodeWithEvent(air)
878         bool succeeded = m_map->removeNodeWithEvent(p);
879         if(!succeeded)
880                 return false;
881         // Call post-destructor
882         if(ndef->get(n_old).has_after_destruct)
883                 m_script->node_after_destruct(p, n_old);
884         // Air doesn't require constructor
885         return true;
886 }
887
888 std::set<u16> ServerEnvironment::getObjectsInsideRadius(v3f pos, float radius)
889 {
890         std::set<u16> objects;
891         for(std::map<u16, ServerActiveObject*>::iterator
892                         i = m_active_objects.begin();
893                         i != m_active_objects.end(); ++i)
894         {
895                 ServerActiveObject* obj = i->second;
896                 u16 id = i->first;
897                 v3f objectpos = obj->getBasePosition();
898                 if(objectpos.getDistanceFrom(pos) > radius)
899                         continue;
900                 objects.insert(id);
901         }
902         return objects;
903 }
904
905 void ServerEnvironment::clearAllObjects()
906 {
907         infostream<<"ServerEnvironment::clearAllObjects(): "
908                         <<"Removing all active objects"<<std::endl;
909         std::list<u16> objects_to_remove;
910         for(std::map<u16, ServerActiveObject*>::iterator
911                         i = m_active_objects.begin();
912                         i != m_active_objects.end(); ++i)
913         {
914                 ServerActiveObject* obj = i->second;
915                 if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
916                         continue;
917                 u16 id = i->first;
918                 // Delete static object if block is loaded
919                 if(obj->m_static_exists){
920                         MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
921                         if(block){
922                                 block->m_static_objects.remove(id);
923                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
924                                                 "clearAllObjects");
925                                 obj->m_static_exists = false;
926                         }
927                 }
928                 // If known by some client, don't delete immediately
929                 if(obj->m_known_by_count > 0){
930                         obj->m_pending_deactivation = true;
931                         obj->m_removed = true;
932                         continue;
933                 }
934
935                 // Tell the object about removal
936                 obj->removingFromEnvironment();
937                 // Deregister in scripting api
938                 m_script->removeObjectReference(obj);
939
940                 // Delete active object
941                 if(obj->environmentDeletes())
942                         delete obj;
943                 // Id to be removed from m_active_objects
944                 objects_to_remove.push_back(id);
945         }
946         // Remove references from m_active_objects
947         for(std::list<u16>::iterator i = objects_to_remove.begin();
948                         i != objects_to_remove.end(); ++i)
949         {
950                 m_active_objects.erase(*i);
951         }
952
953         // Get list of loaded blocks
954         std::list<v3s16> loaded_blocks;
955         infostream<<"ServerEnvironment::clearAllObjects(): "
956                         <<"Listing all loaded blocks"<<std::endl;
957         m_map->listAllLoadedBlocks(loaded_blocks);
958         infostream<<"ServerEnvironment::clearAllObjects(): "
959                         <<"Done listing all loaded blocks: "
960                         <<loaded_blocks.size()<<std::endl;
961
962         // Get list of loadable blocks
963         std::list<v3s16> loadable_blocks;
964         infostream<<"ServerEnvironment::clearAllObjects(): "
965                         <<"Listing all loadable blocks"<<std::endl;
966         m_map->listAllLoadableBlocks(loadable_blocks);
967         infostream<<"ServerEnvironment::clearAllObjects(): "
968                         <<"Done listing all loadable blocks: "
969                         <<loadable_blocks.size()
970                         <<", now clearing"<<std::endl;
971
972         // Grab a reference on each loaded block to avoid unloading it
973         for(std::list<v3s16>::iterator i = loaded_blocks.begin();
974                         i != loaded_blocks.end(); ++i)
975         {
976                 v3s16 p = *i;
977                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
978                 assert(block);
979                 block->refGrab();
980         }
981
982         // Remove objects in all loadable blocks
983         u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
984         unload_interval = MYMAX(unload_interval, 1);
985         u32 report_interval = loadable_blocks.size() / 10;
986         u32 num_blocks_checked = 0;
987         u32 num_blocks_cleared = 0;
988         u32 num_objs_cleared = 0;
989         for(std::list<v3s16>::iterator i = loadable_blocks.begin();
990                         i != loadable_blocks.end(); ++i)
991         {
992                 v3s16 p = *i;
993                 MapBlock *block = m_map->emergeBlock(p, false);
994                 if(!block){
995                         errorstream<<"ServerEnvironment::clearAllObjects(): "
996                                         <<"Failed to emerge block "<<PP(p)<<std::endl;
997                         continue;
998                 }
999                 u32 num_stored = block->m_static_objects.m_stored.size();
1000                 u32 num_active = block->m_static_objects.m_active.size();
1001                 if(num_stored != 0 || num_active != 0){
1002                         block->m_static_objects.m_stored.clear();
1003                         block->m_static_objects.m_active.clear();
1004                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
1005                                         "clearAllObjects");
1006                         num_objs_cleared += num_stored + num_active;
1007                         num_blocks_cleared++;
1008                 }
1009                 num_blocks_checked++;
1010
1011                 if(num_blocks_checked % report_interval == 0){
1012                         float percent = 100.0 * (float)num_blocks_checked /
1013                                         loadable_blocks.size();
1014                         infostream<<"ServerEnvironment::clearAllObjects(): "
1015                                         <<"Cleared "<<num_objs_cleared<<" objects"
1016                                         <<" in "<<num_blocks_cleared<<" blocks ("
1017                                         <<percent<<"%)"<<std::endl;
1018                 }
1019                 if(num_blocks_checked % unload_interval == 0){
1020                         m_map->unloadUnreferencedBlocks();
1021                 }
1022         }
1023         m_map->unloadUnreferencedBlocks();
1024
1025         // Drop references that were added above
1026         for(std::list<v3s16>::iterator i = loaded_blocks.begin();
1027                         i != loaded_blocks.end(); ++i)
1028         {
1029                 v3s16 p = *i;
1030                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1031                 assert(block);
1032                 block->refDrop();
1033         }
1034
1035         infostream<<"ServerEnvironment::clearAllObjects(): "
1036                         <<"Finished: Cleared "<<num_objs_cleared<<" objects"
1037                         <<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
1038 }
1039
1040 void ServerEnvironment::step(float dtime)
1041 {
1042         DSTACK(__FUNCTION_NAME);
1043         
1044         //TimeTaker timer("ServerEnv step");
1045
1046         /* Step time of day */
1047         stepTimeOfDay(dtime);
1048
1049         // Update this one
1050         // NOTE: This is kind of funny on a singleplayer game, but doesn't
1051         // really matter that much.
1052         m_recommended_send_interval = g_settings->getFloat("dedicated_server_step");
1053
1054         /*
1055                 Increment game time
1056         */
1057         {
1058                 m_game_time_fraction_counter += dtime;
1059                 u32 inc_i = (u32)m_game_time_fraction_counter;
1060                 m_game_time += inc_i;
1061                 m_game_time_fraction_counter -= (float)inc_i;
1062         }
1063         
1064         /*
1065                 Handle players
1066         */
1067         {
1068                 ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
1069                 for(std::list<Player*>::iterator i = m_players.begin();
1070                                 i != m_players.end(); ++i)
1071                 {
1072                         Player *player = *i;
1073                         
1074                         // Ignore disconnected players
1075                         if(player->peer_id == 0)
1076                                 continue;
1077                         
1078                         // Move
1079                         player->move(dtime, *m_map, 100*BS);
1080                 }
1081         }
1082
1083         /*
1084                 Manage active block list
1085         */
1086         if(m_active_blocks_management_interval.step(dtime, 2.0))
1087         {
1088                 ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg /2s", SPT_AVG);
1089                 /*
1090                         Get player block positions
1091                 */
1092                 std::list<v3s16> players_blockpos;
1093                 for(std::list<Player*>::iterator
1094                                 i = m_players.begin();
1095                                 i != m_players.end(); ++i)
1096                 {
1097                         Player *player = *i;
1098                         // Ignore disconnected players
1099                         if(player->peer_id == 0)
1100                                 continue;
1101                         v3s16 blockpos = getNodeBlockPos(
1102                                         floatToInt(player->getPosition(), BS));
1103                         players_blockpos.push_back(blockpos);
1104                 }
1105                 
1106                 /*
1107                         Update list of active blocks, collecting changes
1108                 */
1109                 const s16 active_block_range = g_settings->getS16("active_block_range");
1110                 std::set<v3s16> blocks_removed;
1111                 std::set<v3s16> blocks_added;
1112                 m_active_blocks.update(players_blockpos, active_block_range,
1113                                 blocks_removed, blocks_added);
1114
1115                 /*
1116                         Handle removed blocks
1117                 */
1118
1119                 // Convert active objects that are no more in active blocks to static
1120                 deactivateFarObjects(false);
1121                 
1122                 for(std::set<v3s16>::iterator
1123                                 i = blocks_removed.begin();
1124                                 i != blocks_removed.end(); ++i)
1125                 {
1126                         v3s16 p = *i;
1127
1128                         /* infostream<<"Server: Block " << PP(p)
1129                                 << " became inactive"<<std::endl; */
1130                         
1131                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1132                         if(block==NULL)
1133                                 continue;
1134                         
1135                         // Set current time as timestamp (and let it set ChangedFlag)
1136                         block->setTimestamp(m_game_time);
1137                 }
1138
1139                 /*
1140                         Handle added blocks
1141                 */
1142
1143                 for(std::set<v3s16>::iterator
1144                                 i = blocks_added.begin();
1145                                 i != blocks_added.end(); ++i)
1146                 {
1147                         v3s16 p = *i;
1148
1149                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1150                         if(block==NULL){
1151                                 // Block needs to be fetched first
1152                                 m_emerger->queueBlockEmerge(p, false);
1153                                 m_active_blocks.m_list.erase(p);
1154                                 continue;
1155                         }
1156
1157                         activateBlock(block);
1158                         /* infostream<<"Server: Block " << PP(p)
1159                                 << " became active"<<std::endl; */
1160                 }
1161         }
1162
1163         /*
1164                 Mess around in active blocks
1165         */
1166         if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
1167         {
1168                 ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg /1s", SPT_AVG);
1169                 
1170                 float dtime = 1.0;
1171
1172                 for(std::set<v3s16>::iterator
1173                                 i = m_active_blocks.m_list.begin();
1174                                 i != m_active_blocks.m_list.end(); ++i)
1175                 {
1176                         v3s16 p = *i;
1177                         
1178                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1179                                         <<") being handled"<<std::endl;*/
1180
1181                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1182                         if(block==NULL)
1183                                 continue;
1184
1185                         // Reset block usage timer
1186                         block->resetUsageTimer();
1187                         
1188                         // Set current time as timestamp
1189                         block->setTimestampNoChangedFlag(m_game_time);
1190                         // If time has changed much from the one on disk,
1191                         // set block to be saved when it is unloaded
1192                         if(block->getTimestamp() > block->getDiskTimestamp() + 60)
1193                                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1194                                                 "Timestamp older than 60s (step)");
1195
1196                         // Run node timers
1197                         std::map<v3s16, NodeTimer> elapsed_timers =
1198                                 block->m_node_timers.step((float)dtime);
1199                         if(!elapsed_timers.empty()){
1200                                 MapNode n;
1201                                 for(std::map<v3s16, NodeTimer>::iterator
1202                                                 i = elapsed_timers.begin();
1203                                                 i != elapsed_timers.end(); i++){
1204                                         n = block->getNodeNoEx(i->first);
1205                                         p = i->first + block->getPosRelative();
1206                                         if(m_script->node_on_timer(p,n,i->second.elapsed))
1207                                                 block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
1208                                 }
1209                         }
1210                 }
1211         }
1212         
1213         const float abm_interval = 1.0;
1214         if(m_active_block_modifier_interval.step(dtime, abm_interval))
1215         do{ // breakable
1216                 if(m_active_block_interval_overload_skip > 0){
1217                         ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
1218                         m_active_block_interval_overload_skip--;
1219                         break;
1220                 }
1221                 ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg /1s", SPT_AVG);
1222                 TimeTaker timer("modify in active blocks");
1223                 
1224                 // Initialize handling of ActiveBlockModifiers
1225                 ABMHandler abmhandler(m_abms, abm_interval, this, true);
1226
1227                 for(std::set<v3s16>::iterator
1228                                 i = m_active_blocks.m_list.begin();
1229                                 i != m_active_blocks.m_list.end(); ++i)
1230                 {
1231                         v3s16 p = *i;
1232                         
1233                         /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
1234                                         <<") being handled"<<std::endl;*/
1235
1236                         MapBlock *block = m_map->getBlockNoCreateNoEx(p);
1237                         if(block==NULL)
1238                                 continue;
1239                         
1240                         // Set current time as timestamp
1241                         block->setTimestampNoChangedFlag(m_game_time);
1242
1243                         /* Handle ActiveBlockModifiers */
1244                         abmhandler.apply(block);
1245                 }
1246
1247                 u32 time_ms = timer.stop(true);
1248                 u32 max_time_ms = 200;
1249                 if(time_ms > max_time_ms){
1250                         infostream<<"WARNING: active block modifiers took "
1251                                         <<time_ms<<"ms (longer than "
1252                                         <<max_time_ms<<"ms)"<<std::endl;
1253                         m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
1254                 }
1255         }while(0);
1256         
1257         /*
1258                 Step script environment (run global on_step())
1259         */
1260         m_script->environment_Step(dtime);
1261
1262         /*
1263                 Step active objects
1264         */
1265         {
1266                 ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
1267                 //TimeTaker timer("Step active objects");
1268
1269                 g_profiler->avg("SEnv: num of objects", m_active_objects.size());
1270                 
1271                 // This helps the objects to send data at the same time
1272                 bool send_recommended = false;
1273                 m_send_recommended_timer += dtime;
1274                 if(m_send_recommended_timer > getSendRecommendedInterval())
1275                 {
1276                         m_send_recommended_timer -= getSendRecommendedInterval();
1277                         send_recommended = true;
1278                 }
1279
1280                 for(std::map<u16, ServerActiveObject*>::iterator
1281                                 i = m_active_objects.begin();
1282                                 i != m_active_objects.end(); ++i)
1283                 {
1284                         ServerActiveObject* obj = i->second;
1285                         // Remove non-peaceful mobs on peaceful mode
1286                         if(g_settings->getBool("only_peaceful_mobs")){
1287                                 if(!obj->isPeaceful())
1288                                         obj->m_removed = true;
1289                         }
1290                         // Don't step if is to be removed or stored statically
1291                         if(obj->m_removed || obj->m_pending_deactivation)
1292                                 continue;
1293                         // Step object
1294                         obj->step(dtime, send_recommended);
1295                         // Read messages from object
1296                         while(!obj->m_messages_out.empty())
1297                         {
1298                                 m_active_object_messages.push_back(
1299                                                 obj->m_messages_out.pop_front());
1300                         }
1301                 }
1302         }
1303         
1304         /*
1305                 Manage active objects
1306         */
1307         if(m_object_management_interval.step(dtime, 0.5))
1308         {
1309                 ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
1310                 /*
1311                         Remove objects that satisfy (m_removed && m_known_by_count==0)
1312                 */
1313                 removeRemovedObjects();
1314         }
1315 }
1316
1317 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
1318 {
1319         std::map<u16, ServerActiveObject*>::iterator n;
1320         n = m_active_objects.find(id);
1321         if(n == m_active_objects.end())
1322                 return NULL;
1323         return n->second;
1324 }
1325
1326 bool isFreeServerActiveObjectId(u16 id,
1327                 std::map<u16, ServerActiveObject*> &objects)
1328 {
1329         if(id == 0)
1330                 return false;
1331
1332         return objects.find(id) == objects.end();
1333 }
1334
1335 u16 getFreeServerActiveObjectId(
1336                 std::map<u16, ServerActiveObject*> &objects)
1337 {
1338         //try to reuse id's as late as possible
1339         static u16 last_used_id = 0;
1340         u16 startid = last_used_id;
1341         for(;;)
1342         {
1343                 last_used_id ++;
1344                 if(isFreeServerActiveObjectId(last_used_id, objects))
1345                         return last_used_id;
1346                 
1347                 if(last_used_id == startid)
1348                         return 0;
1349         }
1350 }
1351
1352 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1353 {
1354         assert(object);
1355         u16 id = addActiveObjectRaw(object, true, 0);
1356         return id;
1357 }
1358
1359 #if 0
1360 bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
1361 {
1362         assert(obj);
1363
1364         v3f objectpos = obj->getBasePosition(); 
1365
1366         // The block in which the object resides in
1367         v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1368
1369         /*
1370                 Update the static data
1371         */
1372
1373         // Create new static object
1374         std::string staticdata = obj->getStaticData();
1375         StaticObject s_obj(obj->getType(), objectpos, staticdata);
1376         // Add to the block where the object is located in
1377         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1378         // Get or generate the block
1379         MapBlock *block = m_map->emergeBlock(blockpos);
1380
1381         bool succeeded = false;
1382
1383         if(block)
1384         {
1385                 block->m_static_objects.insert(0, s_obj);
1386                 block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
1387                                 "addActiveObjectAsStatic");
1388                 succeeded = true;
1389         }
1390         else{
1391                 infostream<<"ServerEnvironment::addActiveObjectAsStatic: "
1392                                 <<"Could not find or generate "
1393                                 <<"a block for storing static object"<<std::endl;
1394                 succeeded = false;
1395         }
1396
1397         if(obj->environmentDeletes())
1398                 delete obj;
1399
1400         return succeeded;
1401 }
1402 #endif
1403
1404 /*
1405         Finds out what new objects have been added to
1406         inside a radius around a position
1407 */
1408 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1409                 std::set<u16> &current_objects,
1410                 std::set<u16> &added_objects)
1411 {
1412         v3f pos_f = intToFloat(pos, BS);
1413         f32 radius_f = radius * BS;
1414         /*
1415                 Go through the object list,
1416                 - discard m_removed objects,
1417                 - discard objects that are too far away,
1418                 - discard objects that are found in current_objects.
1419                 - add remaining objects to added_objects
1420         */
1421         for(std::map<u16, ServerActiveObject*>::iterator
1422                         i = m_active_objects.begin();
1423                         i != m_active_objects.end(); ++i)
1424         {
1425                 u16 id = i->first;
1426                 // Get object
1427                 ServerActiveObject *object = i->second;
1428                 if(object == NULL)
1429                         continue;
1430                 // Discard if removed
1431                 if(object->m_removed)
1432                         continue;
1433                 if(object->unlimitedTransferDistance() == false){
1434                         // Discard if too far
1435                         f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1436                         if(distance_f > radius_f)
1437                                 continue;
1438                 }
1439                 // Discard if already on current_objects
1440                 std::set<u16>::iterator n;
1441                 n = current_objects.find(id);
1442                 if(n != current_objects.end())
1443                         continue;
1444                 // Add to added_objects
1445                 added_objects.insert(id);
1446         }
1447 }
1448
1449 /*
1450         Finds out what objects have been removed from
1451         inside a radius around a position
1452 */
1453 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1454                 std::set<u16> &current_objects,
1455                 std::set<u16> &removed_objects)
1456 {
1457         v3f pos_f = intToFloat(pos, BS);
1458         f32 radius_f = radius * BS;
1459         /*
1460                 Go through current_objects; object is removed if:
1461                 - object is not found in m_active_objects (this is actually an
1462                   error condition; objects should be set m_removed=true and removed
1463                   only after all clients have been informed about removal), or
1464                 - object has m_removed=true, or
1465                 - object is too far away
1466         */
1467         for(std::set<u16>::iterator
1468                         i = current_objects.begin();
1469                         i != current_objects.end(); ++i)
1470         {
1471                 u16 id = *i;
1472                 ServerActiveObject *object = getActiveObject(id);
1473
1474                 if(object == NULL){
1475                         infostream<<"ServerEnvironment::getRemovedActiveObjects():"
1476                                         <<" object in current_objects is NULL"<<std::endl;
1477                         removed_objects.insert(id);
1478                         continue;
1479                 }
1480
1481                 if(object->m_removed)
1482                 {
1483                         removed_objects.insert(id);
1484                         continue;
1485                 }
1486                 
1487                 // If transfer distance is unlimited, don't remove
1488                 if(object->unlimitedTransferDistance())
1489                         continue;
1490
1491                 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1492
1493                 if(distance_f >= radius_f)
1494                 {
1495                         removed_objects.insert(id);
1496                         continue;
1497                 }
1498                 
1499                 // Not removed
1500         }
1501 }
1502
1503 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1504 {
1505         if(m_active_object_messages.empty())
1506                 return ActiveObjectMessage(0);
1507         
1508         return m_active_object_messages.pop_front();
1509 }
1510
1511 /*
1512         ************ Private methods *************
1513 */
1514
1515 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1516                 bool set_changed, u32 dtime_s)
1517 {
1518         assert(object);
1519         if(object->getId() == 0){
1520                 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
1521                 if(new_id == 0)
1522                 {
1523                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1524                                         <<"no free ids available"<<std::endl;
1525                         if(object->environmentDeletes())
1526                                 delete object;
1527                         return 0;
1528                 }
1529                 object->setId(new_id);
1530         }
1531         else{
1532                 verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1533                                 <<"supplied with id "<<object->getId()<<std::endl;
1534         }
1535         if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
1536         {
1537                 errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1538                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1539                 if(object->environmentDeletes())
1540                         delete object;
1541                 return 0;
1542         }
1543         /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
1544                         <<"added (id="<<object->getId()<<")"<<std::endl;*/
1545                         
1546         m_active_objects[object->getId()] = object;
1547   
1548         verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
1549                         <<"Added id="<<object->getId()<<"; there are now "
1550                         <<m_active_objects.size()<<" active objects."
1551                         <<std::endl;
1552         
1553         // Register reference in scripting api (must be done before post-init)
1554         m_script->addObjectReference(object);
1555         // Post-initialize object
1556         object->addedToEnvironment(dtime_s);
1557         
1558         // Add static data to block
1559         if(object->isStaticAllowed())
1560         {
1561                 // Add static object to active static list of the block
1562                 v3f objectpos = object->getBasePosition();
1563                 std::string staticdata = object->getStaticData();
1564                 StaticObject s_obj(object->getType(), objectpos, staticdata);
1565                 // Add to the block where the object is located in
1566                 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1567                 MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1568                 if(block)
1569                 {
1570                         block->m_static_objects.m_active[object->getId()] = s_obj;
1571                         object->m_static_exists = true;
1572                         object->m_static_block = blockpos;
1573
1574                         if(set_changed)
1575                                 block->raiseModified(MOD_STATE_WRITE_NEEDED, 
1576                                                 "addActiveObjectRaw");
1577                 }
1578                 else{
1579                         v3s16 p = floatToInt(objectpos, BS);
1580                         errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
1581                                         <<"could not find block for storing id="<<object->getId()
1582                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1583                 }
1584         }
1585         
1586         return object->getId();
1587 }
1588
1589 /*
1590         Remove objects that satisfy (m_removed && m_known_by_count==0)
1591 */
1592 void ServerEnvironment::removeRemovedObjects()
1593 {
1594         std::list<u16> objects_to_remove;
1595         for(std::map<u16, ServerActiveObject*>::iterator
1596                         i = m_active_objects.begin();
1597                         i != m_active_objects.end(); ++i)
1598         {
1599                 u16 id = i->first;
1600                 ServerActiveObject* obj = i->second;
1601                 // This shouldn't happen but check it
1602                 if(obj == NULL)
1603                 {
1604                         infostream<<"NULL object found in ServerEnvironment"
1605                                         <<" while finding removed objects. id="<<id<<std::endl;
1606                         // Id to be removed from m_active_objects
1607                         objects_to_remove.push_back(id);
1608                         continue;
1609                 }
1610
1611                 /*
1612                         We will delete objects that are marked as removed or thatare
1613                         waiting for deletion after deactivation
1614                 */
1615                 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1616                         continue;
1617
1618                 /*
1619                         Delete static data from block if is marked as removed
1620                 */
1621                 if(obj->m_static_exists && obj->m_removed)
1622                 {
1623                         MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1624                         if (block) {
1625                                 block->m_static_objects.remove(id);
1626                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1627                                                 "removeRemovedObjects");
1628                                 obj->m_static_exists = false;
1629                         } else {
1630                                 infostream << "failed to emerge block from which "
1631                                         "an object to be removed was loaded from. id="<<id<<std::endl;
1632                         }
1633                 }
1634
1635                 // If m_known_by_count > 0, don't actually remove.
1636                 if(obj->m_known_by_count > 0)
1637                         continue;
1638                 
1639                 // Tell the object about removal
1640                 obj->removingFromEnvironment();
1641                 // Deregister in scripting api
1642                 m_script->removeObjectReference(obj);
1643
1644                 // Delete
1645                 if(obj->environmentDeletes())
1646                         delete obj;
1647                 // Id to be removed from m_active_objects
1648                 objects_to_remove.push_back(id);
1649         }
1650         // Remove references from m_active_objects
1651         for(std::list<u16>::iterator i = objects_to_remove.begin();
1652                         i != objects_to_remove.end(); ++i)
1653         {
1654                 m_active_objects.erase(*i);
1655         }
1656 }
1657
1658 static void print_hexdump(std::ostream &o, const std::string &data)
1659 {
1660         const int linelength = 16;
1661         for(int l=0; ; l++){
1662                 int i0 = linelength * l;
1663                 bool at_end = false;
1664                 int thislinelength = linelength;
1665                 if(i0 + thislinelength > (int)data.size()){
1666                         thislinelength = data.size() - i0;
1667                         at_end = true;
1668                 }
1669                 for(int di=0; di<linelength; di++){
1670                         int i = i0 + di;
1671                         char buf[4];
1672                         if(di<thislinelength)
1673                                 snprintf(buf, 4, "%.2x ", data[i]);
1674                         else
1675                                 snprintf(buf, 4, "   ");
1676                         o<<buf;
1677                 }
1678                 o<<" ";
1679                 for(int di=0; di<thislinelength; di++){
1680                         int i = i0 + di;
1681                         if(data[i] >= 32)
1682                                 o<<data[i];
1683                         else
1684                                 o<<".";
1685                 }
1686                 o<<std::endl;
1687                 if(at_end)
1688                         break;
1689         }
1690 }
1691
1692 /*
1693         Convert stored objects from blocks near the players to active.
1694 */
1695 void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
1696 {
1697         if(block==NULL)
1698                 return;
1699         // Ignore if no stored objects (to not set changed flag)
1700         if(block->m_static_objects.m_stored.size() == 0)
1701                 return;
1702         verbosestream<<"ServerEnvironment::activateObjects(): "
1703                         <<"activating objects of block "<<PP(block->getPos())
1704                         <<" ("<<block->m_static_objects.m_stored.size()
1705                         <<" objects)"<<std::endl;
1706         bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
1707         if(large_amount){
1708                 errorstream<<"suspiciously large amount of objects detected: "
1709                                 <<block->m_static_objects.m_stored.size()<<" in "
1710                                 <<PP(block->getPos())
1711                                 <<"; removing all of them."<<std::endl;
1712                 // Clear stored list
1713                 block->m_static_objects.m_stored.clear();
1714                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1715                                 "stored list cleared in activateObjects due to "
1716                                 "large amount of objects");
1717                 return;
1718         }
1719         // A list for objects that couldn't be converted to active for some
1720         // reason. They will be stored back.
1721         std::list<StaticObject> new_stored;
1722         // Loop through stored static objects
1723         for(std::list<StaticObject>::iterator
1724                         i = block->m_static_objects.m_stored.begin();
1725                         i != block->m_static_objects.m_stored.end(); ++i)
1726         {
1727                 /*infostream<<"Server: Creating an active object from "
1728                                 <<"static data"<<std::endl;*/
1729                 StaticObject &s_obj = *i;
1730                 // Create an active object from the data
1731                 ServerActiveObject *obj = ServerActiveObject::create
1732                                 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1733                 // If couldn't create object, store static data back.
1734                 if(obj==NULL)
1735                 {
1736                         errorstream<<"ServerEnvironment::activateObjects(): "
1737                                         <<"failed to create active object from static object "
1738                                         <<"in block "<<PP(s_obj.pos/BS)
1739                                         <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
1740                         print_hexdump(verbosestream, s_obj.data);
1741                         
1742                         new_stored.push_back(s_obj);
1743                         continue;
1744                 }
1745                 verbosestream<<"ServerEnvironment::activateObjects(): "
1746                                 <<"activated static object pos="<<PP(s_obj.pos/BS)
1747                                 <<" type="<<(int)s_obj.type<<std::endl;
1748                 // This will also add the object to the active static list
1749                 addActiveObjectRaw(obj, false, dtime_s);
1750         }
1751         // Clear stored list
1752         block->m_static_objects.m_stored.clear();
1753         // Add leftover failed stuff to stored list
1754         for(std::list<StaticObject>::iterator
1755                         i = new_stored.begin();
1756                         i != new_stored.end(); ++i)
1757         {
1758                 StaticObject &s_obj = *i;
1759                 block->m_static_objects.m_stored.push_back(s_obj);
1760         }
1761         /*
1762                 Note: Block hasn't really been modified here.
1763                 The objects have just been activated and moved from the stored
1764                 static list to the active static list.
1765                 As such, the block is essentially the same.
1766                 Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
1767                 Otherwise there would be a huge amount of unnecessary I/O.
1768         */
1769 }
1770
1771 /*
1772         Convert objects that are not standing inside active blocks to static.
1773
1774         If m_known_by_count != 0, active object is not deleted, but static
1775         data is still updated.
1776
1777         If force_delete is set, active object is deleted nevertheless. It
1778         shall only be set so in the destructor of the environment.
1779
1780         If block wasn't generated (not in memory or on disk), 
1781 */
1782 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1783 {
1784         std::list<u16> objects_to_remove;
1785         for(std::map<u16, ServerActiveObject*>::iterator
1786                         i = m_active_objects.begin();
1787                         i != m_active_objects.end(); ++i)
1788         {
1789                 ServerActiveObject* obj = i->second;
1790                 assert(obj);
1791                 
1792                 // Do not deactivate if static data creation not allowed
1793                 if(!force_delete && !obj->isStaticAllowed())
1794                         continue;
1795
1796                 // If pending deactivation, let removeRemovedObjects() do it
1797                 if(!force_delete && obj->m_pending_deactivation)
1798                         continue;
1799
1800                 u16 id = i->first;
1801                 v3f objectpos = obj->getBasePosition(); 
1802
1803                 // The block in which the object resides in
1804                 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1805
1806                 // If block is active, don't remove
1807                 if(!force_delete && m_active_blocks.contains(blockpos_o))
1808                         continue;
1809
1810                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1811                                 <<"deactivating object id="<<id<<" on inactive block "
1812                                 <<PP(blockpos_o)<<std::endl;
1813
1814                 // If known by some client, don't immediately delete.
1815                 bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
1816
1817                 /*
1818                         Update the static data
1819                 */
1820
1821                 if(obj->isStaticAllowed())
1822                 {
1823                         // Create new static object
1824                         std::string staticdata_new = obj->getStaticData();
1825                         StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
1826                         
1827                         bool stays_in_same_block = false;
1828                         bool data_changed = true;
1829
1830                         if(obj->m_static_exists){
1831                                 if(obj->m_static_block == blockpos_o)
1832                                         stays_in_same_block = true;
1833
1834                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1835                                 
1836                                 std::map<u16, StaticObject>::iterator n =
1837                                                 block->m_static_objects.m_active.find(id);
1838                                 if(n != block->m_static_objects.m_active.end()){
1839                                         StaticObject static_old = n->second;
1840
1841                                         float save_movem = obj->getMinimumSavedMovement();
1842
1843                                         if(static_old.data == staticdata_new &&
1844                                                         (static_old.pos - objectpos).getLength() < save_movem)
1845                                                 data_changed = false;
1846                                 } else {
1847                                         errorstream<<"ServerEnvironment::deactivateFarObjects(): "
1848                                                         <<"id="<<id<<" m_static_exists=true but "
1849                                                         <<"static data doesn't actually exist in "
1850                                                         <<PP(obj->m_static_block)<<std::endl;
1851                                 }
1852                         }
1853
1854                         bool shall_be_written = (!stays_in_same_block || data_changed);
1855                         
1856                         // Delete old static object
1857                         if(obj->m_static_exists)
1858                         {
1859                                 MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
1860                                 if(block)
1861                                 {
1862                                         block->m_static_objects.remove(id);
1863                                         obj->m_static_exists = false;
1864                                         // Only mark block as modified if data changed considerably
1865                                         if(shall_be_written)
1866                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1867                                                                 "deactivateFarObjects: Static data "
1868                                                                 "changed considerably");
1869                                 }
1870                         }
1871
1872                         // Add to the block where the object is located in
1873                         v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1874                         // Get or generate the block
1875                         MapBlock *block = NULL;
1876                         try{
1877                                 block = m_map->emergeBlock(blockpos);
1878                         } catch(InvalidPositionException &e){
1879                                 // Handled via NULL pointer
1880                         }
1881
1882                         if(block)
1883                         {
1884                                 if(block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")){
1885                                         errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
1886                                                         <<" statically but block "<<PP(blockpos)
1887                                                         <<" already contains "
1888                                                         <<block->m_static_objects.m_stored.size()
1889                                                         <<" objects."
1890                                                         <<" Forcing delete."<<std::endl;
1891                                         force_delete = true;
1892                                 } else {
1893                                         // If static counterpart already exists, remove it first.
1894                                         // This shouldn't happen, but happens rarely for some
1895                                         // unknown reason. Unsuccessful attempts have been made to
1896                                         // find said reason.
1897                                         if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
1898                                                 infostream<<"ServerEnv: WARNING: Performing hack #83274"
1899                                                                 <<std::endl;
1900                                                 block->m_static_objects.remove(id);
1901                                         }
1902                                         //store static data
1903                                         block->m_static_objects.insert(0, s_obj);
1904                                         
1905                                         // Only mark block as modified if data changed considerably
1906                                         if(shall_be_written)
1907                                                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
1908                                                                 "deactivateFarObjects: Static data "
1909                                                                 "changed considerably");
1910                                         
1911                                         obj->m_static_exists = true;
1912                                         obj->m_static_block = block->getPos();
1913                                 }
1914                         }
1915                         else{
1916                                 if(!force_delete){
1917                                         v3s16 p = floatToInt(objectpos, BS);
1918                                         errorstream<<"ServerEnv: Could not find or generate "
1919                                                         <<"a block for storing id="<<obj->getId()
1920                                                         <<" statically (pos="<<PP(p)<<")"<<std::endl;
1921                                         continue;
1922                                 }
1923                         }
1924                 }
1925
1926                 /*
1927                         If known by some client, set pending deactivation.
1928                         Otherwise delete it immediately.
1929                 */
1930
1931                 if(pending_delete && !force_delete)
1932                 {
1933                         verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1934                                         <<"object id="<<id<<" is known by clients"
1935                                         <<"; not deleting yet"<<std::endl;
1936
1937                         obj->m_pending_deactivation = true;
1938                         continue;
1939                 }
1940                 
1941                 verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
1942                                 <<"object id="<<id<<" is not known by clients"
1943                                 <<"; deleting"<<std::endl;
1944
1945                 // Tell the object about removal
1946                 obj->removingFromEnvironment();
1947                 // Deregister in scripting api
1948                 m_script->removeObjectReference(obj);
1949
1950                 // Delete active object
1951                 if(obj->environmentDeletes())
1952                         delete obj;
1953                 // Id to be removed from m_active_objects
1954                 objects_to_remove.push_back(id);
1955         }
1956
1957         // Remove references from m_active_objects
1958         for(std::list<u16>::iterator i = objects_to_remove.begin();
1959                         i != objects_to_remove.end(); ++i)
1960         {
1961                 m_active_objects.erase(*i);
1962         }
1963 }
1964
1965
1966 #ifndef SERVER
1967
1968 #include "clientsimpleobject.h"
1969
1970 /*
1971         ClientEnvironment
1972 */
1973
1974 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
1975                 ITextureSource *texturesource, IGameDef *gamedef,
1976                 IrrlichtDevice *irr):
1977         m_map(map),
1978         m_smgr(smgr),
1979         m_texturesource(texturesource),
1980         m_gamedef(gamedef),
1981         m_irr(irr)
1982 {
1983 }
1984
1985 ClientEnvironment::~ClientEnvironment()
1986 {
1987         // delete active objects
1988         for(std::map<u16, ClientActiveObject*>::iterator
1989                         i = m_active_objects.begin();
1990                         i != m_active_objects.end(); ++i)
1991         {
1992                 delete i->second;
1993         }
1994
1995         for(std::list<ClientSimpleObject*>::iterator
1996                         i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i)
1997         {
1998                 delete *i;
1999         }
2000
2001         // Drop/delete map
2002         m_map->drop();
2003 }
2004
2005 Map & ClientEnvironment::getMap()
2006 {
2007         return *m_map;
2008 }
2009
2010 ClientMap & ClientEnvironment::getClientMap()
2011 {
2012         return *m_map;
2013 }
2014
2015 void ClientEnvironment::addPlayer(Player *player)
2016 {
2017         DSTACK(__FUNCTION_NAME);
2018         /*
2019                 It is a failure if player is local and there already is a local
2020                 player
2021         */
2022         assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
2023
2024         Environment::addPlayer(player);
2025 }
2026
2027 LocalPlayer * ClientEnvironment::getLocalPlayer()
2028 {
2029         for(std::list<Player*>::iterator i = m_players.begin();
2030                         i != m_players.end(); ++i)
2031         {
2032                 Player *player = *i;
2033                 if(player->isLocal())
2034                         return (LocalPlayer*)player;
2035         }
2036         return NULL;
2037 }
2038
2039 void ClientEnvironment::step(float dtime)
2040 {
2041         DSTACK(__FUNCTION_NAME);
2042
2043         /* Step time of day */
2044         stepTimeOfDay(dtime);
2045
2046         // Get some settings
2047         bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
2048         bool free_move = fly_allowed && g_settings->getBool("free_move");
2049
2050         // Get local player
2051         LocalPlayer *lplayer = getLocalPlayer();
2052         assert(lplayer);
2053         // collision info queue
2054         std::list<CollisionInfo> player_collisions;
2055         
2056         /*
2057                 Get the speed the player is going
2058         */
2059         bool is_climbing = lplayer->is_climbing;
2060         
2061         f32 player_speed = lplayer->getSpeed().getLength();
2062         
2063         /*
2064                 Maximum position increment
2065         */
2066         //f32 position_max_increment = 0.05*BS;
2067         f32 position_max_increment = 0.1*BS;
2068
2069         // Maximum time increment (for collision detection etc)
2070         // time = distance / speed
2071         f32 dtime_max_increment = 1;
2072         if(player_speed > 0.001)
2073                 dtime_max_increment = position_max_increment / player_speed;
2074         
2075         // Maximum time increment is 10ms or lower
2076         if(dtime_max_increment > 0.01)
2077                 dtime_max_increment = 0.01;
2078         
2079         // Don't allow overly huge dtime
2080         if(dtime > 0.5)
2081                 dtime = 0.5;
2082         
2083         f32 dtime_downcount = dtime;
2084
2085         /*
2086                 Stuff that has a maximum time increment
2087         */
2088
2089         u32 loopcount = 0;
2090         do
2091         {
2092                 loopcount++;
2093
2094                 f32 dtime_part;
2095                 if(dtime_downcount > dtime_max_increment)
2096                 {
2097                         dtime_part = dtime_max_increment;
2098                         dtime_downcount -= dtime_part;
2099                 }
2100                 else
2101                 {
2102                         dtime_part = dtime_downcount;
2103                         /*
2104                                 Setting this to 0 (no -=dtime_part) disables an infinite loop
2105                                 when dtime_part is so small that dtime_downcount -= dtime_part
2106                                 does nothing
2107                         */
2108                         dtime_downcount = 0;
2109                 }
2110                 
2111                 /*
2112                         Handle local player
2113                 */
2114                 
2115                 {
2116                         // Apply physics
2117                         if(free_move == false && is_climbing == false)
2118                         {
2119                                 // Gravity
2120                                 v3f speed = lplayer->getSpeed();
2121                                 if(lplayer->in_liquid == false)
2122                                         speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
2123
2124                                 // Liquid floating / sinking
2125                                 if(lplayer->in_liquid && !lplayer->swimming_vertical)
2126                                         speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
2127
2128                                 // Liquid resistance
2129                                 if(lplayer->in_liquid_stable || lplayer->in_liquid)
2130                                 {
2131                                         // How much the node's viscosity blocks movement, ranges between 0 and 1
2132                                         // Should match the scale at which viscosity increase affects other liquid attributes
2133                                         const f32 viscosity_factor = 0.3;
2134
2135                                         v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
2136                                         f32 dl = d_wanted.getLength();
2137                                         if(dl > lplayer->movement_liquid_fluidity_smooth)
2138                                                 dl = lplayer->movement_liquid_fluidity_smooth;
2139                                         dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
2140                                         
2141                                         v3f d = d_wanted.normalize() * dl;
2142                                         speed += d;
2143                                         
2144 #if 0 // old code
2145                                         if(speed.X > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.X -= lplayer->movement_liquid_fluidity_smooth;
2146                                         if(speed.X < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.X += lplayer->movement_liquid_fluidity_smooth;
2147                                         if(speed.Y > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Y -= lplayer->movement_liquid_fluidity_smooth;
2148                                         if(speed.Y < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Y += lplayer->movement_liquid_fluidity_smooth;
2149                                         if(speed.Z > lplayer->movement_liquid_fluidity + lplayer->movement_liquid_fluidity_smooth)      speed.Z -= lplayer->movement_liquid_fluidity_smooth;
2150                                         if(speed.Z < -lplayer->movement_liquid_fluidity - lplayer->movement_liquid_fluidity_smooth)     speed.Z += lplayer->movement_liquid_fluidity_smooth;
2151 #endif
2152                                 }
2153
2154                                 lplayer->setSpeed(speed);
2155                         }
2156
2157                         /*
2158                                 Move the lplayer.
2159                                 This also does collision detection.
2160                         */
2161                         lplayer->move(dtime_part, this, position_max_increment,
2162                                         &player_collisions);
2163                 }
2164         }
2165         while(dtime_downcount > 0.001);
2166                 
2167         //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
2168         
2169         for(std::list<CollisionInfo>::iterator
2170                         i = player_collisions.begin();
2171                         i != player_collisions.end(); ++i)
2172         {
2173                 CollisionInfo &info = *i;
2174                 v3f speed_diff = info.new_speed - info.old_speed;;
2175                 // Handle only fall damage
2176                 // (because otherwise walking against something in fast_move kills you)
2177                 if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
2178                         continue;
2179                 // Get rid of other components
2180                 speed_diff.X = 0;
2181                 speed_diff.Z = 0;
2182                 f32 pre_factor = 1; // 1 hp per node/s
2183                 f32 tolerance = BS*14; // 5 without damage
2184                 f32 post_factor = 1; // 1 hp per node/s
2185                 if(info.type == COLLISION_NODE)
2186                 {
2187                         const ContentFeatures &f = m_gamedef->ndef()->
2188                                         get(m_map->getNodeNoEx(info.node_p));
2189                         // Determine fall damage multiplier
2190                         int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
2191                         pre_factor = 1.0 + (float)addp/100.0;
2192                 }
2193                 float speed = pre_factor * speed_diff.getLength();
2194                 if(speed > tolerance)
2195                 {
2196                         f32 damage_f = (speed - tolerance)/BS * post_factor;
2197                         u16 damage = (u16)(damage_f+0.5);
2198                         if(damage != 0){
2199                                 damageLocalPlayer(damage, true);
2200                                 MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
2201                                 m_gamedef->event()->put(e);
2202                         }
2203                 }
2204         }
2205         
2206         /*
2207                 A quick draft of lava damage
2208         */
2209         if(m_lava_hurt_interval.step(dtime, 1.0))
2210         {
2211                 v3f pf = lplayer->getPosition();
2212                 
2213                 // Feet, middle and head
2214                 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
2215                 MapNode n1 = m_map->getNodeNoEx(p1);
2216                 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
2217                 MapNode n2 = m_map->getNodeNoEx(p2);
2218                 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2219                 MapNode n3 = m_map->getNodeNoEx(p3);
2220
2221                 u32 damage_per_second = 0;
2222                 damage_per_second = MYMAX(damage_per_second,
2223                                 m_gamedef->ndef()->get(n1).damage_per_second);
2224                 damage_per_second = MYMAX(damage_per_second,
2225                                 m_gamedef->ndef()->get(n2).damage_per_second);
2226                 damage_per_second = MYMAX(damage_per_second,
2227                                 m_gamedef->ndef()->get(n3).damage_per_second);
2228                 
2229                 if(damage_per_second != 0)
2230                 {
2231                         damageLocalPlayer(damage_per_second, true);
2232                 }
2233         }
2234
2235         /*
2236                 Drowning
2237         */
2238         if(m_drowning_interval.step(dtime, 2.0))
2239         {
2240                 v3f pf = lplayer->getPosition();
2241
2242                 // head
2243                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2244                 MapNode n = m_map->getNodeNoEx(p);
2245                 ContentFeatures c = m_gamedef->ndef()->get(n);
2246                 u8 drowning_damage = c.drowning;
2247                 if(drowning_damage > 0 && lplayer->hp > 0){
2248                         u16 breath = lplayer->getBreath();
2249                         if(breath > 10){
2250                                 breath = 11;
2251                         }
2252                         if(breath > 0){
2253                                 breath -= 1;
2254                         }
2255                         lplayer->setBreath(breath);
2256                         updateLocalPlayerBreath(breath);
2257                 }
2258
2259                 if(lplayer->getBreath() == 0 && drowning_damage > 0){
2260                         damageLocalPlayer(drowning_damage, true);
2261                 }
2262         }
2263         if(m_breathing_interval.step(dtime, 0.5))
2264         {
2265                 v3f pf = lplayer->getPosition();
2266
2267                 // head
2268                 v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
2269                 MapNode n = m_map->getNodeNoEx(p);
2270                 ContentFeatures c = m_gamedef->ndef()->get(n);
2271                 if (!lplayer->hp){
2272                         lplayer->setBreath(11);
2273                 }
2274                 else if(c.drowning == 0){
2275                         u16 breath = lplayer->getBreath();
2276                         if(breath <= 10){
2277                                 breath += 1;
2278                                 lplayer->setBreath(breath);
2279                                 updateLocalPlayerBreath(breath);
2280                         }
2281                 }
2282         }
2283
2284         /*
2285                 Stuff that can be done in an arbitarily large dtime
2286         */
2287         for(std::list<Player*>::iterator i = m_players.begin();
2288                         i != m_players.end(); ++i)
2289         {
2290                 Player *player = *i;
2291                 
2292                 /*
2293                         Handle non-local players
2294                 */
2295                 if(player->isLocal() == false)
2296                 {
2297                         // Move
2298                         player->move(dtime, *m_map, 100*BS);
2299
2300                 }
2301                 
2302                 // Update lighting on all players on client
2303                 float light = 1.0;
2304                 try{
2305                         // Get node at head
2306                         v3s16 p = player->getLightPosition();
2307                         MapNode n = m_map->getNode(p);
2308                         light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
2309                 }
2310                 catch(InvalidPositionException &e){
2311                         light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
2312                 }
2313                 player->light = light;
2314         }
2315         
2316         /*
2317                 Step active objects and update lighting of them
2318         */
2319         
2320         g_profiler->avg("CEnv: num of objects", m_active_objects.size());
2321         bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
2322         for(std::map<u16, ClientActiveObject*>::iterator
2323                         i = m_active_objects.begin();
2324                         i != m_active_objects.end(); ++i)
2325         {
2326                 ClientActiveObject* obj = i->second;
2327                 // Step object
2328                 obj->step(dtime, this);
2329
2330                 if(update_lighting)
2331                 {
2332                         // Update lighting
2333                         u8 light = 0;
2334                         try{
2335                                 // Get node at head
2336                                 v3s16 p = obj->getLightPosition();
2337                                 MapNode n = m_map->getNode(p);
2338                                 light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2339                         }
2340                         catch(InvalidPositionException &e){
2341                                 light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2342                         }
2343                         obj->updateLight(light);
2344                 }
2345         }
2346
2347         /*
2348                 Step and handle simple objects
2349         */
2350         g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
2351         for(std::list<ClientSimpleObject*>::iterator
2352                         i = m_simple_objects.begin(); i != m_simple_objects.end();)
2353         {
2354                 ClientSimpleObject *simple = *i;
2355                 std::list<ClientSimpleObject*>::iterator cur = i;
2356                 ++i;
2357                 simple->step(dtime);
2358                 if(simple->m_to_be_removed){
2359                         delete simple;
2360                         m_simple_objects.erase(cur);
2361                 }
2362         }
2363 }
2364         
2365 void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
2366 {
2367         m_simple_objects.push_back(simple);
2368 }
2369
2370 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
2371 {
2372         std::map<u16, ClientActiveObject*>::iterator n;
2373         n = m_active_objects.find(id);
2374         if(n == m_active_objects.end())
2375                 return NULL;
2376         return n->second;
2377 }
2378
2379 bool isFreeClientActiveObjectId(u16 id,
2380                 std::map<u16, ClientActiveObject*> &objects)
2381 {
2382         if(id == 0)
2383                 return false;
2384
2385         return objects.find(id) == objects.end();
2386 }
2387
2388 u16 getFreeClientActiveObjectId(
2389                 std::map<u16, ClientActiveObject*> &objects)
2390 {
2391         //try to reuse id's as late as possible
2392         static u16 last_used_id = 0;
2393         u16 startid = last_used_id;
2394         for(;;)
2395         {
2396                 last_used_id ++;
2397                 if(isFreeClientActiveObjectId(last_used_id, objects))
2398                         return last_used_id;
2399                 
2400                 if(last_used_id == startid)
2401                         return 0;
2402         }
2403 }
2404
2405 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
2406 {
2407         assert(object);
2408         if(object->getId() == 0)
2409         {
2410                 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
2411                 if(new_id == 0)
2412                 {
2413                         infostream<<"ClientEnvironment::addActiveObject(): "
2414                                         <<"no free ids available"<<std::endl;
2415                         delete object;
2416                         return 0;
2417                 }
2418                 object->setId(new_id);
2419         }
2420         if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
2421         {
2422                 infostream<<"ClientEnvironment::addActiveObject(): "
2423                                 <<"id is not free ("<<object->getId()<<")"<<std::endl;
2424                 delete object;
2425                 return 0;
2426         }
2427         infostream<<"ClientEnvironment::addActiveObject(): "
2428                         <<"added (id="<<object->getId()<<")"<<std::endl;
2429         m_active_objects[object->getId()] = object;
2430         object->addToScene(m_smgr, m_texturesource, m_irr);
2431         { // Update lighting immediately
2432                 u8 light = 0;
2433                 try{
2434                         // Get node at head
2435                         v3s16 p = object->getLightPosition();
2436                         MapNode n = m_map->getNode(p);
2437                         light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
2438                 }
2439                 catch(InvalidPositionException &e){
2440                         light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
2441                 }
2442                 object->updateLight(light);
2443         }
2444         return object->getId();
2445 }
2446
2447 void ClientEnvironment::addActiveObject(u16 id, u8 type,
2448                 const std::string &init_data)
2449 {
2450         ClientActiveObject* obj =
2451                         ClientActiveObject::create(type, m_gamedef, this);
2452         if(obj == NULL)
2453         {
2454                 infostream<<"ClientEnvironment::addActiveObject(): "
2455                                 <<"id="<<id<<" type="<<type<<": Couldn't create object"
2456                                 <<std::endl;
2457                 return;
2458         }
2459         
2460         obj->setId(id);
2461
2462         try
2463         {
2464                 obj->initialize(init_data);
2465         }
2466         catch(SerializationError &e)
2467         {
2468                 errorstream<<"ClientEnvironment::addActiveObject():"
2469                                 <<" id="<<id<<" type="<<type
2470                                 <<": SerializationError in initialize(): "
2471                                 <<e.what()
2472                                 <<": init_data="<<serializeJsonString(init_data)
2473                                 <<std::endl;
2474         }
2475
2476         addActiveObject(obj);
2477 }
2478
2479 void ClientEnvironment::removeActiveObject(u16 id)
2480 {
2481         verbosestream<<"ClientEnvironment::removeActiveObject(): "
2482                         <<"id="<<id<<std::endl;
2483         ClientActiveObject* obj = getActiveObject(id);
2484         if(obj == NULL)
2485         {
2486                 infostream<<"ClientEnvironment::removeActiveObject(): "
2487                                 <<"id="<<id<<" not found"<<std::endl;
2488                 return;
2489         }
2490         obj->removeFromScene(true);
2491         delete obj;
2492         m_active_objects.erase(id);
2493 }
2494
2495 void ClientEnvironment::processActiveObjectMessage(u16 id,
2496                 const std::string &data)
2497 {
2498         ClientActiveObject* obj = getActiveObject(id);
2499         if(obj == NULL)
2500         {
2501                 infostream<<"ClientEnvironment::processActiveObjectMessage():"
2502                                 <<" got message for id="<<id<<", which doesn't exist."
2503                                 <<std::endl;
2504                 return;
2505         }
2506         try
2507         {
2508                 obj->processMessage(data);
2509         }
2510         catch(SerializationError &e)
2511         {
2512                 errorstream<<"ClientEnvironment::processActiveObjectMessage():"
2513                                 <<" id="<<id<<" type="<<obj->getType()
2514                                 <<" SerializationError in processMessage(),"
2515                                 <<" message="<<serializeJsonString(data)
2516                                 <<std::endl;
2517         }
2518 }
2519
2520 /*
2521         Callbacks for activeobjects
2522 */
2523
2524 void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
2525 {
2526         LocalPlayer *lplayer = getLocalPlayer();
2527         assert(lplayer);
2528         
2529         if(handle_hp){
2530                 if(lplayer->hp > damage)
2531                         lplayer->hp -= damage;
2532                 else
2533                         lplayer->hp = 0;
2534         }
2535
2536         ClientEnvEvent event;
2537         event.type = CEE_PLAYER_DAMAGE;
2538         event.player_damage.amount = damage;
2539         event.player_damage.send_to_server = handle_hp;
2540         m_client_event_queue.push_back(event);
2541 }
2542
2543 void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
2544 {
2545         ClientEnvEvent event;
2546         event.type = CEE_PLAYER_BREATH;
2547         event.player_breath.amount = breath;
2548         m_client_event_queue.push_back(event);
2549 }
2550
2551 /*
2552         Client likes to call these
2553 */
2554         
2555 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
2556                 std::vector<DistanceSortedActiveObject> &dest)
2557 {
2558         for(std::map<u16, ClientActiveObject*>::iterator
2559                         i = m_active_objects.begin();
2560                         i != m_active_objects.end(); ++i)
2561         {
2562                 ClientActiveObject* obj = i->second;
2563
2564                 f32 d = (obj->getPosition() - origin).getLength();
2565
2566                 if(d > max_d)
2567                         continue;
2568
2569                 DistanceSortedActiveObject dso(obj, d);
2570
2571                 dest.push_back(dso);
2572         }
2573 }
2574
2575 ClientEnvEvent ClientEnvironment::getClientEvent()
2576 {
2577         if(m_client_event_queue.empty())
2578         {
2579                 ClientEnvEvent event;
2580                 event.type = CEE_NONE;
2581                 return event;
2582         }
2583         return m_client_event_queue.pop_front();
2584 }
2585
2586 #endif // #ifndef SERVER
2587
2588