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