aboutsummaryrefslogtreecommitdiff
path: root/src/content_sao.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/content_sao.cpp')
-rw-r--r--src/content_sao.cpp347
1 files changed, 345 insertions, 2 deletions
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 85340981d..d01b023de 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -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);
+}
+