Conflicts:
	src/game.cpp
	src/player.h
	src/server.h
master
jachoo 2011-11-10 20:33:41 +01:00
commit cc66191422
11 changed files with 277 additions and 62 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -154,4 +154,9 @@
# 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
#are players allowed to build connecting to border/edge of hostile clan territory
#build_on_borders = false

View File

@ -109,5 +109,7 @@ 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");
settings->setDefault("build_on_borders", "false");
}

View File

@ -936,12 +936,14 @@ void the_game(
L"",
core::rect<s32>(0,0,500,text_height*2+5) + v2s32(100,200), //j
false, false, guiroot);
guitext_info->setBackgroundColor(video::SColor(0x20000000));
// Ownership info (clans) //j
gui::IGUIStaticText *guitext_ownership = guienv->addStaticText(
L"",
core::rect<s32>(0,0,200,text_height+5) + v2s32(100,450), //j
core::rect<s32>(0,0,500,text_height+5) + v2s32(100,450), //j
false, false, guiroot);
guitext_ownership->setBackgroundColor(video::SColor(0x20000000));
// Chat text
gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
@ -1765,8 +1767,12 @@ void the_game(
bool canModifyNeighbour = player->canModify(&client.getEnv()->clansManager,NULL,block2,NULL,NULL);
bool canModify = canModifyNeighbour && player->canModify(&client.getEnv()->clansManager,NULL,block,NULL,NULL);
if(block_owner || block2_owner )
if(block_owner || block2_owner ){
if(block_owner == block2_owner)
ownershiptext = L"Property of clan ";
else
ownershiptext = L"Border of clan ";
}
if(block_owner)
ownershiptext += narrow_to_wide(clansManager->clanNameNoEx(block_owner));
@ -1797,7 +1803,43 @@ void the_game(
NodeMetadata *meta = client.getNodeMetadata(nodepos);
if(meta)
{
//maybe server should not be sending teleport info to clients at all?
infotext = narrow_to_wide(meta->infoText());
content_t content = map->getNodeNoEx(nodepos).getContent();
if(content == CONTENT_TELEPORT)
{
// meta/infotext contains text inside "" quotes.
// find 3rd comma
int icomma=infotext.find(L',');
if(icomma>0)
icomma=infotext.find(L',',icomma+1);
if(icomma>0)
icomma=infotext.find(L',',icomma+1);
if(!canModify)
{
if(icomma<0)
infotext = L"Unnamed teleport";
else
infotext=L"Teleport: "+infotext.substr(icomma+1,infotext.length()-icomma-2);
}
else
{
if(icomma<0)
infotext = infotext.substr(0,infotext.length()-1)+L",Unnamed\"";
}
}
else
if(content == CONTENT_BORDERSTONE)
{ char ts[50];
v3s16 tp=getContainerPos(nodepos,MAP_BLOCKSIZE);
tp*=MAP_BLOCKSIZE;
snprintf(ts, 50, "Protected area: %i<=X<%i, %i<=Y<%i, %i<=Z<%i",
tp.X,tp.X+MAP_BLOCKSIZE,
tp.Y,tp.Y+MAP_BLOCKSIZE,
tp.Z,tp.Z+MAP_BLOCKSIZE);
infotext=narrow_to_wide(ts).c_str();
}
}
//MapNode node = client.getNode(nodepos);
@ -1932,7 +1974,7 @@ void the_game(
}
}
if(canModify && input->getRightClicked())
if(canModifyNeighbour && input->getRightClicked())
{
infostream<<"Ground right-clicked"<<std::endl;
@ -2176,8 +2218,29 @@ void the_game(
}
{
guitext_info->setText(infotext.c_str());
guitext_ownership->setText(ownershiptext.c_str());
if(infotext.length()>0){
guitext_info->setVisible(true);
guitext_info->setText(infotext.c_str());
guitext_info->setDrawBackground( true );
guitext_info->setMaxSize(
core::dimension2du(
guitext_info->getTextWidth(),
guitext_info->getTextHeight()
)
);
}else guitext_info->setVisible(false);
if(ownershiptext.length()>0){
guitext_ownership->setVisible(true);
guitext_ownership->setText(ownershiptext.c_str());
guitext_ownership->setDrawBackground( true );
guitext_ownership->setMaxSize(
core::dimension2du(
guitext_ownership->getTextWidth(),
guitext_ownership->getTextHeight()
)
);
}else guitext_ownership->setVisible(false);
}
/*

View File

@ -901,7 +901,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
/*
*/
void Map::addNodeAndUpdate(v3s16 p, MapNode n,
core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name)
core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name,NodeMetadata *initial_metadata)
{
/*PrintInfo(m_dout);
m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
@ -909,6 +909,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
//j
//one block may have only one border stone
//this check is duplicated at Server::ProcessData, to prevent setting block owner and removing borderstone from inventory - but aborting borderstone placement.
if(n.getContent() == CONTENT_BORDERSTONE)
{
MapBlock * block = getBlockNoCreate(getNodeBlockPos(p));
@ -1030,7 +1031,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
Add intial metadata
*/
NodeMetadata *meta_proto = content_features(n).initial_metadata;
NodeMetadata *meta_proto = initial_metadata ? initial_metadata : content_features(n).initial_metadata;
if(meta_proto)
{
NodeMetadata *meta = meta_proto->clone();

View File

@ -209,7 +209,8 @@ public:
These handle lighting but not faces.
*/
void addNodeAndUpdate(v3s16 p, MapNode n,
core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name);
core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name,
NodeMetadata *initial_metadata=NULL);
void removeNodeAndUpdate(v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks);

View File

@ -42,13 +42,15 @@ Player::Player():
craftresult_is_preview(true),
hp(20),
peer_id(PEER_ID_INEXISTENT),
clanOwner(0),
lastClan(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();
}
@ -848,27 +850,27 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
Check if standing on a teleport
TODO: should it be at the beginning or at the end of this func?
*/
v3s16 standPos = floatToInt(position - v3f(0,BS/2,0), BS);
MapNode standNode = map.getNodeNoEx(standPos);
if(standNode.getContent() == CONTENT_TELEPORT){
SignNodeMetadata* meta = (SignNodeMetadata*)map.getNodeMetadata(standPos);
if(meta){
v3f t;
std::string text = meta->getText();
str_replace_char(text,',',' ');
std::istringstream is(text);
is >> t.X >> t.Y >> t.Z;
//v3s16 standPos = floatToInt(position - v3f(0,BS/2,0), BS);
//MapNode standNode = map.getNodeNoEx(standPos);
//if(standNode.getContent() == CONTENT_TELEPORT){
// SignNodeMetadata* meta = (SignNodeMetadata*)map.getNodeMetadata(standPos);
// if(meta){
// v3f t;
// std::string text = meta->getText();
// str_replace_char(text,',',' ');
// std::istringstream is(text);
// is >> t.X >> t.Y >> t.Z;
//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;
// //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;
setPosition(t*BS);
}
}
// setPosition(t*BS);
// }
//}
}
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)

View File

@ -172,6 +172,8 @@ public:
std::set<u16> clansModerator;
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.
u16 lastClan; //server: remember last clan put into borderstone
inline bool isClanMember(u16 clan) const {
if(clan==0)return false; //do we need this?
return clans.find(clan) != clans.end();

View File

@ -1816,6 +1816,41 @@ void Server::Receive()
}
}
//TODO: move this to some map class?
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;
// check player "foot block"
if(m_env->getMap().getNodeNoEx(where).getContent() == CONTENT_TELEPORT)
meta = (SignNodeMetadata*)m_env->getMap().getNodeMetadata(where);
else {
// check player "head block"
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);
@ -2175,30 +2210,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)
{
@ -2410,8 +2473,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
p_over.Z = readS16(&data[13]);
u16 item_i = readU16(&data[15]);
//j
if( !player->canModify(&m_env.clansManager,&m_env.getMap(),NULL,NULL,&p_under) || !player->canModify(&m_env.clansManager,&m_env.getMap(),NULL,NULL,&p_over) )
//j,placki
bool canModifyOver = player->canModify(&m_env.clansManager,&m_env.getMap(),NULL,NULL,&p_over);
bool canModifyUnder = player->canModify(&m_env.clansManager,&m_env.getMap(),NULL,NULL,&p_under);
static const bool canBoB = g_settings->getBool("build_on_borders");
if( action != 2
&& (
( !canBoB && (!canModifyOver || !canModifyUnder) )
|| ( canBoB && ((action == 1 && !canModifyOver) || (action != 1 && !canModifyUnder)) )
)
)
{
derr_server<<"Player isn't owner of a block"<<std::endl;
RemoteClient *client = getClient(peer_id);
@ -2720,12 +2791,47 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
return;
}
MaterialItem *mitem = (MaterialItem*)item;
NodeMetadata *initial_metadata=NULL;
u16 newowner=0;
// Only allow borderstone if player already belongs to some clan
if(mitem->getMaterial() == CONTENT_BORDERSTONE)
{ if(player->lastClan && player->clans.find(player->lastClan) == player->clans.end())
player->lastClan=0; // was invalid (no longer member?)
if(!player->lastClan)
{ if(player->clanOwner)
player->lastClan=player->clanOwner;
else
if(!player->clans.empty())
player->lastClan=*player->clans.begin();
}
if(!player->lastClan)
{
actionstream<<player->getName()<<" failed to put borderstone"<<std::endl;
try{
SendChatMessage(peer_id,L"Server: You need to join or create a clan to use borderstones.");
}
catch(con::PeerNotFoundException &e)
{}
return;
}
actionstream<<player->getName()<<" will put cornerstone for clan "
<<player->lastClan
<<" ["<<m_env.clansManager.clanNameNoEx(player->lastClan)<<"]"<<std::endl;
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(getNodeBlockPos(p_over));
assert(block != NULL);
if(block->getOwner()) return; //already has owner!
newowner=player->lastClan;
initial_metadata=new SignNodeMetadata("Property of "+m_env.clansManager.clanNameNoEx(player->lastClan));
}
// Reset build time counter
getClient(peer_id)->m_time_from_building = 0.0;
// Create node data
MaterialItem *mitem = (MaterialItem*)item;
MapNode n;
n.setContent(mitem->getMaterial());
@ -2789,7 +2895,22 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
MapEditEventIgnorer ign(&m_ignore_map_edit_events);
std::string p_name = std::string(player->getName());
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name, initial_metadata);
if(initial_metadata) delete initial_metadata;
if(newowner)
{
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(getNodeBlockPos(p_over));
assert(block != NULL);
block->setOwner(newowner);
// force update for all clients
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd()==false; i++)
{
RemoteClient *client = i.getNode()->getValue();
if(client) client->SetBlockNotSent(getNodeBlockPos(p_over));
}
}
}
/*
Set blocks not sent to far players
@ -2995,25 +3116,30 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
u16 clan = (u16)i_clan;*/
bool nullclan = false;
if(clanName == "#" || clanName == "" || clanName == "nobody") nullclan = true;
// bool nullclan = false;
// if(clanName == "#" || clanName == "" || clanName == "nobody") nullclan = true;
u16 clan = 0;
if(!nullclan){
// if(!nullclan){
clan = m_env.clansManager.clanId(clanName);
if(!clan){
derr_server<<"Wrong clan name"<<std::endl;
try{
SendChatMessage(peer_id,L"Server: You are not member of that clan.");
}
catch(con::PeerNotFoundException &e)
{}
return;
}
}
// }
//player must be in this clan or clan is null
if(clan && !player->isClanMember(clan))
return;
block->setOwner(clan);
if(clan) text = "Property of " + clanName;
else text = "Property of nobody";
player->lastClan=clan;
text = "Property of " + m_env.clansManager.clanNameNoEx(clan);
} else if( node.getContent() == CONTENT_TELEPORT ){
//j teleport
@ -4349,6 +4475,10 @@ void Server::SendBlocks(float dtime)
/*
Something random
*/
void Server::KillPlayer(Player *player)
{ // to consider: in creative or if hp is disabled: just respawn, so inventory is not lost
HandlePlayerHP(player,32767);
}
void Server::HandlePlayerHP(Player *player, s16 damage)
{

View File

@ -432,6 +432,7 @@ public:
void BroadcastClanName(u16 clan, const std::string& name); //j
void SendClanDeleted(u16 peer_id,u16 clan); //j
void BroadcastClanDeleted(u16 clan); //j
void KillPlayer(Player *player); //p
//void SendClanSpawn(u16 peer_id,u16 clan, v3f spawn); //j
//void BroadcastClanSpawn(u16 clan, v3f spawn); //j

View File

@ -338,6 +338,12 @@ void cmd_clanNew(std::wostringstream &os,
}
}
void cmd_die(std::wostringstream &os,
ServerCommandContext *ctx)
{
ctx->server->KillPlayer(ctx->player);
}
//j
void cmd_clanDelete(std::wostringstream &os,
ServerCommandContext *ctx)
@ -610,6 +616,8 @@ std::wstring processServerCommand(ServerCommandContext *ctx)
cmd_me(os, ctx);
else if(ctx->parms[0] == L"clearobjects")
cmd_clearobjects(os, ctx);
else if(ctx->parms[0] == L"die")
cmd_die(os, ctx);
else if(ctx->parms[0] == L"clan-new")
cmd_clanNew(os, ctx);
else if(ctx->parms[0] == L"clan-delete")