mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	added PlayerSAO and RemotePlayer, removed ServerRemotePlayer
This commit is contained in:
		@@ -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,8 +2221,19 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type,
 | 
			
		||||
	
 | 
			
		||||
	obj->setId(id);
 | 
			
		||||
 | 
			
		||||
	obj->initialize(init_data);
 | 
			
		||||
	
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
	obj->processMessage(data);
 | 
			
		||||
	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,12 +120,7 @@ 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);
 | 
			
		||||
	inventory.serialize(os);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Player::deSerialize(std::istream &is)
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								src/player.h
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								src/player.h
									
									
									
									
									
								
							@@ -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,17 +121,13 @@ public:
 | 
			
		||||
		return m_name;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual bool isLocal() const = 0;
 | 
			
		||||
	virtual bool isLocal() const
 | 
			
		||||
	{ return false; }
 | 
			
		||||
	virtual PlayerSAO *getPlayerSAO()
 | 
			
		||||
	{ return NULL; }
 | 
			
		||||
	virtual void setPlayerSAO(PlayerSAO *sao)
 | 
			
		||||
	{ assert(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) {}*/
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
		serialize() writes a bunch of text that can contain
 | 
			
		||||
		any characters except a '\0', and such an ending that
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										447
									
								
								src/server.cpp
									
									
									
									
									
								
							
							
						
						
									
										447
									
								
								src/server.cpp
									
									
									
									
									
								
							@@ -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);
 | 
			
		||||
		actionstream<<player->getName()<<" damaged by "
 | 
			
		||||
				<<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
 | 
			
		||||
				<<std::endl;
 | 
			
		||||
 | 
			
		||||
		if(g_settings->getBool("enable_damage"))
 | 
			
		||||
		{
 | 
			
		||||
			actionstream<<player->getName()<<" damaged by "
 | 
			
		||||
					<<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
 | 
			
		||||
					<<std::endl;
 | 
			
		||||
		playersao->setHP(playersao->getHP() - damage);
 | 
			
		||||
 | 
			
		||||
			srp->setHP(srp->getHP() - damage);
 | 
			
		||||
		if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
 | 
			
		||||
			DiePlayer(peer_id);
 | 
			
		||||
 | 
			
		||||
			if(srp->getHP() == 0 && srp->m_hp_not_sent)
 | 
			
		||||
				DiePlayer(srp);
 | 
			
		||||
 | 
			
		||||
			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;
 | 
			
		||||
	
 | 
			
		||||
	srp->setHP(0);
 | 
			
		||||
	
 | 
			
		||||
	// Trigger scripted stuff
 | 
			
		||||
	scriptapi_on_dieplayer(m_lua, srp);
 | 
			
		||||
	
 | 
			
		||||
	// Handle players that are not connected
 | 
			
		||||
	if(player->peer_id == PEER_ID_INEXISTENT){
 | 
			
		||||
		RespawnPlayer(player);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
			<<playersao->getPlayer()->getName()
 | 
			
		||||
			<<" dies"<<std::endl;
 | 
			
		||||
 | 
			
		||||
	SendPlayerHP(player);
 | 
			
		||||
	SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
 | 
			
		||||
	playersao->setHP(0);
 | 
			
		||||
 | 
			
		||||
	// Trigger scripted stuff
 | 
			
		||||
	scriptapi_on_dieplayer(m_lua, playersao);
 | 
			
		||||
 | 
			
		||||
	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,46 +4475,21 @@ 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 != NULL && player->peer_id != 0)
 | 
			
		||||
	{
 | 
			
		||||
		// If player is already connected, cancel
 | 
			
		||||
		if(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;
 | 
			
		||||
		infostream<<"emergePlayer(): Player already connected"<<std::endl;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -4593,43 +4501,43 @@ ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id)
 | 
			
		||||
				" peer_id already exists"<<std::endl;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Create a new player
 | 
			
		||||
		Create a new player if it doesn't exist yet
 | 
			
		||||
	*/
 | 
			
		||||
	if(player == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		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);
 | 
			
		||||
	/*
 | 
			
		||||
		Create a new player active object
 | 
			
		||||
	*/
 | 
			
		||||
	PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id);
 | 
			
		||||
 | 
			
		||||
		/* 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);
 | 
			
		||||
		}
 | 
			
		||||
	/* Add object to environment */
 | 
			
		||||
	m_env->addActiveObject(playersao);
 | 
			
		||||
 | 
			
		||||
		return player;
 | 
			
		||||
		
 | 
			
		||||
	} // create new player
 | 
			
		||||
	/* 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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								src/server.h
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								src/server.h
									
									
									
									
									
								
							@@ -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 ¶ms);
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
	os<< L"-!- Teleported.";
 | 
			
		||||
	// 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
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user