3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "environment.h"
23 #include "collision.h"
26 Environment::Environment():
31 Environment::~Environment()
34 for(core::list<Player*>::Iterator i = m_players.begin();
35 i != m_players.end(); i++)
41 void Environment::addPlayer(Player *player)
43 DSTACK(__FUNCTION_NAME);
45 Check that peer_ids are unique.
46 Also check that names are unique.
47 Exception: there can be multiple players with peer_id=0
49 // If peer id is non-zero, it has to be unique.
50 if(player->peer_id != 0)
51 assert(getPlayer(player->peer_id) == NULL);
52 // Name has to be unique.
53 assert(getPlayer(player->getName()) == NULL);
55 m_players.push_back(player);
58 void Environment::removePlayer(u16 peer_id)
60 DSTACK(__FUNCTION_NAME);
62 for(core::list<Player*>::Iterator i = m_players.begin();
63 i != m_players.end(); i++)
66 if(player->peer_id != peer_id)
71 // See if there is an another one
72 // (shouldn't be, but just to be sure)
77 Player * Environment::getPlayer(u16 peer_id)
79 for(core::list<Player*>::Iterator i = m_players.begin();
80 i != m_players.end(); i++)
83 if(player->peer_id == peer_id)
89 Player * Environment::getPlayer(const char *name)
91 for(core::list<Player*>::Iterator i = m_players.begin();
92 i != m_players.end(); i++)
95 if(strcmp(player->getName(), name) == 0)
101 Player * Environment::getRandomConnectedPlayer()
103 core::list<Player*> connected_players = getPlayers(true);
104 u32 chosen_one = myrand() % connected_players.size();
106 for(core::list<Player*>::Iterator
107 i = connected_players.begin();
108 i != connected_players.end(); i++)
120 Player * Environment::getNearestConnectedPlayer(v3f pos)
122 core::list<Player*> connected_players = getPlayers(true);
124 Player *nearest_player = NULL;
125 for(core::list<Player*>::Iterator
126 i = connected_players.begin();
127 i != connected_players.end(); i++)
130 f32 d = player->getPosition().getDistanceFrom(pos);
131 if(d < nearest_d || nearest_player == NULL)
134 nearest_player = player;
137 return nearest_player;
140 core::list<Player*> Environment::getPlayers()
145 core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
147 core::list<Player*> newlist;
148 for(core::list<Player*>::Iterator
149 i = m_players.begin();
150 i != m_players.end(); i++)
154 if(ignore_disconnected)
156 // Ignore disconnected players
157 if(player->peer_id == 0)
161 newlist.push_back(player);
166 void Environment::printPlayers(std::ostream &o)
168 o<<"Players in environment:"<<std::endl;
169 for(core::list<Player*>::Iterator i = m_players.begin();
170 i != m_players.end(); i++)
173 o<<"Player peer_id="<<player->peer_id<<std::endl;
177 /*void Environment::setDayNightRatio(u32 r)
179 getDayNightRatio() = r;
182 u32 Environment::getDayNightRatio()
184 //return getDayNightRatio();
185 return time_to_daynight_ratio(m_time_of_day);
192 void fillRadiusBlock(v3s16 p0, s16 r, core::map<v3s16, bool> &list)
195 for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
196 for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
197 for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
204 void ActiveBlockList::update(core::list<v3s16> &active_positions,
206 core::map<v3s16, bool> &blocks_removed,
207 core::map<v3s16, bool> &blocks_added)
212 core::map<v3s16, bool> newlist;
213 for(core::list<v3s16>::Iterator i = active_positions.begin();
214 i != active_positions.end(); i++)
216 fillRadiusBlock(*i, radius, newlist);
220 Find out which blocks on the old list are not on the new list
222 // Go through old list
223 for(core::map<v3s16, bool>::Iterator i = m_list.getIterator();
224 i.atEnd()==false; i++)
226 v3s16 p = i.getNode()->getKey();
227 // If not on new list, it's been removed
228 if(newlist.find(p) == NULL)
229 blocks_removed.insert(p, true);
233 Find out which blocks on the new list are not on the old list
235 // Go through new list
236 for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
237 i.atEnd()==false; i++)
239 v3s16 p = i.getNode()->getKey();
240 // If not on old list, it's been added
241 if(m_list.find(p) == NULL)
242 blocks_added.insert(p, true);
249 for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
250 i.atEnd()==false; i++)
252 v3s16 p = i.getNode()->getKey();
253 m_list.insert(p, true);
261 ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server):
264 m_random_spawn_timer(3),
265 m_send_recommended_timer(0),
267 m_game_time_fraction_counter(0)
271 ServerEnvironment::~ServerEnvironment()
273 // Clear active block list.
274 // This makes the next one delete all active objects.
275 m_active_blocks.clear();
277 // Convert all objects to static and delete the active objects
278 deactivateFarObjects(true);
284 void ServerEnvironment::serializePlayers(const std::string &savedir)
286 std::string players_path = savedir + "/players";
287 fs::CreateDir(players_path);
289 core::map<Player*, bool> saved_players;
291 std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
292 for(u32 i=0; i<player_files.size(); i++)
294 if(player_files[i].dir)
297 // Full path to this file
298 std::string path = players_path + "/" + player_files[i].name;
300 //dstream<<"Checking player file "<<path<<std::endl;
302 // Load player to see what is its name
303 ServerRemotePlayer testplayer;
305 // Open file and deserialize
306 std::ifstream is(path.c_str(), std::ios_base::binary);
307 if(is.good() == false)
309 dstream<<"Failed to read "<<path<<std::endl;
312 testplayer.deSerialize(is);
315 //dstream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
317 // Search for the player
318 std::string playername = testplayer.getName();
319 Player *player = getPlayer(playername.c_str());
322 dstream<<"Didn't find matching player, ignoring file "<<path<<std::endl;
326 //dstream<<"Found matching player, overwriting."<<std::endl;
328 // OK, found. Save player there.
330 // Open file and serialize
331 std::ofstream os(path.c_str(), std::ios_base::binary);
332 if(os.good() == false)
334 dstream<<"Failed to overwrite "<<path<<std::endl;
337 player->serialize(os);
338 saved_players.insert(player, true);
342 for(core::list<Player*>::Iterator i = m_players.begin();
343 i != m_players.end(); i++)
346 if(saved_players.find(player) != NULL)
348 /*dstream<<"Player "<<player->getName()
349 <<" was already saved."<<std::endl;*/
352 std::string playername = player->getName();
353 // Don't save unnamed player
356 //dstream<<"Not saving unnamed player."<<std::endl;
362 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
363 playername = "player";
364 std::string path = players_path + "/" + playername;
366 for(u32 i=0; i<1000; i++)
368 if(fs::PathExists(path) == false)
373 path = players_path + "/" + playername + itos(i);
377 dstream<<"WARNING: Didn't find free file for player"<<std::endl;
382 /*dstream<<"Saving player "<<player->getName()<<" to "
384 // Open file and serialize
385 std::ofstream os(path.c_str(), std::ios_base::binary);
386 if(os.good() == false)
388 dstream<<"WARNING: Failed to overwrite "<<path<<std::endl;
391 player->serialize(os);
392 saved_players.insert(player, true);
396 //dstream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
399 void ServerEnvironment::deSerializePlayers(const std::string &savedir)
401 std::string players_path = savedir + "/players";
403 core::map<Player*, bool> saved_players;
405 std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
406 for(u32 i=0; i<player_files.size(); i++)
408 if(player_files[i].dir)
411 // Full path to this file
412 std::string path = players_path + "/" + player_files[i].name;
414 dstream<<"Checking player file "<<path<<std::endl;
416 // Load player to see what is its name
417 ServerRemotePlayer testplayer;
419 // Open file and deserialize
420 std::ifstream is(path.c_str(), std::ios_base::binary);
421 if(is.good() == false)
423 dstream<<"Failed to read "<<path<<std::endl;
426 testplayer.deSerialize(is);
429 if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS))
431 dstream<<"Not loading player with invalid name: "
432 <<testplayer.getName()<<std::endl;
435 dstream<<"Loaded test player with name "<<testplayer.getName()
438 // Search for the player
439 std::string playername = testplayer.getName();
440 Player *player = getPlayer(playername.c_str());
441 bool newplayer = false;
444 dstream<<"Is a new player"<<std::endl;
445 player = new ServerRemotePlayer();
451 dstream<<"Reading player "<<testplayer.getName()<<" from "
453 // Open file and deserialize
454 std::ifstream is(path.c_str(), std::ios_base::binary);
455 if(is.good() == false)
457 dstream<<"Failed to read "<<path<<std::endl;
460 player->deSerialize(is);
468 void ServerEnvironment::saveMeta(const std::string &savedir)
470 std::string path = savedir + "/env_meta.txt";
472 // Open file and serialize
473 std::ofstream os(path.c_str(), std::ios_base::binary);
474 if(os.good() == false)
476 dstream<<"WARNING: ServerEnvironment::saveMeta(): Failed to open "
478 throw SerializationError("Couldn't save env meta");
482 args.setU64("game_time", m_game_time);
483 args.setU64("time_of_day", getTimeOfDay());
488 void ServerEnvironment::loadMeta(const std::string &savedir)
490 std::string path = savedir + "/env_meta.txt";
492 // Open file and deserialize
493 std::ifstream is(path.c_str(), std::ios_base::binary);
494 if(is.good() == false)
496 dstream<<"WARNING: ServerEnvironment::loadMeta(): Failed to open "
498 throw SerializationError("Couldn't load env meta");
506 throw SerializationError
507 ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
509 std::getline(is, line);
510 std::string trimmedline = trim(line);
511 if(trimmedline == "EnvArgsEnd")
513 args.parseConfigLine(line);
517 m_game_time = args.getU64("game_time");
518 }catch(SettingNotFoundException &e){
519 // Getting this is crucial, otherwise timestamps are useless
520 throw SerializationError("Couldn't load env meta game_time");
524 m_time_of_day = args.getU64("time_of_day");
525 }catch(SettingNotFoundException &e){
526 // This is not as important
527 m_time_of_day = 9000;
532 // This is probably very useless
533 void spawnRandomObjects(MapBlock *block)
535 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
536 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
538 bool last_node_walkable = false;
539 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
542 MapNode n = block->getNodeNoEx(p);
543 if(n.d == CONTENT_IGNORE)
545 if(content_features(n.d).liquid_type != LIQUID_NONE)
547 if(content_features(n.d).walkable)
549 last_node_walkable = true;
552 if(last_node_walkable)
554 // If block contains light information
555 if(content_features(n.d).param_type == CPT_LIGHT)
557 if(n.getLight(LIGHTBANK_DAY) <= 5)
559 if(myrand() % 1000 == 0)
561 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
563 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
564 std::string data = obj->getStaticData();
565 StaticObject s_obj(obj->getType(),
566 obj->getBasePosition(), data);
568 block->m_static_objects.insert(0, s_obj);
570 block->setChangedFlag();
575 last_node_walkable = false;
581 void ServerEnvironment::step(float dtime)
583 DSTACK(__FUNCTION_NAME);
585 //TimeTaker timer("ServerEnv step");
588 bool footprints = g_settings.getBool("footprints");
594 m_game_time_fraction_counter += dtime;
595 u32 inc_i = (u32)m_game_time_fraction_counter;
596 m_game_time += inc_i;
597 m_game_time_fraction_counter -= (float)inc_i;
601 Let map update it's timers
604 //TimeTaker timer("Server m_map->timerUpdate()");
605 m_map->timerUpdate(dtime);
611 for(core::list<Player*>::Iterator i = m_players.begin();
612 i != m_players.end(); i++)
616 // Ignore disconnected players
617 if(player->peer_id == 0)
620 v3f playerpos = player->getPosition();
623 player->move(dtime, *m_map, 100*BS);
626 Add footsteps to grass
630 // Get node that is at BS/4 under player
631 v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
633 MapNode n = m_map->getNode(bottompos);
634 if(n.d == CONTENT_GRASS)
636 n.d = CONTENT_GRASS_FOOTSTEPS;
637 m_map->setNode(bottompos, n);
640 catch(InvalidPositionException &e)
647 Manage active block list
649 if(m_active_blocks_management_interval.step(dtime, 2.0))
652 Get player block positions
654 core::list<v3s16> players_blockpos;
655 for(core::list<Player*>::Iterator
656 i = m_players.begin();
657 i != m_players.end(); i++)
660 // Ignore disconnected players
661 if(player->peer_id == 0)
663 v3s16 blockpos = getNodeBlockPos(
664 floatToInt(player->getPosition(), BS));
665 players_blockpos.push_back(blockpos);
669 Update list of active blocks, collecting changes
671 const s16 active_block_range = 5;
672 core::map<v3s16, bool> blocks_removed;
673 core::map<v3s16, bool> blocks_added;
674 m_active_blocks.update(players_blockpos, active_block_range,
675 blocks_removed, blocks_added);
678 Handle removed blocks
681 // Convert active objects that are no more in active blocks to static
682 deactivateFarObjects(false);
684 for(core::map<v3s16, bool>::Iterator
685 i = blocks_removed.getIterator();
686 i.atEnd()==false; i++)
688 v3s16 p = i.getNode()->getKey();
690 /*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
691 <<") became inactive"<<std::endl;*/
693 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
697 // Set current time as timestamp
698 block->setTimestamp(m_game_time);
705 for(core::map<v3s16, bool>::Iterator
706 i = blocks_added.getIterator();
707 i.atEnd()==false; i++)
709 v3s16 p = i.getNode()->getKey();
711 /*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
712 <<") became active"<<std::endl;*/
714 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
718 // Get time difference
720 u32 stamp = block->getTimestamp();
721 if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
722 dtime_s = m_game_time - block->getTimestamp();
724 // Set current time as timestamp
725 block->setTimestamp(m_game_time);
727 //dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
729 // Activate stored objects
730 activateObjects(block);
732 // TODO: Do something
733 // TODO: Implement usage of ActiveBlockModifier
735 // Here's a quick demonstration
737 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
738 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
739 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
741 v3s16 p = p0 + block->getPosRelative();
742 MapNode n = block->getNodeNoEx(p0);
744 // Convert all mud under proper day lighting to grass
745 if(n.d == CONTENT_MUD)
749 MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
750 if(content_features(n_top.d).air_equivalent &&
751 n_top.getLight(LIGHTBANK_DAY) >= 13)
754 m_map->addNodeWithEvent(p, n);
763 Mess around in active blocks
765 if(m_active_blocks_test_interval.step(dtime, 5.0))
767 for(core::map<v3s16, bool>::Iterator
768 i = m_active_blocks.m_list.getIterator();
769 i.atEnd()==false; i++)
771 v3s16 p = i.getNode()->getKey();
773 /*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
774 <<") being handled"<<std::endl;*/
776 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
780 // Set current time as timestamp
781 block->setTimestamp(m_game_time);
786 Note that map modifications should be done using the event-
787 making map methods so that the server gets information
790 Reading can be done quickly directly from the block.
792 Everything should bind to inside this single content
793 searching loop to keep things fast.
795 // TODO: Implement usage of ActiveBlockModifier
798 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
799 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
800 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
802 v3s16 p = p0 + block->getPosRelative();
803 MapNode n = block->getNodeNoEx(p0);
805 // Convert mud under proper lighting to grass
806 if(n.d == CONTENT_MUD)
810 MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
811 if(content_features(n_top.d).air_equivalent &&
812 n_top.getLightBlend(getDayNightRatio()) >= 13)
815 m_map->addNodeWithEvent(p, n);
827 //TimeTaker timer("Step active objects");
829 // This helps the objects to send data at the same time
830 bool send_recommended = false;
831 m_send_recommended_timer += dtime;
832 if(m_send_recommended_timer > 0.15)
834 m_send_recommended_timer = 0;
835 send_recommended = true;
838 for(core::map<u16, ServerActiveObject*>::Iterator
839 i = m_active_objects.getIterator();
840 i.atEnd()==false; i++)
842 ServerActiveObject* obj = i.getNode()->getValue();
843 // Don't step if is to be removed or stored statically
844 if(obj->m_removed || obj->m_pending_deactivation)
846 // Step object, putting messages directly to the queue
847 obj->step(dtime, m_active_object_messages, send_recommended);
852 Manage active objects
854 if(m_object_management_interval.step(dtime, 0.5))
857 Remove objects that satisfy (m_removed && m_known_by_count==0)
859 removeRemovedObjects();
862 if(g_settings.getBool("enable_experimental"))
869 m_random_spawn_timer -= dtime;
870 if(m_random_spawn_timer < 0)
872 //m_random_spawn_timer += myrand_range(2.0, 20.0);
873 //m_random_spawn_timer += 2.0;
874 m_random_spawn_timer += 200.0;
880 /*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
881 s16 y = 1 + getServerMap().findGroundLevel(p2d);
882 v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
884 Player *player = getRandomConnectedPlayer();
887 pos = player->getPosition();
889 myrand_range(-3,3)*BS,
891 myrand_range(-3,3)*BS
895 Create a ServerActiveObject
898 //TestSAO *obj = new TestSAO(this, 0, pos);
899 //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
900 //ServerActiveObject *obj = new RatSAO(this, 0, pos);
901 ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
902 addActiveObject(obj);
906 } // enable_experimental
909 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
911 core::map<u16, ServerActiveObject*>::Node *n;
912 n = m_active_objects.find(id);
915 return n->getValue();
918 bool isFreeServerActiveObjectId(u16 id,
919 core::map<u16, ServerActiveObject*> &objects)
924 for(core::map<u16, ServerActiveObject*>::Iterator
925 i = objects.getIterator();
926 i.atEnd()==false; i++)
928 if(i.getNode()->getKey() == id)
934 u16 getFreeServerActiveObjectId(
935 core::map<u16, ServerActiveObject*> &objects)
940 if(isFreeServerActiveObjectId(new_id, objects))
950 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
953 if(object->getId() == 0)
955 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
958 dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
959 <<"no free ids available"<<std::endl;
963 object->setId(new_id);
965 if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
967 dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
968 <<"id is not free ("<<object->getId()<<")"<<std::endl;
972 /*dstream<<"INGO: ServerEnvironment::addActiveObject(): "
973 <<"added (id="<<object->getId()<<")"<<std::endl;*/
975 m_active_objects.insert(object->getId(), object);
977 // Add static object to active static list of the block
978 v3f objectpos = object->getBasePosition();
979 std::string staticdata = object->getStaticData();
980 StaticObject s_obj(object->getType(), objectpos, staticdata);
981 // Add to the block where the object is located in
982 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
983 MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
986 block->m_static_objects.m_active.insert(object->getId(), s_obj);
987 object->m_static_exists = true;
988 object->m_static_block = blockpos;
991 dstream<<"WARNING: Server: Could not find a block for "
992 <<"storing newly added static active object"<<std::endl;
995 return object->getId();
999 Finds out what new objects have been added to
1000 inside a radius around a position
1002 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1003 core::map<u16, bool> ¤t_objects,
1004 core::map<u16, bool> &added_objects)
1006 v3f pos_f = intToFloat(pos, BS);
1007 f32 radius_f = radius * BS;
1009 Go through the object list,
1010 - discard m_removed objects,
1011 - discard objects that are too far away,
1012 - discard objects that are found in current_objects.
1013 - add remaining objects to added_objects
1015 for(core::map<u16, ServerActiveObject*>::Iterator
1016 i = m_active_objects.getIterator();
1017 i.atEnd()==false; i++)
1019 u16 id = i.getNode()->getKey();
1021 ServerActiveObject *object = i.getNode()->getValue();
1024 // Discard if removed
1025 if(object->m_removed)
1027 // Discard if too far
1028 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1029 if(distance_f > radius_f)
1031 // Discard if already on current_objects
1032 core::map<u16, bool>::Node *n;
1033 n = current_objects.find(id);
1036 // Add to added_objects
1037 added_objects.insert(id, false);
1042 Finds out what objects have been removed from
1043 inside a radius around a position
1045 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1046 core::map<u16, bool> ¤t_objects,
1047 core::map<u16, bool> &removed_objects)
1049 v3f pos_f = intToFloat(pos, BS);
1050 f32 radius_f = radius * BS;
1052 Go through current_objects; object is removed if:
1053 - object is not found in m_active_objects (this is actually an
1054 error condition; objects should be set m_removed=true and removed
1055 only after all clients have been informed about removal), or
1056 - object has m_removed=true, or
1057 - object is too far away
1059 for(core::map<u16, bool>::Iterator
1060 i = current_objects.getIterator();
1061 i.atEnd()==false; i++)
1063 u16 id = i.getNode()->getKey();
1064 ServerActiveObject *object = getActiveObject(id);
1067 dstream<<"WARNING: ServerEnvironment::getRemovedActiveObjects():"
1068 <<" object in current_objects is NULL"<<std::endl;
1070 else if(object->m_removed == false)
1072 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1073 /*dstream<<"removed == false"
1074 <<"distance_f = "<<distance_f
1075 <<", radius_f = "<<radius_f<<std::endl;*/
1076 if(distance_f < radius_f)
1082 removed_objects.insert(id, false);
1086 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1088 if(m_active_object_messages.size() == 0)
1089 return ActiveObjectMessage(0);
1091 return m_active_object_messages.pop_front();
1095 ************ Private methods *************
1099 Remove objects that satisfy (m_removed && m_known_by_count==0)
1101 void ServerEnvironment::removeRemovedObjects()
1103 core::list<u16> objects_to_remove;
1104 for(core::map<u16, ServerActiveObject*>::Iterator
1105 i = m_active_objects.getIterator();
1106 i.atEnd()==false; i++)
1108 u16 id = i.getNode()->getKey();
1109 ServerActiveObject* obj = i.getNode()->getValue();
1110 // This shouldn't happen but check it
1113 dstream<<"WARNING: NULL object found in ServerEnvironment"
1114 <<" while finding removed objects. id="<<id<<std::endl;
1115 // Id to be removed from m_active_objects
1116 objects_to_remove.push_back(id);
1121 We will delete objects that are marked as removed or thatare
1122 waiting for deletion after deactivation
1124 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1128 Delete static data from block if is marked as removed
1130 if(obj->m_static_exists && obj->m_removed)
1132 MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
1135 block->m_static_objects.remove(id);
1136 block->setChangedFlag();
1140 // If m_known_by_count > 0, don't actually remove.
1141 if(obj->m_known_by_count > 0)
1146 // Id to be removed from m_active_objects
1147 objects_to_remove.push_back(id);
1149 // Remove references from m_active_objects
1150 for(core::list<u16>::Iterator i = objects_to_remove.begin();
1151 i != objects_to_remove.end(); i++)
1153 m_active_objects.remove(*i);
1158 Convert stored objects from blocks near the players to active.
1160 void ServerEnvironment::activateObjects(MapBlock *block)
1164 // Ignore if no stored objects (to not set changed flag)
1165 if(block->m_static_objects.m_stored.size() == 0)
1167 // A list for objects that couldn't be converted to static for some
1168 // reason. They will be stored back.
1169 core::list<StaticObject> new_stored;
1170 // Loop through stored static objects
1171 for(core::list<StaticObject>::Iterator
1172 i = block->m_static_objects.m_stored.begin();
1173 i != block->m_static_objects.m_stored.end(); i++)
1175 /*dstream<<"INFO: Server: Creating an active object from "
1176 <<"static data"<<std::endl;*/
1177 StaticObject &s_obj = *i;
1178 // Create an active object from the data
1179 ServerActiveObject *obj = ServerActiveObject::create
1180 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1181 // If couldn't create object, store static data back.
1184 new_stored.push_back(s_obj);
1187 // This will also add the object to the active static list
1188 addActiveObject(obj);
1189 //u16 id = addActiveObject(obj);
1191 // Clear stored list
1192 block->m_static_objects.m_stored.clear();
1193 // Add leftover failed stuff to stored list
1194 for(core::list<StaticObject>::Iterator
1195 i = new_stored.begin();
1196 i != new_stored.end(); i++)
1198 StaticObject &s_obj = *i;
1199 block->m_static_objects.m_stored.push_back(s_obj);
1201 // Block has been modified
1202 block->setChangedFlag();
1206 Convert objects that are not in active blocks to static.
1208 If m_known_by_count != 0, active object is not deleted, but static
1209 data is still updated.
1211 If force_delete is set, active object is deleted nevertheless. It
1212 shall only be set so in the destructor of the environment.
1214 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1216 core::list<u16> objects_to_remove;
1217 for(core::map<u16, ServerActiveObject*>::Iterator
1218 i = m_active_objects.getIterator();
1219 i.atEnd()==false; i++)
1221 ServerActiveObject* obj = i.getNode()->getValue();
1222 u16 id = i.getNode()->getKey();
1223 v3f objectpos = obj->getBasePosition();
1225 // This shouldn't happen but check it
1228 dstream<<"WARNING: NULL object found in ServerEnvironment"
1234 // The block in which the object resides in
1235 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1237 // If block is active, don't remove
1238 if(m_active_blocks.contains(blockpos_o))
1242 Update the static data
1245 // Delete old static object
1246 MapBlock *oldblock = NULL;
1247 if(obj->m_static_exists)
1249 MapBlock *block = m_map->getBlockNoCreateNoEx
1250 (obj->m_static_block);
1253 block->m_static_objects.remove(id);
1257 // Create new static object
1258 std::string staticdata = obj->getStaticData();
1259 StaticObject s_obj(obj->getType(), objectpos, staticdata);
1260 // Add to the block where the object is located in
1261 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1262 MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1265 block->m_static_objects.insert(0, s_obj);
1266 block->setChangedFlag();
1267 obj->m_static_exists = true;
1268 obj->m_static_block = block->getPos();
1270 // If not possible, add back to previous block
1273 oldblock->m_static_objects.insert(0, s_obj);
1274 oldblock->setChangedFlag();
1275 obj->m_static_exists = true;
1276 obj->m_static_block = oldblock->getPos();
1279 dstream<<"WARNING: Server: Could not find a block for "
1280 <<"storing static object"<<std::endl;
1281 obj->m_static_exists = false;
1286 Delete active object if not known by some client,
1287 else set pending deactivation
1290 // If known by some client, don't delete.
1291 if(obj->m_known_by_count > 0 && force_delete == false)
1293 obj->m_pending_deactivation = true;
1297 /*dstream<<"INFO: Server: Stored static data. Deleting object."
1299 // Delete active object
1301 // Id to be removed from m_active_objects
1302 objects_to_remove.push_back(id);
1305 // Remove references from m_active_objects
1306 for(core::list<u16>::Iterator i = objects_to_remove.begin();
1307 i != objects_to_remove.end(); i++)
1309 m_active_objects.remove(*i);
1320 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr):
1328 ClientEnvironment::~ClientEnvironment()
1330 // delete active objects
1331 for(core::map<u16, ClientActiveObject*>::Iterator
1332 i = m_active_objects.getIterator();
1333 i.atEnd()==false; i++)
1335 delete i.getNode()->getValue();
1342 void ClientEnvironment::addPlayer(Player *player)
1344 DSTACK(__FUNCTION_NAME);
1346 It is a failure if player is local and there already is a local
1349 assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
1351 Environment::addPlayer(player);
1354 LocalPlayer * ClientEnvironment::getLocalPlayer()
1356 for(core::list<Player*>::Iterator i = m_players.begin();
1357 i != m_players.end(); i++)
1359 Player *player = *i;
1360 if(player->isLocal())
1361 return (LocalPlayer*)player;
1366 void ClientEnvironment::step(float dtime)
1368 DSTACK(__FUNCTION_NAME);
1370 // Get some settings
1371 bool free_move = g_settings.getBool("free_move");
1372 bool footprints = g_settings.getBool("footprints");
1375 //TimeTaker timer("Client m_map->timerUpdate()");
1376 m_map->timerUpdate(dtime);
1380 LocalPlayer *lplayer = getLocalPlayer();
1382 // collision info queue
1383 core::list<CollisionInfo> player_collisions;
1386 Get the speed the player is going
1388 f32 player_speed = 0.001; // just some small value
1389 player_speed = lplayer->getSpeed().getLength();
1392 Maximum position increment
1394 //f32 position_max_increment = 0.05*BS;
1395 f32 position_max_increment = 0.1*BS;
1397 // Maximum time increment (for collision detection etc)
1398 // time = distance / speed
1399 f32 dtime_max_increment = position_max_increment / player_speed;
1401 // Maximum time increment is 10ms or lower
1402 if(dtime_max_increment > 0.01)
1403 dtime_max_increment = 0.01;
1405 // Don't allow overly huge dtime
1409 f32 dtime_downcount = dtime;
1412 Stuff that has a maximum time increment
1421 if(dtime_downcount > dtime_max_increment)
1423 dtime_part = dtime_max_increment;
1424 dtime_downcount -= dtime_part;
1428 dtime_part = dtime_downcount;
1430 Setting this to 0 (no -=dtime_part) disables an infinite loop
1431 when dtime_part is so small that dtime_downcount -= dtime_part
1434 dtime_downcount = 0;
1442 v3f lplayerpos = lplayer->getPosition();
1445 if(free_move == false)
1448 v3f speed = lplayer->getSpeed();
1449 if(lplayer->swimming_up == false)
1450 speed.Y -= 9.81 * BS * dtime_part * 2;
1453 if(lplayer->in_water_stable || lplayer->in_water)
1455 f32 max_down = 2.0*BS;
1456 if(speed.Y < -max_down) speed.Y = -max_down;
1459 if(speed.getLength() > max)
1461 speed = speed / speed.getLength() * max;
1465 lplayer->setSpeed(speed);
1470 This also does collision detection.
1472 lplayer->move(dtime_part, *m_map, position_max_increment,
1473 &player_collisions);
1476 while(dtime_downcount > 0.001);
1478 //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
1480 for(core::list<CollisionInfo>::Iterator
1481 i = player_collisions.begin();
1482 i != player_collisions.end(); i++)
1484 CollisionInfo &info = *i;
1485 if(info.t == COLLISION_FALL)
1487 //f32 tolerance = BS*10; // 2 without damage
1488 f32 tolerance = BS*12; // 3 without damage
1490 if(info.speed > tolerance)
1492 f32 damage_f = (info.speed - tolerance)/BS*factor;
1493 u16 damage = (u16)(damage_f+0.5);
1494 if(lplayer->hp > damage)
1495 lplayer->hp -= damage;
1499 ClientEnvEvent event;
1500 event.type = CEE_PLAYER_DAMAGE;
1501 event.player_damage.amount = damage;
1502 m_client_event_queue.push_back(event);
1508 Stuff that can be done in an arbitarily large dtime
1510 for(core::list<Player*>::Iterator i = m_players.begin();
1511 i != m_players.end(); i++)
1513 Player *player = *i;
1514 v3f playerpos = player->getPosition();
1517 Handle non-local players
1519 if(player->isLocal() == false)
1522 player->move(dtime, *m_map, 100*BS);
1524 // Update lighting on remote players on client
1525 u8 light = LIGHT_MAX;
1528 v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS);
1529 MapNode n = m_map->getNode(p);
1530 light = n.getLightBlend(getDayNightRatio());
1532 catch(InvalidPositionException &e) {}
1533 player->updateLight(light);
1537 Add footsteps to grass
1541 // Get node that is at BS/4 under player
1542 v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
1544 MapNode n = m_map->getNode(bottompos);
1545 if(n.d == CONTENT_GRASS)
1547 n.d = CONTENT_GRASS_FOOTSTEPS;
1548 m_map->setNode(bottompos, n);
1549 // Update mesh on client
1550 if(m_map->mapType() == MAPTYPE_CLIENT)
1552 v3s16 p_blocks = getNodeBlockPos(bottompos);
1553 MapBlock *b = m_map->getBlockNoCreate(p_blocks);
1554 //b->updateMesh(getDayNightRatio());
1555 b->setMeshExpired(true);
1559 catch(InvalidPositionException &e)
1566 Step active objects and update lighting of them
1569 for(core::map<u16, ClientActiveObject*>::Iterator
1570 i = m_active_objects.getIterator();
1571 i.atEnd()==false; i++)
1573 ClientActiveObject* obj = i.getNode()->getValue();
1575 obj->step(dtime, this);
1577 //u8 light = LIGHT_MAX;
1581 v3s16 p = obj->getLightPosition();
1582 MapNode n = m_map->getNode(p);
1583 light = n.getLightBlend(getDayNightRatio());
1585 catch(InvalidPositionException &e) {}
1586 obj->updateLight(light);
1590 void ClientEnvironment::updateMeshes(v3s16 blockpos)
1592 m_map->updateMeshes(blockpos, getDayNightRatio());
1595 void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
1597 m_map->expireMeshes(only_daynight_diffed);
1600 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
1602 core::map<u16, ClientActiveObject*>::Node *n;
1603 n = m_active_objects.find(id);
1606 return n->getValue();
1609 bool isFreeClientActiveObjectId(u16 id,
1610 core::map<u16, ClientActiveObject*> &objects)
1615 for(core::map<u16, ClientActiveObject*>::Iterator
1616 i = objects.getIterator();
1617 i.atEnd()==false; i++)
1619 if(i.getNode()->getKey() == id)
1625 u16 getFreeClientActiveObjectId(
1626 core::map<u16, ClientActiveObject*> &objects)
1631 if(isFreeClientActiveObjectId(new_id, objects))
1641 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
1644 if(object->getId() == 0)
1646 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
1649 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1650 <<"no free ids available"<<std::endl;
1654 object->setId(new_id);
1656 if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
1658 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1659 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1663 dstream<<"INGO: ClientEnvironment::addActiveObject(): "
1664 <<"added (id="<<object->getId()<<")"<<std::endl;
1665 m_active_objects.insert(object->getId(), object);
1666 object->addToScene(m_smgr);
1667 return object->getId();
1670 void ClientEnvironment::addActiveObject(u16 id, u8 type,
1671 const std::string &init_data)
1673 ClientActiveObject* obj = ClientActiveObject::create(type);
1676 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1677 <<"id="<<id<<" type="<<type<<": Couldn't create object"
1684 addActiveObject(obj);
1686 obj->initialize(init_data);
1689 void ClientEnvironment::removeActiveObject(u16 id)
1691 dstream<<"ClientEnvironment::removeActiveObject(): "
1692 <<"id="<<id<<std::endl;
1693 ClientActiveObject* obj = getActiveObject(id);
1696 dstream<<"WARNING: ClientEnvironment::removeActiveObject(): "
1697 <<"id="<<id<<" not found"<<std::endl;
1700 obj->removeFromScene();
1702 m_active_objects.remove(id);
1705 void ClientEnvironment::processActiveObjectMessage(u16 id,
1706 const std::string &data)
1708 ClientActiveObject* obj = getActiveObject(id);
1711 dstream<<"WARNING: ClientEnvironment::processActiveObjectMessage():"
1712 <<" got message for id="<<id<<", which doesn't exist."
1716 obj->processMessage(data);
1720 Callbacks for activeobjects
1723 void ClientEnvironment::damageLocalPlayer(u8 damage)
1725 LocalPlayer *lplayer = getLocalPlayer();
1728 if(lplayer->hp > damage)
1729 lplayer->hp -= damage;
1733 ClientEnvEvent event;
1734 event.type = CEE_PLAYER_DAMAGE;
1735 event.player_damage.amount = damage;
1736 m_client_event_queue.push_back(event);
1740 Client likes to call these
1743 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
1744 core::array<DistanceSortedActiveObject> &dest)
1746 for(core::map<u16, ClientActiveObject*>::Iterator
1747 i = m_active_objects.getIterator();
1748 i.atEnd()==false; i++)
1750 ClientActiveObject* obj = i.getNode()->getValue();
1752 f32 d = (obj->getPosition() - origin).getLength();
1757 DistanceSortedActiveObject dso(obj, d);
1759 dest.push_back(dso);
1763 ClientEnvEvent ClientEnvironment::getClientEvent()
1765 if(m_client_event_queue.size() == 0)
1767 ClientEnvEvent event;
1768 event.type = CEE_NONE;
1771 return m_client_event_queue.pop_front();
1774 #endif // #ifndef SERVER