added PlayerSAO and RemotePlayer, removed ServerRemotePlayer

This commit is contained in:
Kahrl 2012-03-19 03:04:16 +01:00 committed by Perttu Ahola
parent 072c265c30
commit f8c3743991
20 changed files with 833 additions and 810 deletions

@ -159,7 +159,6 @@ set(common_SRCS
subgame.cpp
inventorymanager.cpp
mods.cpp
serverremoteplayer.cpp
content_abm.cpp
craftdef.cpp
nameidmapping.cpp

@ -1397,45 +1397,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
}
else if(command == TOCLIENT_PLAYERITEM)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u16 count = readU16(is);
for (u16 i = 0; i < count; ++i) {
u16 peer_id = readU16(is);
Player *player = m_env.getPlayer(peer_id);
if (player == NULL)
{
infostream<<"Client: ignoring player item "
<< deSerializeString(is)
<< " for non-existing peer id " << peer_id
<< std::endl;
continue;
} else if (player->isLocal()) {
infostream<<"Client: ignoring player item "
<< deSerializeString(is)
<< " for local player" << std::endl;
continue;
} else {
InventoryList *inv = player->inventory.getList("main");
std::string itemstring(deSerializeString(is));
ItemStack item;
item.deSerialize(itemstring, m_itemdef);
inv->changeItem(0, item);
if(itemstring.empty())
{
infostream<<"Client: empty player item for peer "
<<peer_id<<std::endl;
}
else
{
infostream<<"Client: player item for peer "
<<peer_id<<": "<<itemstring<<std::endl;
}
}
}
infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
}
else if(command == TOCLIENT_DEATHSCREEN)
{

@ -200,7 +200,7 @@ enum ToClientCommand
wstring reason
*/
TOCLIENT_PLAYERITEM = 0x36,
TOCLIENT_PLAYERITEM = 0x36, // Obsolete
/*
u16 command
u16 count of player items

@ -99,9 +99,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Length of cracking animation in count of images
#define CRACK_ANIMATION_LENGTH 5
// Some stuff needed by old code moved to here from heightmap.h
#define GROUNDHEIGHT_NOTFOUND_SETVALUE (-10e6)
#define GROUNDHEIGHT_VALID_MINVALUE ( -9e6)
// Maximum hit points of a player
#define PLAYER_MAX_HP 20
#endif

@ -1011,6 +1011,7 @@ private:
float m_damage_visual_timer;
bool m_dead;
float m_step_distance_counter;
std::string m_wielded_item;
public:
PlayerCAO(IGameDef *gamedef, ClientEnvironment *env):
@ -1024,7 +1025,8 @@ public:
m_local_player(NULL),
m_damage_visual_timer(0),
m_dead(false),
m_step_distance_counter(0)
m_step_distance_counter(0),
m_wielded_item("")
{
if(gamedef == NULL)
ClientActiveObject::registerType(getType(), create);
@ -1048,6 +1050,11 @@ public:
m_yaw = readF1000(is);
// dead
m_dead = readU8(is);
// wielded item
try{
m_wielded_item = deSerializeString(is);
}
catch(SerializationError &e){}
pos_translator.init(m_position);
@ -1263,6 +1270,11 @@ public:
m_dead = readU8(is);
updateVisibility();
}
else if(cmd == 3) // wielded item
{
m_wielded_item = deSerializeString(is);
updateWieldedItem();
}
}
void updateTextures(const std::string &mod)
@ -1288,6 +1300,50 @@ public:
}
}
}
void updateWieldedItem()
{
if(m_is_local_player)
{
// ignoring player item for local player
return;
}
ItemStack item;
try
{
item.deSerialize(m_wielded_item, m_gamedef->idef());
}
catch(SerializationError &e)
{
errorstream<<"PlayerCAO: SerializationError "
"while reading wielded item: "
<<m_wielded_item<<std::endl;
return;
}
// do something with the item, for example:
Player *player = m_env->getPlayer(m_name.c_str());
if(player)
{
InventoryList *inv = player->inventory.getList("main");
assert(inv);
inv->changeItem(0, item);
}
if(item.empty())
{
infostream<<"PlayerCAO: empty player item for player "
<<m_name<<std::endl;
}
else
{
infostream<<"PlayerCAO: player item for player "
<<m_name<<": "
<<item.getItemString()<<std::endl;
}
}
};
// Prototype

@ -26,6 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serialization.h" // For compressZlib
#include "tool.h" // For ToolCapabilities
#include "gamedef.h"
#include "player.h"
#include "scriptapi.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
@ -333,7 +335,6 @@ ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
LuaEntitySAO
*/
#include "scriptapi.h"
#include "luaentity_common.h"
// Prototype (registers item for deserialization)
@ -610,7 +611,7 @@ void LuaEntitySAO::setHP(s16 hp)
m_hp = hp;
}
s16 LuaEntitySAO::getHP()
s16 LuaEntitySAO::getHP() const
{
return m_hp;
}
@ -749,3 +750,345 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
m_messages_out.push_back(aom);
}
/*
PlayerSAO
*/
// No prototype, PlayerSAO does not need to be deserialized
PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_):
ServerActiveObject(env_, v3f(0,0,0)),
m_player(player_),
m_peer_id(peer_id_),
m_inventory(NULL),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
m_time_from_last_punch(0),
m_wield_index(0),
m_position_not_sent(false),
m_teleported(false),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_wielded_item_not_sent(false)
{
assert(m_player);
assert(m_peer_id != 0);
setBasePosition(m_player->getPosition());
m_inventory = &m_player->inventory;
}
PlayerSAO::~PlayerSAO()
{
if(m_inventory != &m_player->inventory)
delete m_inventory;
}
std::string PlayerSAO::getDescription()
{
return std::string("player ") + m_player->getName();
}
// Called after id has been set and has been inserted in environment
void PlayerSAO::addedToEnvironment()
{
ServerActiveObject::addedToEnvironment();
ServerActiveObject::setBasePosition(m_player->getPosition());
m_player->setPlayerSAO(this);
m_player->peer_id = m_peer_id;
m_last_good_position = m_player->getPosition();
m_last_good_position_age = 0.0;
}
// Called before removing from environment
void PlayerSAO::removingFromEnvironment()
{
ServerActiveObject::removingFromEnvironment();
if(m_player->getPlayerSAO() == this)
{
m_player->setPlayerSAO(NULL);
m_player->peer_id = 0;
}
}
bool PlayerSAO::isStaticAllowed() const
{
return false;
}
bool PlayerSAO::unlimitedTransferDistance() const
{
return g_settings->getBool("unlimited_player_transfer_distance");
}
std::string PlayerSAO::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// name
os<<serializeString(m_player->getName());
// pos
writeV3F1000(os, m_player->getPosition());
// yaw
writeF1000(os, m_player->getYaw());
// dead
writeU8(os, getHP() == 0);
// wielded item
os<<serializeString(getWieldedItem().getItemString());
return os.str();
}
std::string PlayerSAO::getStaticData()
{
assert(0);
return "";
}
void PlayerSAO::step(float dtime, bool send_recommended)
{
m_time_from_last_punch += dtime;
/*
Check player movements
NOTE: Actually the server should handle player physics like the
client does and compare player's position to what is calculated
on our side. This is required when eg. players fly due to an
explosion.
*/
//float player_max_speed = BS * 4.0; // Normal speed
float player_max_speed = BS * 20; // Fast speed
float player_max_speed_up = BS * 20;
player_max_speed *= 2.5; // Tolerance
player_max_speed_up *= 2.5;
m_last_good_position_age += dtime;
if(m_last_good_position_age >= 1.0){
float age = m_last_good_position_age;
v3f diff = (m_player->getPosition() - m_last_good_position);
float d_vert = diff.Y;
diff.Y = 0;
float d_horiz = diff.getLength();
/*infostream<<m_player->getName()<<"'s horizontal speed is "
<<(d_horiz/age)<<std::endl;*/
if(d_horiz <= age * player_max_speed &&
(d_vert < 0 || d_vert < age * player_max_speed_up)){
m_last_good_position = m_player->getPosition();
} else {
actionstream<<"Player "<<m_player->getName()
<<" moved too fast; resetting position"
<<std::endl;
m_player->setPosition(m_last_good_position);
m_teleported = true;
}
m_last_good_position_age = 0;
}
if(send_recommended == false)
return;
if(m_position_not_sent)
{
m_position_not_sent = false;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, 0);
// pos
writeV3F1000(os, m_player->getPosition());
// yaw
writeF1000(os, m_player->getYaw());
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
if(m_wielded_item_not_sent)
{
m_wielded_item_not_sent = false;
std::ostringstream os(std::ios::binary);
// command (3 = wielded item)
writeU8(os, 3);
// wielded item
os<<serializeString(getWieldedItem().getItemString());
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
void PlayerSAO::setBasePosition(const v3f &position)
{
ServerActiveObject::setBasePosition(position);
m_position_not_sent = true;
}
void PlayerSAO::setPos(v3f pos)
{
m_player->setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
// Force position change on client
m_teleported = true;
}
void PlayerSAO::moveTo(v3f pos, bool continuous)
{
m_player->setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
// Force position change on client
m_teleported = true;
}
int PlayerSAO::punch(v3f dir,
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
float time_from_last_punch)
{
if(!toolcap)
return 0;
// No effect if PvP disabled
if(g_settings->getBool("enable_pvp") == false){
if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
return 0;
}
// "Material" groups of the player
ItemGroupList groups;
groups["choppy"] = 2;
groups["fleshy"] = 3;
HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch);
actionstream<<"Player "<<m_player->getName()<<" punched by "
<<puncher->getDescription()<<", damage "<<hitparams.hp
<<" HP"<<std::endl;
setHP(getHP() - hitparams.hp);
if(hitparams.hp != 0)
{
std::ostringstream os(std::ios::binary);
// command (1 = punched)
writeU8(os, 1);
// damage
writeS16(os, hitparams.hp);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
return hitparams.wear;
}
void PlayerSAO::rightClick(ServerActiveObject *clicker)
{
}
s16 PlayerSAO::getHP() const
{
return m_player->hp;
}
void PlayerSAO::setHP(s16 hp)
{
s16 oldhp = m_player->hp;
if(hp < 0)
hp = 0;
else if(hp > PLAYER_MAX_HP)
hp = PLAYER_MAX_HP;
if(hp < oldhp && g_settings->getBool("enable_damage") == false)
{
m_hp_not_sent = true; // fix wrong prediction on client
return;
}
m_player->hp = hp;
if(hp != oldhp)
m_hp_not_sent = true;
// On death or reincarnation send an active object message
if((hp == 0) != (oldhp == 0))
{
std::ostringstream os(std::ios::binary);
// command (2 = update death state)
writeU8(os, 2);
// dead?
writeU8(os, hp == 0);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
Inventory* PlayerSAO::getInventory()
{
return m_inventory;
}
const Inventory* PlayerSAO::getInventory() const
{
return m_inventory;
}
InventoryLocation PlayerSAO::getInventoryLocation() const
{
InventoryLocation loc;
loc.setPlayer(m_player->getName());
return loc;
}
void PlayerSAO::setInventoryModified()
{
m_inventory_not_sent = true;
}
std::string PlayerSAO::getWieldList() const
{
return "main";
}
int PlayerSAO::getWieldIndex() const
{
return m_wield_index;
}
void PlayerSAO::setWieldIndex(int i)
{
if(i != m_wield_index)
{
m_wield_index = i;
m_wielded_item_not_sent = true;
}
}
void PlayerSAO::disconnected()
{
m_peer_id = 0;
m_removed = true;
if(m_player->getPlayerSAO() == this)
{
m_player->setPlayerSAO(NULL);
m_player->peer_id = 0;
}
}
void PlayerSAO::createCreativeInventory()
{
if(m_inventory != &m_player->inventory)
delete m_inventory;
m_inventory = new Inventory(m_player->inventory);
m_inventory->clearContents();
scriptapi_get_creative_inventory(m_env->getLua(), this);
}

@ -23,14 +23,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverobject.h"
#include "content_object.h"
#include "itemgroup.h"
#include "player.h"
ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
const std::string itemstring);
/*
LuaEntitySAO
This is the only SAO that needs to have a bunch of it's internals exposed.
LuaEntitySAO needs some internals exposed.
*/
struct LuaEntityProperties;
@ -59,7 +58,7 @@ public:
float getMinimumSavedMovement();
std::string getDescription();
void setHP(s16 hp);
s16 getHP();
s16 getHP() const;
/* LuaEntitySAO-specific */
void setVelocity(v3f velocity);
v3f getVelocity();
@ -94,5 +93,102 @@ private:
bool m_armor_groups_sent;
};
/*
PlayerSAO needs some internals exposed.
*/
class PlayerSAO : public ServerActiveObject
{
public:
PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_);
~PlayerSAO();
u8 getType() const
{return ACTIVEOBJECT_TYPE_PLAYER;}
std::string getDescription();
/*
Active object <-> environment interface
*/
void addedToEnvironment();
void removingFromEnvironment();
bool isStaticAllowed() const;
bool unlimitedTransferDistance() const;
std::string getClientInitializationData();
std::string getStaticData();
void step(float dtime, bool send_recommended);
void setBasePosition(const v3f &position);
void setPos(v3f pos);
void moveTo(v3f pos, bool continuous);
/*
Interaction interface
*/
int punch(v3f dir,
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
float time_from_last_punch);
void rightClick(ServerActiveObject *clicker);
s16 getHP() const;
void setHP(s16 hp);
/*
Inventory interface
*/
Inventory* getInventory();
const Inventory* getInventory() const;
InventoryLocation getInventoryLocation() const;
void setInventoryModified();
std::string getWieldList() const;
int getWieldIndex() const;
void setWieldIndex(int i);
/*
PlayerSAO-specific
*/
void disconnected();
void createCreativeInventory();
Player* getPlayer()
{
return m_player;
}
u16 getPeerID() const
{
return m_peer_id;
}
v3f getLastGoodPosition() const
{
return m_last_good_position;
}
float resetTimeFromLastPunch()
{
float r = m_time_from_last_punch;
m_time_from_last_punch = 0.0;
return r;
}
private:
Player *m_player;
u16 m_peer_id;
Inventory *m_inventory;
v3f m_last_good_position;
float m_last_good_position_age;
float m_time_from_last_punch;
int m_wield_index;
bool m_position_not_sent;
public:
// Some flags used by Server
bool m_teleported;
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_wielded_item_not_sent;
};
#endif

@ -37,7 +37,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "nodemetadata.h"
#include "main.h" // For g_settings, g_profiler
#include "gamedef.h"
#include "serverremoteplayer.h"
#ifndef SERVER
#include "clientmap.h"
#endif
@ -368,7 +367,7 @@ void ServerEnvironment::serializePlayers(const std::string &savedir)
//infostream<<"Checking player file "<<path<<std::endl;
// Load player to see what is its name
ServerRemotePlayer testplayer(this);
RemotePlayer testplayer(m_gamedef);
{
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
@ -482,7 +481,7 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
//infostream<<"Checking player file "<<path<<std::endl;
// Load player to see what is its name
ServerRemotePlayer testplayer(this);
RemotePlayer testplayer(m_gamedef);
{
// Open file and deserialize
std::ifstream is(path.c_str(), std::ios_base::binary);
@ -510,12 +509,10 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
if(player == NULL)
{
//infostream<<"Is a new player"<<std::endl;
player = new ServerRemotePlayer(this);
player = new RemotePlayer(m_gamedef);
newplayer = true;
}
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
// Load player
{
verbosestream<<"Reading player "<<testplayer.getName()<<" from "
@ -527,9 +524,7 @@ void ServerEnvironment::deSerializePlayers(const std::string &savedir)
infostream<<"Failed to read "<<path<<std::endl;
continue;
}
srp->deSerialize(is);
srp->m_last_good_position = srp->getBasePosition();
srp->m_last_good_position_age = 0;
player->deSerialize(is);
}
if(newplayer)
@ -2074,7 +2069,7 @@ void ClientEnvironment::step(float dtime)
catch(InvalidPositionException &e){
light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
}
player->updateLight(light);
player->light = light;
}
/*
@ -2226,7 +2221,18 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
obj->setId(id);
try
{
obj->initialize(init_data);
}
catch(SerializationError &e)
{
errorstream<<"ClientEnvironment::addActiveObject():"
<<" id="<<id<<" type="<<type
<<": SerializationError in initialize(),"
<<" init_data="<<serializeJsonString(init_data)
<<std::endl;
}
addActiveObject(obj);
}
@ -2258,7 +2264,18 @@ void ClientEnvironment::processActiveObjectMessage(u16 id,
<<std::endl;
return;
}
try
{
obj->processMessage(data);
}
catch(SerializationError &e)
{
errorstream<<"ClientEnvironment::processActiveObjectMessage():"
<<" id="<<id<<" type="<<obj->getType()
<<" SerializationError in processMessage(),"
<<" message="<<serializeJsonString(data)
<<std::endl;
}
}
/*

@ -795,6 +795,18 @@ void Inventory::clear()
m_lists.clear();
}
void Inventory::clearContents()
{
for(u32 i=0; i<m_lists.size(); i++)
{
InventoryList *list = m_lists[i];
for(u32 j=0; j<list->getSize(); j++)
{
list->deleteItem(j);
}
}
}
Inventory::Inventory(IItemDefManager *itemdef)
{
m_itemdef = itemdef;

@ -250,6 +250,7 @@ public:
~Inventory();
void clear();
void clearContents();
Inventory(IItemDefManager *itemdef);
Inventory(const Inventory &other);

@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "environment.h"
#include "gamedef.h"
#include "event.h"
#include "content_sao.h"
Player::Player(IGameDef *gamedef):
touching_ground(false),
@ -40,8 +41,7 @@ Player::Player(IGameDef *gamedef):
is_climbing(false),
swimming_up(false),
inventory(gamedef->idef()),
inventory_backup(NULL),
hp(20),
hp(PLAYER_MAX_HP),
peer_id(PEER_ID_INEXISTENT),
// protected
m_gamedef(gamedef),
@ -51,16 +51,6 @@ Player::Player(IGameDef *gamedef):
m_position(0,0,0)
{
updateName("<not set>");
resetInventory();
}
Player::~Player()
{
delete inventory_backup;
}
void Player::resetInventory()
{
inventory.clear();
inventory.addList("main", PLAYER_INVENTORY_SIZE);
inventory.addList("craft", 9);
@ -68,6 +58,10 @@ void Player::resetInventory()
inventory.addList("craftresult", 1);
}
Player::~Player()
{
}
// Y direction is ignored
void Player::accelerate(v3f target_speed, f32 max_increase)
{
@ -126,11 +120,6 @@ void Player::serialize(std::ostream &os)
os<<"PlayerArgsEnd\n";
// If actual inventory is backed up due to creative mode, save it
// instead of the dummy creative mode inventory
if(inventory_backup)
inventory_backup->serialize(os);
else
inventory.serialize(os);
}
@ -779,3 +768,13 @@ v3s16 LocalPlayer::getStandingNodePos()
#endif
/*
RemotePlayer
*/
void RemotePlayer::setPosition(const v3f &position)
{
Player::setPosition(position);
if(m_sao)
m_sao->setBasePosition(position);
}

@ -31,18 +31,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Map;
class IGameDef;
struct CollisionInfo;
class PlayerSAO;
class Player
{
public:
Player(IGameDef *gamedef);
virtual ~Player();
virtual ~Player() = 0;
void resetInventory();
//void move(f32 dtime, Map &map);
virtual void move(f32 dtime, Map &map, f32 pos_max_d) = 0;
virtual void move(f32 dtime, Map &map, f32 pos_max_d)
{}
v3f getSpeed()
{
@ -112,7 +111,7 @@ public:
return (m_yaw + 90.) * core::DEGTORAD;
}
virtual void updateName(const char *name)
void updateName(const char *name)
{
snprintf(m_name, PLAYERNAME_SIZE, "%s", name);
}
@ -122,16 +121,12 @@ public:
return m_name;
}
virtual bool isLocal() const = 0;
virtual void updateLight(u8 light_at_pos)
{
light = light_at_pos;
}
// NOTE: Use peer_id == 0 for disconnected
/*virtual bool isClientConnected() { return false; }
virtual void setClientConnected(bool) {}*/
virtual bool isLocal() const
{ return false; }
virtual PlayerSAO *getPlayerSAO()
{ return NULL; }
virtual void setPlayerSAO(PlayerSAO *sao)
{ assert(0); }
/*
serialize() writes a bunch of text that can contain
@ -151,9 +146,8 @@ public:
u8 light;
// In creative mode, this is the invisible backup inventory
Inventory inventory;
// Actual inventory is backed up here when creative mode is used
Inventory *inventory_backup;
u16 hp;
@ -167,9 +161,6 @@ protected:
f32 m_yaw;
v3f m_speed;
v3f m_position;
public:
};
#ifndef SERVER
@ -249,5 +240,24 @@ private:
};
#endif // !SERVER
/*
Player on the server
*/
class RemotePlayer : public Player
{
public:
RemotePlayer(IGameDef *gamedef): Player(gamedef), m_sao(0) {}
virtual ~RemotePlayer() {}
PlayerSAO *getPlayerSAO()
{ return m_sao; }
void setPlayerSAO(PlayerSAO *sao)
{ m_sao = sao; }
void setPosition(const v3f &position);
private:
PlayerSAO *m_sao;
};
#endif

@ -35,7 +35,7 @@ extern "C" {
#include "script.h"
//#include "luna.h"
#include "luaentity_common.h"
#include "content_sao.h" // For LuaEntitySAO
#include "content_sao.h" // For LuaEntitySAO and PlayerSAO
#include "itemdef.h"
#include "nodedef.h"
#include "craftdef.h"
@ -1095,7 +1095,6 @@ static ItemStack read_item(lua_State *L, int index);
static void inventory_set_list_from_lua(Inventory *inv, const char *name,
lua_State *L, int tableindex, int forcesize=-1)
{
dstream<<"inventory_set_list_from_lua\n";
if(tableindex < 0)
tableindex = lua_gettop(L) + 1 + tableindex;
// If nil, delete list
@ -1127,7 +1126,6 @@ static void inventory_set_list_from_lua(Inventory *inv, const char *name,
invlist->deleteItem(index);
index++;
}
dstream<<"inventory_set_list_from_lua done\n";
}
static void inventory_get_list_to_lua(Inventory *inv, const char *name,
@ -2259,14 +2257,22 @@ private:
return (LuaEntitySAO*)obj;
}
static ServerRemotePlayer* getplayer(ObjectRef *ref)
static PlayerSAO* getplayersao(ObjectRef *ref)
{
ServerActiveObject *obj = getobject(ref);
if(obj == NULL)
return NULL;
if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
return NULL;
return static_cast<ServerRemotePlayer*>(obj);
return (PlayerSAO*)obj;
}
static Player* getplayer(ObjectRef *ref)
{
PlayerSAO *playersao = getplayersao(ref);
if(playersao == NULL)
return NULL;
return playersao->getPlayer();
}
// Exported functions
@ -2319,10 +2325,6 @@ private:
v3f pos = checkFloatPos(L, 2);
// Do it
co->setPos(pos);
// Move player if applicable
ServerRemotePlayer *player = getplayer(ref);
if(player != NULL)
get_server(L)->SendMovePlayer(player);
return 0;
}
@ -2626,7 +2628,7 @@ private:
static int l_get_player_name(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerRemotePlayer *player = getplayer(ref);
Player *player = getplayer(ref);
if(player == NULL){
lua_pushnil(L);
return 1;
@ -2640,7 +2642,7 @@ private:
static int l_get_look_dir(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerRemotePlayer *player = getplayer(ref);
Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
float pitch = player->getRadPitch();
@ -2654,7 +2656,7 @@ private:
static int l_get_look_pitch(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerRemotePlayer *player = getplayer(ref);
Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadPitch());
@ -2665,7 +2667,7 @@ private:
static int l_get_look_yaw(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
ServerRemotePlayer *player = getplayer(ref);
Player *player = getplayer(ref);
if(player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadYaw());
@ -2996,14 +2998,18 @@ private:
if(env == NULL) return 0;
// Do it
const char *name = luaL_checkstring(L, 2);
ServerRemotePlayer *player =
static_cast<ServerRemotePlayer*>(env->getPlayer(name));
Player *player = env->getPlayer(name);
if(player == NULL){
lua_pushnil(L);
return 1;
}
PlayerSAO *sao = player->getPlayerSAO();
if(sao == NULL){
lua_pushnil(L);
return 1;
}
// Put player on stack
objectref_get_or_create(L, player);
objectref_get_or_create(L, sao);
return 1;
}
@ -4211,8 +4217,6 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
dstream<<"player: "<<player<<" id: "<<player->getId()<<std::endl;
bool positioning_handled_by_some = false;
// Get minetest.registered_on_respawnplayers
@ -4238,13 +4242,15 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player)
return positioning_handled_by_some;
}
void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player)
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
{
Inventory *inv = player->getInventory();
assert(inv);
lua_getglobal(L, "minetest");
lua_getfield(L, -1, "creative_inventory");
luaL_checktype(L, -1, LUA_TTABLE);
inventory_set_list_from_lua(&player->inventory, "main", L, -1,
PLAYER_INVENTORY_SIZE);
inventory_set_list_from_lua(inv, "main", L, -1, PLAYER_INVENTORY_SIZE);
}
/*

@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Server;
class ServerEnvironment;
class ServerActiveObject;
class ServerRemotePlayer;
typedef struct lua_State lua_State;
struct LuaEntityProperties;
struct ItemStack;
@ -58,7 +57,7 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player);
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player);
/* item callbacks */
bool scriptapi_item_on_drop(lua_State *L, ItemStack &item,

@ -30,8 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "config.h"
#include "servercommand.h"
#include "filesys.h"
#include "content_mapnode.h"
#include "content_nodemeta.h"
#include "mapblock.h"
#include "serverobject.h"
#include "settings.h"
@ -43,7 +41,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemdef.h"
#include "craftdef.h"
#include "mapgen.h"
#include "content_mapnode.h"
#include "content_nodemeta.h"
#include "content_abm.h"
#include "content_sao.h"
#include "mods.h"
#include "sha1.h"
#include "base64.h"
@ -379,6 +380,27 @@ void * EmergeThread::Thread()
return NULL;
}
v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
{
if(pos_exists) *pos_exists = false;
switch(type){
case SSP_LOCAL:
return v3f(0,0,0);
case SSP_POSITIONAL:
if(pos_exists) *pos_exists = true;
return pos;
case SSP_OBJECT: {
if(object == 0)
return v3f(0,0,0);
ServerActiveObject *sao = env->getActiveObject(object);
if(!sao)
return v3f(0,0,0);
if(pos_exists) *pos_exists = true;
return sao->getBasePosition(); }
}
return v3f(0,0,0);
}
void RemoteClient::GetNextBlocks(Server *server, float dtime,
core::array<PrioritySortedBlockTransfer> &dest)
{
@ -1250,8 +1272,6 @@ void Server::AsyncRunStep()
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
//Player *player = m_env->getPlayer(client->peer_id);
SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
// Send as reliable
@ -1291,78 +1311,36 @@ void Server::AsyncRunStep()
ScopeProfiler sp(g_profiler, "Server: handle players");
//float player_max_speed = BS * 4.0; // Normal speed
float player_max_speed = BS * 20; // Fast speed
float player_max_speed_up = BS * 20;
player_max_speed *= 2.5; // Tolerance
player_max_speed_up *= 2.5;
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
RemoteClient *client = i.getNode()->getValue();
ServerRemotePlayer *player =
static_cast<ServerRemotePlayer*>
(m_env->getPlayer(client->peer_id));
if(player==NULL)
PlayerSAO *playersao = getPlayerSAO(client->peer_id);
if(playersao == NULL){
errorstream<<"Handling client without PlayerSAO, peer_id="<<client->peer_id<<std::endl;
continue;
/*
Check player movements
NOTE: Actually the server should handle player physics like the
client does and compare player's position to what is calculated
on our side. This is required when eg. players fly due to an
explosion.
*/
player->m_last_good_position_age += dtime;
if(player->m_last_good_position_age >= 1.0){
float age = player->m_last_good_position_age;
v3f diff = (player->getPosition() - player->m_last_good_position);
float d_vert = diff.Y;
diff.Y = 0;
float d_horiz = diff.getLength();
/*infostream<<player->getName()<<"'s horizontal speed is "
<<(d_horiz/age)<<std::endl;*/
if(d_horiz <= age * player_max_speed &&
(d_vert < 0 || d_vert < age * player_max_speed_up)){
player->m_last_good_position = player->getPosition();
} else {
actionstream<<"Player "<<player->getName()
<<" moved too fast; resetting position"
<<std::endl;
player->setPosition(player->m_last_good_position);
SendMovePlayer(player);
}
player->m_last_good_position_age = 0;
}
/*
Handle player HPs (die if hp=0)
*/
if(player->hp == 0 && player->m_hp_not_sent)
DiePlayer(player);
if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
DiePlayer(client->peer_id);
/*
Send player inventories and HPs if necessary
*/
if(player->m_inventory_not_sent){
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
if(playersao->m_teleported){
SendMovePlayer(client->peer_id);
playersao->m_teleported = false;
}
if(player->m_hp_not_sent){
SendPlayerHP(player);
if(playersao->m_inventory_not_sent){
UpdateCrafting(client->peer_id);
SendInventory(client->peer_id);
}
/*
Add to environment
*/
if(!player->m_is_in_environment){
player->m_removed = false;
player->setId(0);
m_env->addActiveObject(player);
if(playersao->m_hp_not_sent){
SendPlayerHP(client->peer_id);
}
}
}
@ -2167,10 +2145,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
// Get player
ServerRemotePlayer *player = emergePlayer(playername, peer_id);
PlayerSAO *playersao = emergePlayer(playername, peer_id);
// If failed, cancel
if(player == NULL)
if(playersao == NULL)
{
errorstream<<"Server: peer_id="<<peer_id
<<": failed to emerge player"<<std::endl;
@ -2184,7 +2162,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
SharedBuffer<u8> reply(2+1+6+8);
writeU16(&reply[0], TOCLIENT_INIT);
writeU8(&reply[2], deployed);
writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
// Send as reliable
@ -2194,7 +2172,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
/*
Send complete position information
*/
SendMovePlayer(player);
SendMovePlayer(peer_id);
return;
}
@ -2231,17 +2209,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
UpdateCrafting(peer_id);
SendInventory(peer_id);
// Send player items to all players
SendPlayerItems();
Player *player = m_env->getPlayer(peer_id);
// Send HP
SendPlayerHP(player);
SendPlayerHP(peer_id);
// Show death screen if necessary
if(player->hp == 0)
SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
// Send time of day
{
@ -2314,14 +2289,21 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
Player *player = m_env->getPlayer(peer_id);
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
if(player == NULL){
infostream<<"Server::ProcessData(): Cancelling: "
"No player for peer_id="<<peer_id
<<std::endl;
return;
}
PlayerSAO *playersao = player->getPlayerSAO();
if(playersao == NULL){
infostream<<"Server::ProcessData(): Cancelling: "
"No player object for peer_id="<<peer_id
<<std::endl;
return;
}
if(command == TOSERVER_PLAYERPOS)
{
if(datasize < 2+12+12+4+4)
@ -2644,7 +2626,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
// Do the action
a->apply(this, srp, this);
a->apply(this, playersao, this);
// Eat the action
delete a;
}
@ -2775,27 +2757,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
std::istringstream is(datastring, std::ios_base::binary);
u8 damage = readU8(is);
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
if(g_settings->getBool("enable_damage"))
{
actionstream<<player->getName()<<" damaged by "
<<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
<<std::endl;
srp->setHP(srp->getHP() - damage);
playersao->setHP(playersao->getHP() - damage);
if(srp->getHP() == 0 && srp->m_hp_not_sent)
DiePlayer(srp);
if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
DiePlayer(peer_id);
if(srp->m_hp_not_sent)
SendPlayerHP(player);
}
else
{
// Force send (to correct the client's predicted HP)
SendPlayerHP(player);
}
if(playersao->m_hp_not_sent)
SendPlayerHP(peer_id);
}
else if(command == TOSERVER_PASSWORD)
{
@ -2865,15 +2837,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
return;
u16 item = readU16(&data[2]);
srp->setWieldIndex(item);
SendWieldedItem(srp);
playersao->setWieldIndex(item);
}
else if(command == TOSERVER_RESPAWN)
{
if(player->hp != 0)
return;
RespawnPlayer(player);
RespawnPlayer(peer_id);
actionstream<<player->getName()<<" respawns at "
<<PP(player->getPosition()/BS)<<std::endl;
@ -2934,19 +2905,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if(player->hp == 0)
{
verbosestream<<"TOSERVER_INTERACT: "<<srp->getName()
verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
<<" tried to interact, but is dead!"<<std::endl;
return;
}
v3f player_pos = srp->m_last_good_position;
v3f player_pos = playersao->getLastGoodPosition();
// Update wielded item
if(srp->getWieldIndex() != item_i)
{
srp->setWieldIndex(item_i);
SendWieldedItem(srp);
}
playersao->setWieldIndex(item_i);
// Get pointed to node (undefined if not POINTEDTYPE_NODE)
v3s16 p_under = pointed.node_undersurface;
@ -3038,7 +3005,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
}
if(n.getContent() != CONTENT_IGNORE)
scriptapi_node_on_punch(m_lua, p_under, n, srp);
scriptapi_node_on_punch(m_lua, p_under, n, playersao);
}
else if(pointed.type == POINTEDTHING_OBJECT)
{
@ -3050,15 +3017,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<pointed.object_id<<": "
<<pointed_object->getDescription()<<std::endl;
ItemStack punchitem = srp->getWieldedItem();
ItemStack punchitem = playersao->getWieldedItem();
ToolCapabilities toolcap =
punchitem.getToolCapabilities(m_itemdef);
v3f dir = (pointed_object->getBasePosition() -
(srp->getPosition() + srp->getEyeOffset())
(player->getPosition() + player->getEyeOffset())
).normalize();
pointed_object->punch(dir, &toolcap, srp,
srp->m_time_from_last_punch);
srp->m_time_from_last_punch = 0;
float time_from_last_punch =
playersao->resetTimeFromLastPunch();
pointed_object->punch(dir, &toolcap, playersao,
time_from_last_punch);
}
} // action == 0
@ -3092,7 +3060,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
}
if(n.getContent() != CONTENT_IGNORE)
scriptapi_node_on_dig(m_lua, p_under, n, srp);
scriptapi_node_on_dig(m_lua, p_under, n, playersao);
}
} // action == 2
@ -3101,7 +3069,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
else if(action == 3)
{
ItemStack item = srp->getWieldedItem();
ItemStack item = playersao->getWieldedItem();
// Reset build time counter
if(pointed.type == POINTEDTHING_NODE &&
@ -3121,16 +3089,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
<<pointed_object->getDescription()<<std::endl;
// Do stuff
pointed_object->rightClick(srp);
pointed_object->rightClick(playersao);
}
else if(scriptapi_item_on_place(m_lua,
item, srp, pointed))
item, playersao, pointed))
{
// Placement was handled in lua
// Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
srp->setWieldedItem(item);
playersao->setWieldedItem(item);
}
} // action == 3
@ -3140,17 +3108,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
*/
else if(action == 4)
{
ItemStack item = srp->getWieldedItem();
ItemStack item = playersao->getWieldedItem();
actionstream<<player->getName()<<" uses "<<item.name
<<", pointing at "<<pointed.dump()<<std::endl;
if(scriptapi_item_on_use(m_lua,
item, srp, pointed))
item, playersao, pointed))
{
// Apply returned ItemStack
if(g_settings->getBool("creative_mode") == false)
srp->setWieldedItem(item);
playersao->setWieldedItem(item);
}
} // action == 4
@ -3222,7 +3190,10 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
Player *player = m_env->getPlayer(loc.name.c_str());
if(!player)
return NULL;
return &player->inventory;
PlayerSAO *playersao = player->getPlayerSAO();
if(!playersao)
return NULL;
return playersao->getInventory();
}
break;
case InventoryLocation::NODEMETA:
@ -3273,11 +3244,14 @@ void Server::setInventoryModified(const InventoryLocation &loc)
break;
case InventoryLocation::PLAYER:
{
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
(m_env->getPlayer(loc.name.c_str()));
if(!srp)
Player *player = m_env->getPlayer(loc.name.c_str());
if(!player)
return;
srp->m_inventory_not_sent = true;
PlayerSAO *playersao = player->getPlayerSAO();
if(!playersao)
return;
playersao->m_inventory_not_sent = true;
playersao->m_wielded_item_not_sent = true;
}
break;
case InventoryLocation::NODEMETA:
@ -3482,20 +3456,17 @@ void Server::SendInventory(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
ServerRemotePlayer* player =
static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
assert(player);
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
player->m_inventory_not_sent = false;
playersao->m_inventory_not_sent = false;
/*
Serialize it
*/
std::ostringstream os;
//os.imbue(std::locale("C"));
player->inventory.serialize(os);
playersao->getInventory()->serialize(os);
std::string s = os.str();
@ -3507,52 +3478,6 @@ void Server::SendInventory(u16 peer_id)
m_con.Send(peer_id, 0, data, true);
}
void Server::SendWieldedItem(const ServerRemotePlayer* srp)
{
DSTACK(__FUNCTION_NAME);
assert(srp);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_PLAYERITEM);
writeU16(os, 1);
writeU16(os, srp->peer_id);
os<<serializeString(srp->getWieldedItem().getItemString());
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
m_con.SendToAll(0, data, true);
}
void Server::SendPlayerItems()
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
core::list<Player *> players = m_env->getPlayers(true);
writeU16(os, TOCLIENT_PLAYERITEM);
writeU16(os, players.size());
core::list<Player *>::Iterator i;
for(i = players.begin(); i != players.end(); ++i)
{
Player *p = *i;
ServerRemotePlayer *srp =
static_cast<ServerRemotePlayer*>(p);
writeU16(os, p->peer_id);
os<<serializeString(srp->getWieldedItem().getItemString());
}
// Make data buffer
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
m_con.SendToAll(0, data, true);
}
void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
{
DSTACK(__FUNCTION_NAME);
@ -3599,17 +3524,22 @@ void Server::BroadcastChatMessage(const std::wstring &message)
}
}
void Server::SendPlayerHP(Player *player)
{
SendHP(m_con, player->peer_id, player->hp);
static_cast<ServerRemotePlayer*>(player)->m_hp_not_sent = false;
}
void Server::SendMovePlayer(Player *player)
void Server::SendPlayerHP(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
std::ostringstream os(std::ios_base::binary);
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
playersao->m_hp_not_sent = false;
SendHP(m_con, peer_id, playersao->getHP());
}
void Server::SendMovePlayer(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);
Player *player = m_env->getPlayer(peer_id);
assert(player);
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_MOVE_PLAYER);
writeV3F1000(os, player->getPosition());
writeF1000(os, player->getPitch());
@ -3630,7 +3560,7 @@ void Server::SendMovePlayer(Player *player)
std::string s = os.str();
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
// Send as reliable
m_con.Send(player->peer_id, 0, data, true);
m_con.Send(peer_id, 0, data, true);
}
s32 Server::playSound(const SimpleSoundSpec &spec,
@ -4242,41 +4172,44 @@ void Server::sendRequestedMedia(u16 peer_id,
Something random
*/
void Server::DiePlayer(Player *player)
void Server::DiePlayer(u16 peer_id)
{
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
DSTACK(__FUNCTION_NAME);
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
infostream<<"Server::DiePlayer(): Player "
<<player->getName()<<" dies"<<std::endl;
<<playersao->getPlayer()->getName()
<<" dies"<<std::endl;
srp->setHP(0);
playersao->setHP(0);
// Trigger scripted stuff
scriptapi_on_dieplayer(m_lua, srp);
scriptapi_on_dieplayer(m_lua, playersao);
// Handle players that are not connected
if(player->peer_id == PEER_ID_INEXISTENT){
RespawnPlayer(player);
return;
}
SendPlayerHP(player);
SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
SendPlayerHP(peer_id);
SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
}
void Server::RespawnPlayer(Player *player)
void Server::RespawnPlayer(u16 peer_id)
{
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
srp->setHP(20);
bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
DSTACK(__FUNCTION_NAME);
PlayerSAO *playersao = getPlayerSAO(peer_id);
assert(playersao);
infostream<<"Server::RespawnPlayer(): Player "
<<playersao->getPlayer()->getName()
<<" respawns"<<std::endl;
playersao->setHP(PLAYER_MAX_HP);
bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
if(!repositioned){
v3f pos = findSpawnPos(m_env->getServerMap());
player->setPosition(pos);
srp->m_last_good_position = pos;
srp->m_last_good_position_age = 0;
playersao->setPos(pos);
}
SendMovePlayer(player);
SendPlayerHP(player);
}
void Server::UpdateCrafting(u16 peer_id)
@ -4542,48 +4475,23 @@ v3f findSpawnPos(ServerMap &map)
return intToFloat(nodepos, BS);
}
ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
{
RemotePlayer *player = NULL;
bool newplayer = false;
/*
Try to get an existing player
*/
ServerRemotePlayer *player =
static_cast<ServerRemotePlayer*>(m_env->getPlayer(name));
if(player != NULL)
{
player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
// If player is already connected, cancel
if(player->peer_id != 0)
if(player != NULL && player->peer_id != 0)
{
infostream<<"emergePlayer(): Player already connected"<<std::endl;
return NULL;
}
// Got one.
player->peer_id = peer_id;
// Re-add player to environment
if(player->m_removed)
{
player->m_removed = false;
player->setId(0);
m_env->addActiveObject(player);
}
// Reset inventory to creative if in creative mode
if(g_settings->getBool("creative_mode"))
{
// Warning: double code below
// Backup actual inventory
player->inventory_backup = new Inventory(m_itemdef);
*(player->inventory_backup) = player->inventory;
// Set creative inventory
player->resetInventory();
scriptapi_get_creative_inventory(m_lua, player);
}
return player;
}
/*
If player with the wanted peer_id already exists, cancel.
*/
@ -4595,41 +4503,41 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
}
/*
Create a new player
Create a new player if it doesn't exist yet
*/
if(player == NULL)
{
/* Set player position */
newplayer = true;
player = new RemotePlayer(this);
player->updateName(name);
/* Set player position */
infostream<<"Server: Finding spawn place for player \""
<<name<<"\""<<std::endl;
v3f pos = findSpawnPos(m_env->getServerMap());
player = new ServerRemotePlayer(m_env, pos, peer_id, name);
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
player->setPosition(pos);
/* Add player to environment */
m_env->addPlayer(player);
m_env->addActiveObject(srp);
/* Run scripts */
scriptapi_on_newplayer(m_lua, srp);
/* Add stuff to inventory */
if(g_settings->getBool("creative_mode"))
{
// Warning: double code above
// Backup actual inventory
player->inventory_backup = new Inventory(m_itemdef);
*(player->inventory_backup) = player->inventory;
// Set creative inventory
player->resetInventory();
scriptapi_get_creative_inventory(m_lua, player);
}
return player;
/*
Create a new player active object
*/
PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id);
} // create new player
/* Add object to environment */
m_env->addActiveObject(playersao);
/* Run scripts */
if(newplayer)
scriptapi_on_newplayer(m_lua, playersao);
/* Creative mode */
if(g_settings->getBool("creative_mode"))
playersao->createCreativeInventory();
return playersao;
}
void Server::handlePeerChange(PeerChange &c)
@ -4699,8 +4607,7 @@ void Server::handlePeerChange(PeerChange &c)
i++;
}
ServerRemotePlayer* player =
static_cast<ServerRemotePlayer*>(m_env->getPlayer(c.peer_id));
Player *player = m_env->getPlayer(c.peer_id);
// Collect information about leaving in chat
std::wstring message;
@ -4717,12 +4624,8 @@ void Server::handlePeerChange(PeerChange &c)
}
// Remove from environment
if(player != NULL)
player->m_removed = true;
// Set player client disconnected
if(player != NULL)
player->peer_id = 0;
if(player->getPlayerSAO())
player->getPlayerSAO()->disconnected();
/*
Print out action

@ -31,7 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "ban.h"
#include "gamedef.h"
#include "serialization.h" // For SER_FMT_VER_INVALID
#include "serverremoteplayer.h"
#include "mods.h"
#include "inventorymanager.h"
#include "subgame.h"
@ -42,6 +41,7 @@ class IWritableItemDefManager;
class IWritableNodeDefManager;
class IWritableCraftDefManager;
class EventManager;
class PlayerSAO;
class ServerError : public std::exception
{
@ -299,26 +299,7 @@ struct ServerSoundParams
loop(false)
{}
v3f getPos(ServerEnvironment *env, bool *pos_exists) const
{
if(pos_exists) *pos_exists = false;
switch(type){
case SSP_LOCAL:
return v3f(0,0,0);
case SSP_POSITIONAL:
if(pos_exists) *pos_exists = true;
return pos;
case SSP_OBJECT: {
if(object == 0)
return v3f(0,0,0);
ServerActiveObject *sao = env->getActiveObject(object);
if(!sao)
return v3f(0,0,0);
if(pos_exists) *pos_exists = true;
return sao->getBasePosition(); }
}
return v3f(0,0,0);
}
v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
};
struct ServerPlayingSound
@ -514,9 +495,6 @@ public:
m_shutdown_requested = true;
}
// Envlock and conlock should be locked when calling this
void SendMovePlayer(Player *player);
// Returns -1 if failed, sound handle on success
// Envlock + conlock
s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params);
@ -620,14 +598,11 @@ private:
*/
// Envlock and conlock should be locked when calling these
void SendMovePlayer(u16 peer_id);
void SendInventory(u16 peer_id);
// send wielded item info about player to all
void SendWieldedItem(const ServerRemotePlayer *srp);
// send wielded item info about all players to all players
void SendPlayerItems();
void SendChatMessage(u16 peer_id, const std::wstring &message);
void BroadcastChatMessage(const std::wstring &message);
void SendPlayerHP(Player *player);
void SendPlayerHP(u16 peer_id);
/*
Send a node removal/addition event to all clients except ignore_id.
Additionally, if far_players!=NULL, players further away than
@ -655,8 +630,8 @@ private:
Something random
*/
void DiePlayer(Player *player);
void RespawnPlayer(Player *player);
void DiePlayer(u16 peer_id);
void RespawnPlayer(u16 peer_id);
void UpdateCrafting(u16 peer_id);
@ -672,6 +647,15 @@ private:
return player->getName();
}
// When called, environment mutex should be locked
PlayerSAO* getPlayerSAO(u16 peer_id)
{
Player *player = m_env->getPlayer(peer_id);
if(player == NULL)
return NULL;
return player->getPlayerSAO();
}
/*
Get a player from memory or creates one.
If player is already connected, return NULL
@ -679,7 +663,7 @@ private:
Call with env and con locked.
*/
ServerRemotePlayer *emergePlayer(const char *name, u16 peer_id);
PlayerSAO *emergePlayer(const char *name, u16 peer_id);
// Locks environment and connection by its own
struct PeerChange;

@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "utility.h"
#include "settings.h"
#include "main.h" // For g_settings
#include "content_sao.h"
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@ -216,20 +217,26 @@ void cmd_teleport(std::wostringstream &os,
return;
}
v3f dest(stoi(coords[0])*10, stoi(coords[1])*10, stoi(coords[2])*10);
v3f dest(stoi(coords[0])*BS, stoi(coords[1])*BS, stoi(coords[2])*BS);
actionstream<<ctx->player->getName()<<" teleports from "
<<PP(ctx->player->getPosition()/BS)<<" to "
<<PP(dest/BS)<<std::endl;
//ctx->player->setPosition(dest);
// Use the ServerActiveObject interface of ServerRemotePlayer
ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(ctx->player);
srp->setPos(dest);
ctx->server->SendMovePlayer(ctx->player);
// Use the ServerActiveObject interface of RemotePlayer
// This forces a position change on the client
ServerActiveObject *sao = ctx->player->getPlayerSAO();
if(sao)
{
sao->setPos(dest);
os<< L"-!- Teleported.";
}
else
{
errorstream<<"Teleport failed, player object not found!"
<<std::endl;
os<< L"-!- Teleport failed.";
}
}
void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx)

@ -143,7 +143,7 @@ public:
{}
virtual void setHP(s16 hp)
{}
virtual s16 getHP()
virtual s16 getHP() const
{ return 0; }
// Inventory and wielded item

@ -1,265 +0,0 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "serverremoteplayer.h"
#include "main.h" // For g_settings
#include "settings.h"
#include "log.h"
#include "gamedef.h"
#include "inventory.h"
#include "environment.h"
#include "tool.h"
ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env):
Player(env->getGameDef()),
ServerActiveObject(env, v3f(0,0,0)),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
m_wield_index(0),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_is_in_environment(false),
m_time_from_last_punch(0),
m_position_not_sent(false)
{
}
ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
const char *name_):
Player(env->getGameDef()),
ServerActiveObject(env, pos_),
m_last_good_position(0,0,0),
m_last_good_position_age(0),
m_wield_index(0),
m_inventory_not_sent(false),
m_hp_not_sent(false),
m_is_in_environment(false),
m_time_from_last_punch(0),
m_position_not_sent(false)
{
setPosition(pos_);
peer_id = peer_id_;
updateName(name_);
}
ServerRemotePlayer::~ServerRemotePlayer()
{
}
void ServerRemotePlayer::setPosition(const v3f &position)
{
Player::setPosition(position);
ServerActiveObject::setBasePosition(position);
m_position_not_sent = true;
}
Inventory* ServerRemotePlayer::getInventory()
{
return &inventory;
}
const Inventory* ServerRemotePlayer::getInventory() const
{
return &inventory;
}
InventoryLocation ServerRemotePlayer::getInventoryLocation() const
{
InventoryLocation loc;
loc.setPlayer(getName());
return loc;
}
void ServerRemotePlayer::setInventoryModified()
{
m_inventory_not_sent = true;
}
std::string ServerRemotePlayer::getWieldList() const
{
return "main";
}
int ServerRemotePlayer::getWieldIndex() const
{
return m_wield_index;
}
void ServerRemotePlayer::setWieldIndex(int i)
{
m_wield_index = i;
}
/* ServerActiveObject interface */
void ServerRemotePlayer::addedToEnvironment()
{
assert(!m_is_in_environment);
m_is_in_environment = true;
}
void ServerRemotePlayer::removingFromEnvironment()
{
assert(m_is_in_environment);
m_is_in_environment = false;
}
bool ServerRemotePlayer::unlimitedTransferDistance() const
{
return g_settings->getBool("unlimited_player_transfer_distance");
}
void ServerRemotePlayer::step(float dtime, bool send_recommended)
{
m_time_from_last_punch += dtime;
if(send_recommended == false)
return;
if(m_position_not_sent)
{
m_position_not_sent = false;
std::ostringstream os(std::ios::binary);
// command (0 = update position)
writeU8(os, 0);
// pos
writeV3F1000(os, getPosition());
// yaw
writeF1000(os, getYaw());
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
std::string ServerRemotePlayer::getClientInitializationData()
{
std::ostringstream os(std::ios::binary);
// version
writeU8(os, 0);
// name
os<<serializeString(getName());
// pos
writeV3F1000(os, getPosition());
// yaw
writeF1000(os, getYaw());
// dead
writeU8(os, getHP() == 0);
return os.str();
}
std::string ServerRemotePlayer::getStaticData()
{
assert(0);
return "";
}
int ServerRemotePlayer::punch(v3f dir,
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
float time_from_last_punch)
{
if(!toolcap)
return 0;
// No effect if PvP disabled
if(g_settings->getBool("enable_pvp") == false){
if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
return 0;
}
// "Material" groups of the player
ItemGroupList groups;
groups["choppy"] = 2;
groups["fleshy"] = 3;
HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch);
actionstream<<"Player "<<getName()<<" punched by "
<<puncher->getDescription()<<", damage "<<hitparams.hp
<<" HP"<<std::endl;
setHP(getHP() - hitparams.hp);
if(hitparams.hp != 0)
{
std::ostringstream os(std::ios::binary);
// command (1 = punched)
writeU8(os, 1);
// damage
writeS16(os, hitparams.hp);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
return hitparams.wear;
}
void ServerRemotePlayer::rightClick(ServerActiveObject *clicker)
{
}
void ServerRemotePlayer::setPos(v3f pos)
{
setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
}
void ServerRemotePlayer::moveTo(v3f pos, bool continuous)
{
setPosition(pos);
// Movement caused by this command is always valid
m_last_good_position = pos;
m_last_good_position_age = 0;
}
void ServerRemotePlayer::setHP(s16 hp_)
{
s16 oldhp = hp;
// FIXME: don't hardcode maximum HP, make configurable per object
if(hp_ < 0)
hp_ = 0;
else if(hp_ > 20)
hp_ = 20;
hp = hp_;
if(hp != oldhp)
m_hp_not_sent = true;
// On death or reincarnation send an active object message
if((hp == 0) != (oldhp == 0))
{
std::ostringstream os(std::ios::binary);
// command (2 = update death state)
writeU8(os, 2);
// dead?
writeU8(os, hp == 0);
// create message and add to list
ActiveObjectMessage aom(getId(), false, os.str());
m_messages_out.push_back(aom);
}
}
s16 ServerRemotePlayer::getHP()
{
return hp;
}

@ -1,105 +0,0 @@
/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef SERVERREMOTEPLAYER_HEADER
#define SERVERREMOTEPLAYER_HEADER
#include "player.h"
#include "serverobject.h"
#include "content_object.h" // Object type IDs
/*
Player on the server
*/
class ServerRemotePlayer : public Player, public ServerActiveObject
{
public:
ServerRemotePlayer(ServerEnvironment *env);
ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_,
const char *name_);
virtual ~ServerRemotePlayer();
virtual bool isLocal() const
{ return false; }
virtual void move(f32 dtime, Map &map, f32 pos_max_d)
{
}
virtual void setPosition(const v3f &position);
/* ServerActiveObject interface */
u8 getType() const
{return ACTIVEOBJECT_TYPE_PLAYER;}
// Called after id has been set and has been inserted in environment
void addedToEnvironment();
// Called before removing from environment
void removingFromEnvironment();
bool environmentDeletes() const
{ return false; }
virtual bool unlimitedTransferDistance() const;
bool isStaticAllowed() const
{ return false; }
void step(float dtime, bool send_recommended);
std::string getClientInitializationData();
std::string getStaticData();
int punch(v3f dir,
const ToolCapabilities *toolcap,
ServerActiveObject *puncher,
float time_from_last_punch);
void rightClick(ServerActiveObject *clicker);
void setPos(v3f pos);
void moveTo(v3f pos, bool continuous);
virtual std::string getDescription()
{return std::string("player ")+getName();}
virtual Inventory* getInventory();
virtual const Inventory* getInventory() const;
virtual InventoryLocation getInventoryLocation() const;
virtual void setInventoryModified();
virtual std::string getWieldList() const;
virtual int getWieldIndex() const;
virtual void setWieldIndex(int i);
virtual void setHP(s16 hp_);
virtual s16 getHP();
v3f m_last_good_position;
float m_last_good_position_age;
int m_wield_index;
bool m_inventory_not_sent;
bool m_hp_not_sent;
bool m_is_in_environment;
// Incremented by step(), read and reset by Server
float m_time_from_last_punch;
private:
bool m_position_not_sent;
};
#endif