crafted_teleports, teleport pairs/loops, working "0,0,0"

This commit is contained in:
placki 2011-10-29 00:14:40 +02:00
parent 73360b86cd
commit d264de084c
5 changed files with 92 additions and 24 deletions

View File

@ -154,4 +154,8 @@
# Set to true to enable experimental features or stuff that is tested
# (varies from version to version, usually not useful at all)
#enable_experimental = false
# 0 - disables crafted teleports. 1 - teleport work if target area exists and there are 2 air/water (clear) tiles
# 2 - teleport A works iff it points to clear area containing teleport B, and teleport B points back to teleport A
# 3 or more - just like 2 but there can be 3 of more teleports in loop (warning - high value is bad for server performance)
#crafted_teleports = 4

View File

@ -109,5 +109,6 @@ void set_default_settings(Settings *settings)
settings->setDefault("server_map_save_interval", "10");
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
settings->setDefault("enable_experimental", "false");
settings->setDefault("crafted_teleports", "4");
}

View File

@ -40,13 +40,14 @@ Player::Player():
craftresult_is_preview(true),
hp(20),
peer_id(PEER_ID_INEXISTENT),
clanOwner(0),
m_selected_item(0),
m_pitch(0),
m_yaw(0),
m_speed(0,0,0),
m_position(0,0,0),
clanOwner(0)
m_position(0,0,0)
{
lastTeleportPos.X=FLT_MAX;
updateName("<not set>");
resetInventory();
}

View File

@ -171,6 +171,8 @@ public:
std::set<int> clans;
u16 clanOwner;
bool canModify(const ClansManager* clansManager, Map* map, MapBlock* block, MapNode* node, v3s16* nodepos) const;
v3f lastTeleportPos; //server: remember position player teleported to, to let him move away.
protected:
char m_name[PLAYERNAME_SIZE];

View File

@ -1816,6 +1816,38 @@ void Server::Receive()
}
}
bool getTeleportTarget(/*const*/ ServerEnvironment *m_env,/*in+out*/ v3s16 &where,/*out*/v3f &tgt)
{
// actionstream<<"Is Teleport at: "<<"("<<where.X<<","<<where.Y<<","<<where.Z<<") "<<std::endl;
SignNodeMetadata* meta=NULL;
if(m_env->getMap().getNodeNoEx(where).getContent() == CONTENT_TELEPORT)
meta = (SignNodeMetadata*)m_env->getMap().getNodeMetadata(where);
else {
where.Y++;
if(where.Y<MAP_GENERATION_LIMIT-1)
if(m_env->getMap().getNodeNoEx(where).getContent() == CONTENT_TELEPORT)
meta = (SignNodeMetadata*)m_env->getMap().getNodeMetadata(where);
}
if(meta){
std::string text = meta->getText();
if(text == "")
return false;
str_replace_char(text,',',' ');
std::istringstream is(text);
is >> tgt.X >> tgt.Y >> tgt.Z;
if( tgt.X >= MAP_GENERATION_LIMIT || tgt.X <= -MAP_GENERATION_LIMIT ||
tgt.Y >= MAP_GENERATION_LIMIT || tgt.Y <= -MAP_GENERATION_LIMIT ||
tgt.Z >= MAP_GENERATION_LIMIT || tgt.Z <= -MAP_GENERATION_LIMIT ||
( tgt.X == 0 && tgt.Y == 0 && tgt.Z == 0 && text.substr(0,5) != "0 0 0" )
) return false;
// actionstream<<"It points to: "<<"("<<tgt.X<<","<<tgt.Y<<","<<tgt.Z<<") "<<std::endl;
return true;
}
return false;
}
void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
@ -2174,30 +2206,58 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
<<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
//j
v3s16 pos = floatToInt(position, BS);
MapNode n = m_env.getMap().getNodeNoEx(pos);
if(n.getContent() == CONTENT_TELEPORT){
SignNodeMetadata* meta = (SignNodeMetadata*)m_env.getMap().getNodeMetadata(pos);
if(meta){
v3f t;
std::string text = meta->getText();
str_replace_char(text,',',' ');
std::istringstream is(text);
is >> t.X >> t.Y >> t.Z;
//j,placki
int teleport_option=g_settings->getU16("crafted_teleports");
if(teleport_option) {
v3s16 tele_posi = floatToInt(position, BS);
//TODO: map limits!
if( t.X > 32000 || t.X < -32000 ||
t.Y > 32000 || t.Y < -32000 ||
t.Z > 32000 || t.Z < -32000 ||
(t.X == 0 && t.Y == 0 && t.Z == 0)
) return;
dout_server << "Teleporting: " << text << std::endl;
player->setPosition(t*BS);
SendMovePlayer(player);
if(player->lastTeleportPos.X != FLT_MAX){
if(player->getPosition().getDistanceFrom(player->lastTeleportPos) <= BS*3/2) //1 tile away
return; //allow player to leave teleport destination
else
player->lastTeleportPos.X=FLT_MAX; //player left previous teleport destination
}
}
v3f tgtf;
if(getTeleportTarget(&m_env,tele_posi,tgtf)){
if(player->lastTeleportPos == tgtf*BS)
return; //already checked... and failed, so skip checks.
player->lastTeleportPos=tgtf*BS;
// check: is there known and empty place to teleport to?
v3s16 tgti=floatToInt(tgtf, 1);
content_t c1,c2;
c1=m_env.getMap().getNodeNoEx(tgti).getContent();
tgti.Y++;
c2=m_env.getMap().getNodeNoEx(tgti).getContent();
if((c1==CONTENT_IGNORE)||(c2==CONTENT_IGNORE)) //teleporting to unknown space?
return;
if(content_features(c1).walkable || content_features(c2).walkable)
return;
if(teleport_option > 1){
tgti=floatToInt(tgtf, 1);
bool loop=false;
while(!loop && teleport_option>1)
{ //check if there is teleport at primary teleport target, and it loops back.
v3f tgtfnext;
if(getTeleportTarget(&m_env,tgti,tgtfnext)){
tgti=floatToInt(tgtfnext, 1);
loop=(tele_posi.getDistanceFrom(tgti)<=1); // tile away
//actionstream<<" D:"<<tele_posi.getDistanceFrom(tgti)<<" from="<<"("<<tgtf.X<<","<<tgtf.Y<<","<<tgtf.Z<<")"<<
//" to="<<"("<<tgtfnext.X<<","<<tgtfnext.Y<<","<<tgtfnext.Z<<") "<< std::endl;
} else return; //no teleport at destination
teleport_option--;
}
if(!loop)
return;
}
dout_server << "Teleporting: " << tgtf.X << " " << tgtf.Y << " " << tgtf.Z << std::endl;
player->setPosition(tgtf*BS);
SendMovePlayer(player);
} //teleport exists
} //teleport_option
}
else if(command == TOSERVER_GOTBLOCKS)
{