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"
24 #include "content_mapnode.h"
26 #include "serverobject.h"
27 #include "content_sao.h"
31 Environment::Environment():
36 Environment::~Environment()
39 for(core::list<Player*>::Iterator i = m_players.begin();
40 i != m_players.end(); i++)
46 void Environment::addPlayer(Player *player)
48 DSTACK(__FUNCTION_NAME);
50 Check that peer_ids are unique.
51 Also check that names are unique.
52 Exception: there can be multiple players with peer_id=0
54 // If peer id is non-zero, it has to be unique.
55 if(player->peer_id != 0)
56 assert(getPlayer(player->peer_id) == NULL);
57 // Name has to be unique.
58 assert(getPlayer(player->getName()) == NULL);
60 m_players.push_back(player);
63 void Environment::removePlayer(u16 peer_id)
65 DSTACK(__FUNCTION_NAME);
67 for(core::list<Player*>::Iterator i = m_players.begin();
68 i != m_players.end(); i++)
71 if(player->peer_id != peer_id)
76 // See if there is an another one
77 // (shouldn't be, but just to be sure)
82 Player * Environment::getPlayer(u16 peer_id)
84 for(core::list<Player*>::Iterator i = m_players.begin();
85 i != m_players.end(); i++)
88 if(player->peer_id == peer_id)
94 Player * Environment::getPlayer(const char *name)
96 for(core::list<Player*>::Iterator i = m_players.begin();
97 i != m_players.end(); i++)
100 if(strcmp(player->getName(), name) == 0)
106 Player * Environment::getRandomConnectedPlayer()
108 core::list<Player*> connected_players = getPlayers(true);
109 u32 chosen_one = myrand() % connected_players.size();
111 for(core::list<Player*>::Iterator
112 i = connected_players.begin();
113 i != connected_players.end(); i++)
125 Player * Environment::getNearestConnectedPlayer(v3f pos)
127 core::list<Player*> connected_players = getPlayers(true);
129 Player *nearest_player = NULL;
130 for(core::list<Player*>::Iterator
131 i = connected_players.begin();
132 i != connected_players.end(); i++)
135 f32 d = player->getPosition().getDistanceFrom(pos);
136 if(d < nearest_d || nearest_player == NULL)
139 nearest_player = player;
142 return nearest_player;
145 core::list<Player*> Environment::getPlayers()
150 core::list<Player*> Environment::getPlayers(bool ignore_disconnected)
152 core::list<Player*> newlist;
153 for(core::list<Player*>::Iterator
154 i = m_players.begin();
155 i != m_players.end(); i++)
159 if(ignore_disconnected)
161 // Ignore disconnected players
162 if(player->peer_id == 0)
166 newlist.push_back(player);
171 void Environment::printPlayers(std::ostream &o)
173 o<<"Players in environment:"<<std::endl;
174 for(core::list<Player*>::Iterator i = m_players.begin();
175 i != m_players.end(); i++)
178 o<<"Player peer_id="<<player->peer_id<<std::endl;
182 /*void Environment::setDayNightRatio(u32 r)
184 getDayNightRatio() = r;
187 u32 Environment::getDayNightRatio()
189 //return getDayNightRatio();
190 return time_to_daynight_ratio(m_time_of_day);
197 void fillRadiusBlock(v3s16 p0, s16 r, core::map<v3s16, bool> &list)
200 for(p.X=p0.X-r; p.X<=p0.X+r; p.X++)
201 for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++)
202 for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++)
209 void ActiveBlockList::update(core::list<v3s16> &active_positions,
211 core::map<v3s16, bool> &blocks_removed,
212 core::map<v3s16, bool> &blocks_added)
217 core::map<v3s16, bool> newlist;
218 for(core::list<v3s16>::Iterator i = active_positions.begin();
219 i != active_positions.end(); i++)
221 fillRadiusBlock(*i, radius, newlist);
225 Find out which blocks on the old list are not on the new list
227 // Go through old list
228 for(core::map<v3s16, bool>::Iterator i = m_list.getIterator();
229 i.atEnd()==false; i++)
231 v3s16 p = i.getNode()->getKey();
232 // If not on new list, it's been removed
233 if(newlist.find(p) == NULL)
234 blocks_removed.insert(p, true);
238 Find out which blocks on the new list are not on the old list
240 // Go through new list
241 for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
242 i.atEnd()==false; i++)
244 v3s16 p = i.getNode()->getKey();
245 // If not on old list, it's been added
246 if(m_list.find(p) == NULL)
247 blocks_added.insert(p, true);
254 for(core::map<v3s16, bool>::Iterator i = newlist.getIterator();
255 i.atEnd()==false; i++)
257 v3s16 p = i.getNode()->getKey();
258 m_list.insert(p, true);
266 ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server):
269 m_random_spawn_timer(3),
270 m_send_recommended_timer(0),
272 m_game_time_fraction_counter(0)
276 ServerEnvironment::~ServerEnvironment()
278 // Clear active block list.
279 // This makes the next one delete all active objects.
280 m_active_blocks.clear();
282 // Convert all objects to static and delete the active objects
283 deactivateFarObjects(true);
289 void ServerEnvironment::serializePlayers(const std::string &savedir)
291 std::string players_path = savedir + "/players";
292 fs::CreateDir(players_path);
294 core::map<Player*, bool> saved_players;
296 std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
297 for(u32 i=0; i<player_files.size(); i++)
299 if(player_files[i].dir)
302 // Full path to this file
303 std::string path = players_path + "/" + player_files[i].name;
305 //dstream<<"Checking player file "<<path<<std::endl;
307 // Load player to see what is its name
308 ServerRemotePlayer testplayer;
310 // Open file and deserialize
311 std::ifstream is(path.c_str(), std::ios_base::binary);
312 if(is.good() == false)
314 dstream<<"Failed to read "<<path<<std::endl;
317 testplayer.deSerialize(is);
320 //dstream<<"Loaded test player with name "<<testplayer.getName()<<std::endl;
322 // Search for the player
323 std::string playername = testplayer.getName();
324 Player *player = getPlayer(playername.c_str());
327 dstream<<"Didn't find matching player, ignoring file "<<path<<std::endl;
331 //dstream<<"Found matching player, overwriting."<<std::endl;
333 // OK, found. Save player there.
335 // Open file and serialize
336 std::ofstream os(path.c_str(), std::ios_base::binary);
337 if(os.good() == false)
339 dstream<<"Failed to overwrite "<<path<<std::endl;
342 player->serialize(os);
343 saved_players.insert(player, true);
347 for(core::list<Player*>::Iterator i = m_players.begin();
348 i != m_players.end(); i++)
351 if(saved_players.find(player) != NULL)
353 /*dstream<<"Player "<<player->getName()
354 <<" was already saved."<<std::endl;*/
357 std::string playername = player->getName();
358 // Don't save unnamed player
361 //dstream<<"Not saving unnamed player."<<std::endl;
367 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false)
368 playername = "player";
369 std::string path = players_path + "/" + playername;
371 for(u32 i=0; i<1000; i++)
373 if(fs::PathExists(path) == false)
378 path = players_path + "/" + playername + itos(i);
382 dstream<<"WARNING: Didn't find free file for player"<<std::endl;
387 /*dstream<<"Saving player "<<player->getName()<<" to "
389 // Open file and serialize
390 std::ofstream os(path.c_str(), std::ios_base::binary);
391 if(os.good() == false)
393 dstream<<"WARNING: Failed to overwrite "<<path<<std::endl;
396 player->serialize(os);
397 saved_players.insert(player, true);
401 //dstream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
404 void ServerEnvironment::deSerializePlayers(const std::string &savedir)
406 std::string players_path = savedir + "/players";
408 core::map<Player*, bool> saved_players;
410 std::vector<fs::DirListNode> player_files = fs::GetDirListing(players_path);
411 for(u32 i=0; i<player_files.size(); i++)
413 if(player_files[i].dir)
416 // Full path to this file
417 std::string path = players_path + "/" + player_files[i].name;
419 dstream<<"Checking player file "<<path<<std::endl;
421 // Load player to see what is its name
422 ServerRemotePlayer testplayer;
424 // Open file and deserialize
425 std::ifstream is(path.c_str(), std::ios_base::binary);
426 if(is.good() == false)
428 dstream<<"Failed to read "<<path<<std::endl;
431 testplayer.deSerialize(is);
434 if(!string_allowed(testplayer.getName(), PLAYERNAME_ALLOWED_CHARS))
436 dstream<<"Not loading player with invalid name: "
437 <<testplayer.getName()<<std::endl;
440 dstream<<"Loaded test player with name "<<testplayer.getName()
443 // Search for the player
444 std::string playername = testplayer.getName();
445 Player *player = getPlayer(playername.c_str());
446 bool newplayer = false;
449 dstream<<"Is a new player"<<std::endl;
450 player = new ServerRemotePlayer();
456 dstream<<"Reading player "<<testplayer.getName()<<" from "
458 // Open file and deserialize
459 std::ifstream is(path.c_str(), std::ios_base::binary);
460 if(is.good() == false)
462 dstream<<"Failed to read "<<path<<std::endl;
465 player->deSerialize(is);
473 void ServerEnvironment::saveMeta(const std::string &savedir)
475 std::string path = savedir + "/env_meta.txt";
477 // Open file and serialize
478 std::ofstream os(path.c_str(), std::ios_base::binary);
479 if(os.good() == false)
481 dstream<<"WARNING: ServerEnvironment::saveMeta(): Failed to open "
483 throw SerializationError("Couldn't save env meta");
487 args.setU64("game_time", m_game_time);
488 args.setU64("time_of_day", getTimeOfDay());
493 void ServerEnvironment::loadMeta(const std::string &savedir)
495 std::string path = savedir + "/env_meta.txt";
497 // Open file and deserialize
498 std::ifstream is(path.c_str(), std::ios_base::binary);
499 if(is.good() == false)
501 dstream<<"WARNING: ServerEnvironment::loadMeta(): Failed to open "
503 throw SerializationError("Couldn't load env meta");
511 throw SerializationError
512 ("ServerEnvironment::loadMeta(): EnvArgsEnd not found");
514 std::getline(is, line);
515 std::string trimmedline = trim(line);
516 if(trimmedline == "EnvArgsEnd")
518 args.parseConfigLine(line);
522 m_game_time = args.getU64("game_time");
523 }catch(SettingNotFoundException &e){
524 // Getting this is crucial, otherwise timestamps are useless
525 throw SerializationError("Couldn't load env meta game_time");
529 m_time_of_day = args.getU64("time_of_day");
530 }catch(SettingNotFoundException &e){
531 // This is not as important
532 m_time_of_day = 9000;
537 // This is probably very useless
538 void spawnRandomObjects(MapBlock *block)
540 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
541 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
543 bool last_node_walkable = false;
544 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
547 MapNode n = block->getNodeNoEx(p);
548 if(n.getContent() == CONTENT_IGNORE)
550 if(content_features(n).liquid_type != LIQUID_NONE)
552 if(content_features(n).walkable)
554 last_node_walkable = true;
557 if(last_node_walkable)
559 // If block contains light information
560 if(content_features(n).param_type == CPT_LIGHT)
562 if(n.getLight(LIGHTBANK_DAY) <= 5)
564 if(myrand() % 1000 == 0)
566 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
568 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
569 std::string data = obj->getStaticData();
570 StaticObject s_obj(obj->getType(),
571 obj->getBasePosition(), data);
573 block->m_static_objects.insert(0, s_obj);
575 block->setChangedFlag();
580 last_node_walkable = false;
586 void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
588 // Get time difference
590 u32 stamp = block->getTimestamp();
591 if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
592 dtime_s = m_game_time - block->getTimestamp();
593 dtime_s += additional_dtime;
595 // Set current time as timestamp (and let it set ChangedFlag)
596 block->setTimestamp(m_game_time);
598 //dstream<<"Block is "<<dtime_s<<" seconds old."<<std::endl;
600 // Activate stored objects
601 activateObjects(block);
604 bool changed = block->m_node_metadata.step((float)dtime_s);
608 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
609 event.p = block->getPos();
610 m_map->dispatchEvent(&event);
612 block->setChangedFlag();
615 // TODO: Do something
616 // TODO: Implement usage of ActiveBlockModifier
618 // Here's a quick demonstration
620 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
621 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
622 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
624 v3s16 p = p0 + block->getPosRelative();
625 MapNode n = block->getNodeNoEx(p0);
628 // Convert all mud under proper day lighting to grass
629 if(n.getContent() == CONTENT_MUD)
633 MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
634 if(content_features(n_top).air_equivalent &&
635 n_top.getLight(LIGHTBANK_DAY) >= 13)
637 n.setContent(CONTENT_GRASS);
638 m_map->addNodeWithEvent(p, n);
646 void ServerEnvironment::step(float dtime)
648 DSTACK(__FUNCTION_NAME);
650 //TimeTaker timer("ServerEnv step");
653 bool footprints = g_settings->getBool("footprints");
659 m_game_time_fraction_counter += dtime;
660 u32 inc_i = (u32)m_game_time_fraction_counter;
661 m_game_time += inc_i;
662 m_game_time_fraction_counter -= (float)inc_i;
668 for(core::list<Player*>::Iterator i = m_players.begin();
669 i != m_players.end(); i++)
673 // Ignore disconnected players
674 if(player->peer_id == 0)
677 v3f playerpos = player->getPosition();
680 player->move(dtime, *m_map, 100*BS);
683 Add footsteps to grass
687 // Get node that is at BS/4 under player
688 v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
690 MapNode n = m_map->getNode(bottompos);
691 if(n.getContent() == CONTENT_GRASS)
693 n.setContent(CONTENT_GRASS_FOOTSTEPS);
694 m_map->setNode(bottompos, n);
697 catch(InvalidPositionException &e)
704 Manage active block list
706 if(m_active_blocks_management_interval.step(dtime, 2.0))
709 Get player block positions
711 core::list<v3s16> players_blockpos;
712 for(core::list<Player*>::Iterator
713 i = m_players.begin();
714 i != m_players.end(); i++)
717 // Ignore disconnected players
718 if(player->peer_id == 0)
720 v3s16 blockpos = getNodeBlockPos(
721 floatToInt(player->getPosition(), BS));
722 players_blockpos.push_back(blockpos);
726 Update list of active blocks, collecting changes
728 const s16 active_block_range = 5;
729 core::map<v3s16, bool> blocks_removed;
730 core::map<v3s16, bool> blocks_added;
731 m_active_blocks.update(players_blockpos, active_block_range,
732 blocks_removed, blocks_added);
735 Handle removed blocks
738 // Convert active objects that are no more in active blocks to static
739 deactivateFarObjects(false);
741 for(core::map<v3s16, bool>::Iterator
742 i = blocks_removed.getIterator();
743 i.atEnd()==false; i++)
745 v3s16 p = i.getNode()->getKey();
747 /*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
748 <<") became inactive"<<std::endl;*/
750 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
754 // Set current time as timestamp (and let it set ChangedFlag)
755 block->setTimestamp(m_game_time);
762 for(core::map<v3s16, bool>::Iterator
763 i = blocks_added.getIterator();
764 i.atEnd()==false; i++)
766 v3s16 p = i.getNode()->getKey();
768 /*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
769 <<") became active"<<std::endl;*/
771 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
775 activateBlock(block);
780 Mess around in active blocks
782 if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
786 for(core::map<v3s16, bool>::Iterator
787 i = m_active_blocks.m_list.getIterator();
788 i.atEnd()==false; i++)
790 v3s16 p = i.getNode()->getKey();
792 /*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
793 <<") being handled"<<std::endl;*/
795 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
799 // Reset block usage timer
800 block->resetUsageTimer();
802 // Set current time as timestamp
803 block->setTimestampNoChangedFlag(m_game_time);
806 bool changed = block->m_node_metadata.step(dtime);
810 event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
812 m_map->dispatchEvent(&event);
814 block->setChangedFlag();
818 if(m_active_blocks_test_interval.step(dtime, 10.0))
820 //float dtime = 10.0;
822 for(core::map<v3s16, bool>::Iterator
823 i = m_active_blocks.m_list.getIterator();
824 i.atEnd()==false; i++)
826 v3s16 p = i.getNode()->getKey();
828 /*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
829 <<") being handled"<<std::endl;*/
831 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
835 // Set current time as timestamp
836 block->setTimestampNoChangedFlag(m_game_time);
841 Note that map modifications should be done using the event-
842 making map methods so that the server gets information
845 Reading can be done quickly directly from the block.
847 Everything should bind to inside this single content
848 searching loop to keep things fast.
850 // TODO: Implement usage of ActiveBlockModifier
852 // Find out how many objects the block contains
853 u32 active_object_count = block->m_static_objects.m_active.size();
854 // Find out how many objects this and all the neighbors contain
855 u32 active_object_count_wider = 0;
856 for(s16 x=-1; x<=1; x++)
857 for(s16 y=-1; y<=1; y++)
858 for(s16 z=-1; z<=1; z++)
860 MapBlock *block = m_map->getBlockNoCreateNoEx(p+v3s16(x,y,z));
863 active_object_count_wider +=
864 block->m_static_objects.m_active.size();
868 for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
869 for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
870 for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
872 v3s16 p = p0 + block->getPosRelative();
873 MapNode n = block->getNodeNoEx(p0);
877 Convert mud under proper lighting to grass
879 if(n.getContent() == CONTENT_MUD)
883 MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
884 if(content_features(n_top).air_equivalent &&
885 n_top.getLightBlend(getDayNightRatio()) >= 13)
887 n.setContent(CONTENT_GRASS);
888 m_map->addNodeWithEvent(p, n);
893 Convert grass into mud if under something else than air
895 if(n.getContent() == CONTENT_GRASS)
897 //if(myrand()%20 == 0)
899 MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
900 if(content_features(n_top).air_equivalent == false)
902 n.setContent(CONTENT_MUD);
903 m_map->addNodeWithEvent(p, n);
908 Rats spawn around regular trees
910 if(n.getContent() == CONTENT_TREE ||
911 n.getContent() == CONTENT_JUNGLETREE)
913 if(myrand()%200 == 0 && active_object_count_wider == 0)
915 v3s16 p1 = p + v3s16(myrand_range(-2, 2),
916 0, myrand_range(-2, 2));
917 MapNode n1 = m_map->getNodeNoEx(p1);
918 MapNode n1b = m_map->getNodeNoEx(p1+v3s16(0,-1,0));
919 if(n1b.getContent() == CONTENT_GRASS &&
920 n1.getContent() == CONTENT_AIR)
922 v3f pos = intToFloat(p1, BS);
923 ServerActiveObject *obj = new RatSAO(this, 0, pos);
924 addActiveObject(obj);
929 Make trees from saplings!
931 if(n.getContent() == CONTENT_SAPLING)
935 core::map<v3s16, MapBlock*> modified_blocks;
937 ManualMapVoxelManipulator vmanip(m_map);
938 v3s16 tree_blockp = getNodeBlockPos(tree_p);
939 vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
940 bool is_apple_tree = myrand()%4 == 0;
941 mapgen::make_tree(vmanip, tree_p, is_apple_tree);
942 vmanip.blitBackAll(&modified_blocks);
945 core::map<v3s16, MapBlock*> lighting_modified_blocks;
946 for(core::map<v3s16, MapBlock*>::Iterator
947 i = modified_blocks.getIterator();
948 i.atEnd() == false; i++)
950 lighting_modified_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue());
952 m_map->updateLighting(lighting_modified_blocks, modified_blocks);
954 // Send a MEET_OTHER event
956 event.type = MEET_OTHER;
957 for(core::map<v3s16, MapBlock*>::Iterator
958 i = modified_blocks.getIterator();
959 i.atEnd() == false; i++)
961 v3s16 p = i.getNode()->getKey();
962 event.modified_blocks.insert(p, true);
964 m_map->dispatchEvent(&event);
976 //TimeTaker timer("Step active objects");
978 // This helps the objects to send data at the same time
979 bool send_recommended = false;
980 m_send_recommended_timer += dtime;
981 if(m_send_recommended_timer > 0.15)
983 m_send_recommended_timer = 0;
984 send_recommended = true;
987 for(core::map<u16, ServerActiveObject*>::Iterator
988 i = m_active_objects.getIterator();
989 i.atEnd()==false; i++)
991 ServerActiveObject* obj = i.getNode()->getValue();
992 // Don't step if is to be removed or stored statically
993 if(obj->m_removed || obj->m_pending_deactivation)
996 obj->step(dtime, send_recommended);
997 // Read messages from object
998 while(obj->m_messages_out.size() > 0)
1000 m_active_object_messages.push_back(
1001 obj->m_messages_out.pop_front());
1007 Manage active objects
1009 if(m_object_management_interval.step(dtime, 0.5))
1012 Remove objects that satisfy (m_removed && m_known_by_count==0)
1014 removeRemovedObjects();
1017 if(g_settings->getBool("enable_experimental"))
1024 m_random_spawn_timer -= dtime;
1025 if(m_random_spawn_timer < 0)
1027 //m_random_spawn_timer += myrand_range(2.0, 20.0);
1028 //m_random_spawn_timer += 2.0;
1029 m_random_spawn_timer += 200.0;
1035 /*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
1036 s16 y = 1 + getServerMap().findGroundLevel(p2d);
1037 v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
1039 Player *player = getRandomConnectedPlayer();
1042 pos = player->getPosition();
1044 myrand_range(-3,3)*BS,
1046 myrand_range(-3,3)*BS
1050 Create a ServerActiveObject
1053 //TestSAO *obj = new TestSAO(this, 0, pos);
1054 //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
1055 //ServerActiveObject *obj = new RatSAO(this, 0, pos);
1056 //ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
1057 ServerActiveObject *obj = new FireflySAO(this, 0, pos);
1058 addActiveObject(obj);
1062 } // enable_experimental
1065 ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
1067 core::map<u16, ServerActiveObject*>::Node *n;
1068 n = m_active_objects.find(id);
1071 return n->getValue();
1074 bool isFreeServerActiveObjectId(u16 id,
1075 core::map<u16, ServerActiveObject*> &objects)
1080 for(core::map<u16, ServerActiveObject*>::Iterator
1081 i = objects.getIterator();
1082 i.atEnd()==false; i++)
1084 if(i.getNode()->getKey() == id)
1090 u16 getFreeServerActiveObjectId(
1091 core::map<u16, ServerActiveObject*> &objects)
1096 if(isFreeServerActiveObjectId(new_id, objects))
1106 u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
1109 u16 id = addActiveObjectRaw(object, true);
1114 Finds out what new objects have been added to
1115 inside a radius around a position
1117 void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
1118 core::map<u16, bool> ¤t_objects,
1119 core::map<u16, bool> &added_objects)
1121 v3f pos_f = intToFloat(pos, BS);
1122 f32 radius_f = radius * BS;
1124 Go through the object list,
1125 - discard m_removed objects,
1126 - discard objects that are too far away,
1127 - discard objects that are found in current_objects.
1128 - add remaining objects to added_objects
1130 for(core::map<u16, ServerActiveObject*>::Iterator
1131 i = m_active_objects.getIterator();
1132 i.atEnd()==false; i++)
1134 u16 id = i.getNode()->getKey();
1136 ServerActiveObject *object = i.getNode()->getValue();
1139 // Discard if removed
1140 if(object->m_removed)
1142 // Discard if too far
1143 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1144 if(distance_f > radius_f)
1146 // Discard if already on current_objects
1147 core::map<u16, bool>::Node *n;
1148 n = current_objects.find(id);
1151 // Add to added_objects
1152 added_objects.insert(id, false);
1157 Finds out what objects have been removed from
1158 inside a radius around a position
1160 void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
1161 core::map<u16, bool> ¤t_objects,
1162 core::map<u16, bool> &removed_objects)
1164 v3f pos_f = intToFloat(pos, BS);
1165 f32 radius_f = radius * BS;
1167 Go through current_objects; object is removed if:
1168 - object is not found in m_active_objects (this is actually an
1169 error condition; objects should be set m_removed=true and removed
1170 only after all clients have been informed about removal), or
1171 - object has m_removed=true, or
1172 - object is too far away
1174 for(core::map<u16, bool>::Iterator
1175 i = current_objects.getIterator();
1176 i.atEnd()==false; i++)
1178 u16 id = i.getNode()->getKey();
1179 ServerActiveObject *object = getActiveObject(id);
1182 dstream<<"WARNING: ServerEnvironment::getRemovedActiveObjects():"
1183 <<" object in current_objects is NULL"<<std::endl;
1185 else if(object->m_removed == false)
1187 f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
1188 /*dstream<<"removed == false"
1189 <<"distance_f = "<<distance_f
1190 <<", radius_f = "<<radius_f<<std::endl;*/
1191 if(distance_f < radius_f)
1197 removed_objects.insert(id, false);
1201 ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
1203 if(m_active_object_messages.size() == 0)
1204 return ActiveObjectMessage(0);
1206 return m_active_object_messages.pop_front();
1210 ************ Private methods *************
1213 u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
1217 if(object->getId() == 0)
1219 u16 new_id = getFreeServerActiveObjectId(m_active_objects);
1222 dstream<<"WARNING: ServerEnvironment::addActiveObjectRaw(): "
1223 <<"no free ids available"<<std::endl;
1227 object->setId(new_id);
1229 if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
1231 dstream<<"WARNING: ServerEnvironment::addActiveObjectRaw(): "
1232 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1236 /*dstream<<"INFO: ServerEnvironment::addActiveObjectRaw(): "
1237 <<"added (id="<<object->getId()<<")"<<std::endl;*/
1239 m_active_objects.insert(object->getId(), object);
1241 // Add static object to active static list of the block
1242 v3f objectpos = object->getBasePosition();
1243 std::string staticdata = object->getStaticData();
1244 StaticObject s_obj(object->getType(), objectpos, staticdata);
1245 // Add to the block where the object is located in
1246 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1247 MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1250 block->m_static_objects.m_active.insert(object->getId(), s_obj);
1251 object->m_static_exists = true;
1252 object->m_static_block = blockpos;
1255 block->setChangedFlag();
1258 dstream<<"WARNING: ServerEnv: Could not find a block for "
1259 <<"storing newly added static active object"<<std::endl;
1262 return object->getId();
1266 Remove objects that satisfy (m_removed && m_known_by_count==0)
1268 void ServerEnvironment::removeRemovedObjects()
1270 core::list<u16> objects_to_remove;
1271 for(core::map<u16, ServerActiveObject*>::Iterator
1272 i = m_active_objects.getIterator();
1273 i.atEnd()==false; i++)
1275 u16 id = i.getNode()->getKey();
1276 ServerActiveObject* obj = i.getNode()->getValue();
1277 // This shouldn't happen but check it
1280 dstream<<"WARNING: NULL object found in ServerEnvironment"
1281 <<" while finding removed objects. id="<<id<<std::endl;
1282 // Id to be removed from m_active_objects
1283 objects_to_remove.push_back(id);
1288 We will delete objects that are marked as removed or thatare
1289 waiting for deletion after deactivation
1291 if(obj->m_removed == false && obj->m_pending_deactivation == false)
1295 Delete static data from block if is marked as removed
1297 if(obj->m_static_exists && obj->m_removed)
1299 MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
1302 block->m_static_objects.remove(id);
1303 block->setChangedFlag();
1307 // If m_known_by_count > 0, don't actually remove.
1308 if(obj->m_known_by_count > 0)
1313 // Id to be removed from m_active_objects
1314 objects_to_remove.push_back(id);
1316 // Remove references from m_active_objects
1317 for(core::list<u16>::Iterator i = objects_to_remove.begin();
1318 i != objects_to_remove.end(); i++)
1320 m_active_objects.remove(*i);
1325 Convert stored objects from blocks near the players to active.
1327 void ServerEnvironment::activateObjects(MapBlock *block)
1331 // Ignore if no stored objects (to not set changed flag)
1332 if(block->m_static_objects.m_stored.size() == 0)
1334 // A list for objects that couldn't be converted to static for some
1335 // reason. They will be stored back.
1336 core::list<StaticObject> new_stored;
1337 // Loop through stored static objects
1338 for(core::list<StaticObject>::Iterator
1339 i = block->m_static_objects.m_stored.begin();
1340 i != block->m_static_objects.m_stored.end(); i++)
1342 /*dstream<<"INFO: Server: Creating an active object from "
1343 <<"static data"<<std::endl;*/
1344 StaticObject &s_obj = *i;
1345 // Create an active object from the data
1346 ServerActiveObject *obj = ServerActiveObject::create
1347 (s_obj.type, this, 0, s_obj.pos, s_obj.data);
1348 // If couldn't create object, store static data back.
1351 new_stored.push_back(s_obj);
1354 // This will also add the object to the active static list
1355 addActiveObjectRaw(obj, false);
1356 //u16 id = addActiveObjectRaw(obj, false);
1358 // Clear stored list
1359 block->m_static_objects.m_stored.clear();
1360 // Add leftover failed stuff to stored list
1361 for(core::list<StaticObject>::Iterator
1362 i = new_stored.begin();
1363 i != new_stored.end(); i++)
1365 StaticObject &s_obj = *i;
1366 block->m_static_objects.m_stored.push_back(s_obj);
1368 // Block has been modified
1369 // NOTE: No it has not really. Save I/O here.
1370 //block->setChangedFlag();
1374 Convert objects that are not in active blocks to static.
1376 If m_known_by_count != 0, active object is not deleted, but static
1377 data is still updated.
1379 If force_delete is set, active object is deleted nevertheless. It
1380 shall only be set so in the destructor of the environment.
1382 void ServerEnvironment::deactivateFarObjects(bool force_delete)
1384 core::list<u16> objects_to_remove;
1385 for(core::map<u16, ServerActiveObject*>::Iterator
1386 i = m_active_objects.getIterator();
1387 i.atEnd()==false; i++)
1389 ServerActiveObject* obj = i.getNode()->getValue();
1391 // This shouldn't happen but check it
1394 dstream<<"WARNING: NULL object found in ServerEnvironment"
1400 u16 id = i.getNode()->getKey();
1401 v3f objectpos = obj->getBasePosition();
1403 // The block in which the object resides in
1404 v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
1406 // If block is active, don't remove
1407 if(m_active_blocks.contains(blockpos_o))
1411 Update the static data
1414 // Delete old static object
1415 MapBlock *oldblock = NULL;
1416 if(obj->m_static_exists)
1418 MapBlock *block = m_map->getBlockNoCreateNoEx
1419 (obj->m_static_block);
1422 block->m_static_objects.remove(id);
1426 // Create new static object
1427 std::string staticdata = obj->getStaticData();
1428 StaticObject s_obj(obj->getType(), objectpos, staticdata);
1429 // Add to the block where the object is located in
1430 v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
1431 // Get or generate the block
1432 MapBlock *block = m_map->emergeBlock(blockpos);
1434 /*MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
1437 // Block not found. Is the old block still ok?
1440 // Load from disk or generate
1442 block = m_map->emergeBlock(blockpos);
1447 block->m_static_objects.insert(0, s_obj);
1448 block->setChangedFlag();
1449 obj->m_static_exists = true;
1450 obj->m_static_block = block->getPos();
1453 dstream<<"WARNING: ServerEnv: Could not find or generate "
1454 <<"a block for storing static object"<<std::endl;
1455 obj->m_static_exists = false;
1460 Delete active object if not known by some client,
1461 else set pending deactivation
1464 // If known by some client, don't delete.
1465 if(obj->m_known_by_count > 0 && force_delete == false)
1467 obj->m_pending_deactivation = true;
1471 /*dstream<<"INFO: Server: Stored static data. Deleting object."
1473 // Delete active object
1475 // Id to be removed from m_active_objects
1476 objects_to_remove.push_back(id);
1479 // Remove references from m_active_objects
1480 for(core::list<u16>::Iterator i = objects_to_remove.begin();
1481 i != objects_to_remove.end(); i++)
1483 m_active_objects.remove(*i);
1494 ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr):
1502 ClientEnvironment::~ClientEnvironment()
1504 // delete active objects
1505 for(core::map<u16, ClientActiveObject*>::Iterator
1506 i = m_active_objects.getIterator();
1507 i.atEnd()==false; i++)
1509 delete i.getNode()->getValue();
1516 void ClientEnvironment::addPlayer(Player *player)
1518 DSTACK(__FUNCTION_NAME);
1520 It is a failure if player is local and there already is a local
1523 assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
1525 Environment::addPlayer(player);
1528 LocalPlayer * ClientEnvironment::getLocalPlayer()
1530 for(core::list<Player*>::Iterator i = m_players.begin();
1531 i != m_players.end(); i++)
1533 Player *player = *i;
1534 if(player->isLocal())
1535 return (LocalPlayer*)player;
1540 void ClientEnvironment::step(float dtime)
1542 DSTACK(__FUNCTION_NAME);
1544 // Get some settings
1545 bool free_move = g_settings->getBool("free_move");
1546 bool footprints = g_settings->getBool("footprints");
1549 LocalPlayer *lplayer = getLocalPlayer();
1551 // collision info queue
1552 core::list<CollisionInfo> player_collisions;
1555 Get the speed the player is going
1557 bool is_climbing = lplayer->is_climbing;
1560 Check if the player is frozen (don't apply physics)
1562 bool is_frozen = lplayer->is_frozen;
1564 f32 player_speed = 0.001; // just some small value
1565 player_speed = lplayer->getSpeed().getLength();
1568 Maximum position increment
1570 //f32 position_max_increment = 0.05*BS;
1571 f32 position_max_increment = 0.1*BS;
1573 // Maximum time increment (for collision detection etc)
1574 // time = distance / speed
1575 f32 dtime_max_increment = position_max_increment / player_speed;
1577 // Maximum time increment is 10ms or lower
1578 if(dtime_max_increment > 0.01)
1579 dtime_max_increment = 0.01;
1581 // Don't allow overly huge dtime
1585 f32 dtime_downcount = dtime;
1588 Stuff that has a maximum time increment
1597 if(dtime_downcount > dtime_max_increment)
1599 dtime_part = dtime_max_increment;
1600 dtime_downcount -= dtime_part;
1604 dtime_part = dtime_downcount;
1606 Setting this to 0 (no -=dtime_part) disables an infinite loop
1607 when dtime_part is so small that dtime_downcount -= dtime_part
1610 dtime_downcount = 0;
1618 v3f lplayerpos = lplayer->getPosition();
1621 if(free_move == false && is_climbing == false && is_frozen == false)
1624 v3f speed = lplayer->getSpeed();
1625 if(lplayer->swimming_up == false)
1626 speed.Y -= 9.81 * BS * dtime_part * 2;
1629 if(lplayer->in_water_stable || lplayer->in_water)
1631 f32 max_down = 2.0*BS;
1632 if(speed.Y < -max_down) speed.Y = -max_down;
1635 if(speed.getLength() > max)
1637 speed = speed / speed.getLength() * max;
1641 lplayer->setSpeed(speed);
1646 This also does collision detection.
1648 lplayer->move(dtime_part, *m_map, position_max_increment,
1649 &player_collisions);
1652 while(dtime_downcount > 0.001);
1654 //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
1656 for(core::list<CollisionInfo>::Iterator
1657 i = player_collisions.begin();
1658 i != player_collisions.end(); i++)
1660 CollisionInfo &info = *i;
1661 if(info.t == COLLISION_FALL)
1663 //f32 tolerance = BS*10; // 2 without damage
1664 f32 tolerance = BS*12; // 3 without damage
1666 if(info.speed > tolerance)
1668 f32 damage_f = (info.speed - tolerance)/BS*factor;
1669 u16 damage = (u16)(damage_f+0.5);
1670 if(lplayer->hp > damage)
1671 lplayer->hp -= damage;
1675 ClientEnvEvent event;
1676 event.type = CEE_PLAYER_DAMAGE;
1677 event.player_damage.amount = damage;
1678 m_client_event_queue.push_back(event);
1684 A quick draft of lava damage
1686 if(m_lava_hurt_interval.step(dtime, 1.0))
1688 v3f pf = lplayer->getPosition();
1690 // Feet, middle and head
1691 v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
1692 MapNode n1 = m_map->getNodeNoEx(p1);
1693 v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
1694 MapNode n2 = m_map->getNodeNoEx(p2);
1695 v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
1696 MapNode n3 = m_map->getNodeNoEx(p2);
1698 u32 damage_per_second = 0;
1699 damage_per_second = MYMAX(damage_per_second,
1700 content_features(n1).damage_per_second);
1701 damage_per_second = MYMAX(damage_per_second,
1702 content_features(n2).damage_per_second);
1703 damage_per_second = MYMAX(damage_per_second,
1704 content_features(n3).damage_per_second);
1706 if(damage_per_second != 0)
1708 ClientEnvEvent event;
1709 event.type = CEE_PLAYER_DAMAGE;
1710 event.player_damage.amount = damage_per_second;
1711 m_client_event_queue.push_back(event);
1716 Stuff that can be done in an arbitarily large dtime
1718 for(core::list<Player*>::Iterator i = m_players.begin();
1719 i != m_players.end(); i++)
1721 Player *player = *i;
1722 v3f playerpos = player->getPosition();
1725 Handle non-local players
1727 if(player->isLocal() == false)
1730 player->move(dtime, *m_map, 100*BS);
1734 // Update lighting on all players on client
1735 u8 light = LIGHT_MAX;
1738 v3s16 p = player->getLightPosition();
1739 MapNode n = m_map->getNode(p);
1740 light = n.getLightBlend(getDayNightRatio());
1742 catch(InvalidPositionException &e) {}
1743 player->updateLight(light);
1746 Add footsteps to grass
1750 // Get node that is at BS/4 under player
1751 v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
1753 MapNode n = m_map->getNode(bottompos);
1754 if(n.getContent() == CONTENT_GRASS)
1756 n.setContent(CONTENT_GRASS_FOOTSTEPS);
1757 m_map->setNode(bottompos, n);
1758 // Update mesh on client
1759 if(m_map->mapType() == MAPTYPE_CLIENT)
1761 v3s16 p_blocks = getNodeBlockPos(bottompos);
1762 MapBlock *b = m_map->getBlockNoCreate(p_blocks);
1763 //b->updateMesh(getDayNightRatio());
1764 b->setMeshExpired(true);
1768 catch(InvalidPositionException &e)
1775 Step active objects and update lighting of them
1778 for(core::map<u16, ClientActiveObject*>::Iterator
1779 i = m_active_objects.getIterator();
1780 i.atEnd()==false; i++)
1782 ClientActiveObject* obj = i.getNode()->getValue();
1784 obj->step(dtime, this);
1786 if(m_active_object_light_update_interval.step(dtime, 0.21))
1789 //u8 light = LIGHT_MAX;
1793 v3s16 p = obj->getLightPosition();
1794 MapNode n = m_map->getNode(p);
1795 light = n.getLightBlend(getDayNightRatio());
1797 catch(InvalidPositionException &e) {}
1798 obj->updateLight(light);
1803 void ClientEnvironment::updateMeshes(v3s16 blockpos)
1805 m_map->updateMeshes(blockpos, getDayNightRatio());
1808 void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
1810 m_map->expireMeshes(only_daynight_diffed);
1813 ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
1815 core::map<u16, ClientActiveObject*>::Node *n;
1816 n = m_active_objects.find(id);
1819 return n->getValue();
1822 bool isFreeClientActiveObjectId(u16 id,
1823 core::map<u16, ClientActiveObject*> &objects)
1828 for(core::map<u16, ClientActiveObject*>::Iterator
1829 i = objects.getIterator();
1830 i.atEnd()==false; i++)
1832 if(i.getNode()->getKey() == id)
1838 u16 getFreeClientActiveObjectId(
1839 core::map<u16, ClientActiveObject*> &objects)
1844 if(isFreeClientActiveObjectId(new_id, objects))
1854 u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
1857 if(object->getId() == 0)
1859 u16 new_id = getFreeClientActiveObjectId(m_active_objects);
1862 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1863 <<"no free ids available"<<std::endl;
1867 object->setId(new_id);
1869 if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
1871 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1872 <<"id is not free ("<<object->getId()<<")"<<std::endl;
1876 dstream<<"INFO: ClientEnvironment::addActiveObject(): "
1877 <<"added (id="<<object->getId()<<")"<<std::endl;
1878 m_active_objects.insert(object->getId(), object);
1879 object->addToScene(m_smgr);
1880 return object->getId();
1883 void ClientEnvironment::addActiveObject(u16 id, u8 type,
1884 const std::string &init_data)
1886 ClientActiveObject* obj = ClientActiveObject::create(type);
1889 dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
1890 <<"id="<<id<<" type="<<type<<": Couldn't create object"
1897 addActiveObject(obj);
1899 obj->initialize(init_data);
1902 void ClientEnvironment::removeActiveObject(u16 id)
1904 dstream<<"ClientEnvironment::removeActiveObject(): "
1905 <<"id="<<id<<std::endl;
1906 ClientActiveObject* obj = getActiveObject(id);
1909 dstream<<"WARNING: ClientEnvironment::removeActiveObject(): "
1910 <<"id="<<id<<" not found"<<std::endl;
1913 obj->removeFromScene();
1915 m_active_objects.remove(id);
1918 void ClientEnvironment::processActiveObjectMessage(u16 id,
1919 const std::string &data)
1921 ClientActiveObject* obj = getActiveObject(id);
1924 dstream<<"WARNING: ClientEnvironment::processActiveObjectMessage():"
1925 <<" got message for id="<<id<<", which doesn't exist."
1929 obj->processMessage(data);
1933 Callbacks for activeobjects
1936 void ClientEnvironment::damageLocalPlayer(u8 damage)
1938 LocalPlayer *lplayer = getLocalPlayer();
1941 if(lplayer->hp > damage)
1942 lplayer->hp -= damage;
1946 ClientEnvEvent event;
1947 event.type = CEE_PLAYER_DAMAGE;
1948 event.player_damage.amount = damage;
1949 m_client_event_queue.push_back(event);
1953 Client likes to call these
1956 void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
1957 core::array<DistanceSortedActiveObject> &dest)
1959 for(core::map<u16, ClientActiveObject*>::Iterator
1960 i = m_active_objects.getIterator();
1961 i.atEnd()==false; i++)
1963 ClientActiveObject* obj = i.getNode()->getValue();
1965 f32 d = (obj->getPosition() - origin).getLength();
1970 DistanceSortedActiveObject dso(obj, d);
1972 dest.push_back(dso);
1976 ClientEnvEvent ClientEnvironment::getClientEvent()
1978 if(m_client_event_queue.size() == 0)
1980 ClientEnvEvent event;
1981 event.type = CEE_NONE;
1984 return m_client_event_queue.pop_front();
1987 #endif // #ifndef SERVER