]> git.lizzy.rs Git - minetest.git/blobdiff - src/content_sao.cpp
Switch the license to be LGPLv2/later, with small parts still remaining as GPLv2...
[minetest.git] / src / content_sao.cpp
index d01b023de069fa3b5e38be7847e309ccc50bc7b6..c1a3ded5533437d7c351b2e3c486afb2dfbee1a8 100644 (file)
@@ -3,16 +3,16 @@ 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
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 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.
+GNU Lesser General Public License for more details.
 
-You should have received a copy of the GNU General Public License along
+You should have received a copy of the GNU Lesser 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.
 */
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "gamedef.h"
 #include "player.h"
 #include "scriptapi.h"
+#include "genericobject.h"
 
 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
 
@@ -335,8 +336,6 @@ ServerActiveObject* createItemSAO(ServerEnvironment *env, v3f pos,
        LuaEntitySAO
 */
 
-#include "luaentity_common.h"
-
 // Prototype (registers item for deserialization)
 LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
 
@@ -346,11 +345,11 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos,
        m_init_name(name),
        m_init_state(state),
        m_registered(false),
-       m_prop(new LuaEntityProperties),
        m_hp(-1),
        m_velocity(0,0,0),
        m_acceleration(0,0,0),
        m_yaw(0),
+       m_properties_sent(true),
        m_last_sent_yaw(0),
        m_last_sent_position(0,0,0),
        m_last_sent_velocity(0,0,0),
@@ -375,7 +374,6 @@ LuaEntitySAO::~LuaEntitySAO()
                lua_State *L = m_env->getLua();
                scriptapi_luaentity_rm(L, m_id);
        }
-       delete m_prop;
 }
 
 void LuaEntitySAO::addedToEnvironment()
@@ -388,13 +386,12 @@ void LuaEntitySAO::addedToEnvironment()
        
        if(m_registered){
                // Get properties
-               scriptapi_luaentity_get_properties(L, m_id, m_prop);
+               scriptapi_luaentity_get_properties(L, m_id, &m_prop);
                // Initialize HP from properties
-               m_hp = m_prop->hp_max;
+               m_hp = m_prop.hp_max;
+               // Activate entity, supplying serialized state
+               scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
        }
-       
-       // Activate entity, supplying serialized state
-       scriptapi_luaentity_activate(L, m_id, m_init_state.c_str());
 }
 
 ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
@@ -434,10 +431,19 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos,
 
 void LuaEntitySAO::step(float dtime, bool send_recommended)
 {
+       if(!m_properties_sent)
+       {
+               m_properties_sent = true;
+               std::string str = getPropertyPacket();
+               // create message and add to list
+               ActiveObjectMessage aom(getId(), true, str);
+               m_messages_out.push_back(aom);
+       }
+
        m_last_sent_position_timer += dtime;
        
-       if(m_prop->physical){
-               core::aabbox3d<f32> box = m_prop->collisionbox;
+       if(m_prop.physical){
+               core::aabbox3d<f32> box = m_prop.collisionbox;
                box.MinEdge *= BS;
                box.MaxEdge *= BS;
                collisionMoveResult moveresult;
@@ -483,16 +489,10 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
 
        if(m_armor_groups_sent == false){
                m_armor_groups_sent = true;
-               std::ostringstream os(std::ios::binary);
-               writeU8(os, LUAENTITY_CMD_UPDATE_ARMOR_GROUPS);
-               writeU16(os, m_armor_groups.size());
-               for(ItemGroupList::const_iterator i = m_armor_groups.begin();
-                               i != m_armor_groups.end(); i++){
-                       os<<serializeString(i->first);
-                       writeS16(os, i->second);
-               }
+               std::string str = gob_cmd_update_armor_groups(
+                               m_armor_groups);
                // create message and add to list
-               ActiveObjectMessage aom(getId(), true, os.str());
+               ActiveObjectMessage aom(getId(), true, str);
                m_messages_out.push_back(aom);
        }
 }
@@ -500,18 +500,15 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
 std::string LuaEntitySAO::getClientInitializationData()
 {
        std::ostringstream os(std::ios::binary);
-       // version
-       writeU8(os, 1);
-       // pos
+       writeU8(os, 0); // version
+       os<<serializeString(""); // name
+       writeU8(os, 0); // is_player
        writeV3F1000(os, m_base_position);
-       // yaw
        writeF1000(os, m_yaw);
-       // hp
        writeS16(os, m_hp);
-       // properties
-       std::ostringstream prop_os(std::ios::binary);
-       m_prop->serialize(prop_os);
-       os<<serializeLongString(prop_os.str());
+       writeU8(os, 2); // number of messages stuffed in here
+       os<<serializeLongString(getPropertyPacket()); // message 1
+       os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
        // return result
        return os.str();
 }
@@ -574,15 +571,9 @@ int LuaEntitySAO::punch(v3f dir,
                                <<" hp, health now "<<getHP()<<" hp"<<std::endl;
                
                {
-                       std::ostringstream os(std::ios::binary);
-                       // command 
-                       writeU8(os, LUAENTITY_CMD_PUNCHED);
-                       // damage
-                       writeS16(os, result.damage);
-                       // result_hp
-                       writeS16(os, getHP());
+                       std::string str = gob_cmd_punched(result.damage, getHP());
                        // create message and add to list
-                       ActiveObjectMessage aom(getId(), true, os.str());
+                       ActiveObjectMessage aom(getId(), true, str);
                        m_messages_out.push_back(aom);
                }
 
@@ -605,17 +596,6 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
        scriptapi_luaentity_rightclick(L, m_id, clicker);
 }
 
-void LuaEntitySAO::setHP(s16 hp)
-{
-       if(hp < 0) hp = 0;
-       m_hp = hp;
-}
-
-s16 LuaEntitySAO::getHP() const
-{
-       return m_hp;
-}
-
 void LuaEntitySAO::setPos(v3f pos)
 {
        m_base_position = pos;
@@ -645,6 +625,33 @@ std::string LuaEntitySAO::getDescription()
        return os.str();
 }
 
+void LuaEntitySAO::setHP(s16 hp)
+{
+       if(hp < 0) hp = 0;
+       m_hp = hp;
+}
+
+s16 LuaEntitySAO::getHP() const
+{
+       return m_hp;
+}
+
+void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
+{
+       m_armor_groups = armor_groups;
+       m_armor_groups_sent = false;
+}
+
+ObjectProperties* LuaEntitySAO::accessObjectProperties()
+{
+       return &m_prop;
+}
+
+void LuaEntitySAO::notifyObjectPropertiesModified()
+{
+       m_properties_sent = false;
+}
+
 void LuaEntitySAO::setVelocity(v3f velocity)
 {
        m_velocity = velocity;
@@ -677,29 +684,23 @@ float LuaEntitySAO::getYaw()
 
 void LuaEntitySAO::setTextureMod(const std::string &mod)
 {
-       std::ostringstream os(std::ios::binary);
-       // command 
-       writeU8(os, LUAENTITY_CMD_SET_TEXTURE_MOD);
-       // parameters
-       os<<serializeString(mod);
+       std::string str = gob_cmd_set_texture_mod(mod);
        // create message and add to list
-       ActiveObjectMessage aom(getId(), false, os.str());
+       ActiveObjectMessage aom(getId(), true, str);
        m_messages_out.push_back(aom);
 }
 
 void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
                bool select_horiz_by_yawpitch)
 {
-       std::ostringstream os(std::ios::binary);
-       // command
-       writeU8(os, LUAENTITY_CMD_SET_SPRITE);
-       // parameters
-       writeV2S16(os, p);
-       writeU16(os, num_frames);
-       writeF1000(os, framelength);
-       writeU8(os, select_horiz_by_yawpitch);
+       std::string str = gob_cmd_set_sprite(
+               p,
+               num_frames,
+               framelength,
+               select_horiz_by_yawpitch
+       );
        // create message and add to list
-       ActiveObjectMessage aom(getId(), false, os.str());
+       ActiveObjectMessage aom(getId(), true, str);
        m_messages_out.push_back(aom);
 }
 
@@ -708,10 +709,9 @@ std::string LuaEntitySAO::getName()
        return m_init_name;
 }
 
-void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups)
+std::string LuaEntitySAO::getPropertyPacket()
 {
-       m_armor_groups = armor_groups;
-       m_armor_groups_sent = false;
+       return gob_cmd_set_properties(m_prop);
 }
 
 void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
@@ -726,27 +726,17 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
 
        float update_interval = m_env->getSendRecommendedInterval();
 
-       std::ostringstream os(std::ios::binary);
-       // command
-       writeU8(os, LUAENTITY_CMD_UPDATE_POSITION);
-
-       // do_interpolate
-       writeU8(os, do_interpolate);
-       // pos
-       writeV3F1000(os, m_base_position);
-       // velocity
-       writeV3F1000(os, m_velocity);
-       // acceleration
-       writeV3F1000(os, m_acceleration);
-       // yaw
-       writeF1000(os, m_yaw);
-       // is_end_position (for interpolation)
-       writeU8(os, is_movement_end);
-       // update_interval (for interpolation)
-       writeF1000(os, update_interval);
-
+       std::string str = gob_cmd_update_position(
+               m_base_position,
+               m_velocity,
+               m_acceleration,
+               m_yaw,
+               do_interpolate,
+               is_movement_end,
+               update_interval
+       );
        // create message and add to list
-       ActiveObjectMessage aom(getId(), false, os.str());
+       ActiveObjectMessage aom(getId(), false, str);
        m_messages_out.push_back(aom);
 }
 
@@ -756,7 +746,8 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
 
 // No prototype, PlayerSAO does not need to be deserialized
 
-PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_):
+PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
+               const std::set<std::string> &privs, bool is_singleplayer):
        ServerActiveObject(env_, v3f(0,0,0)),
        m_player(player_),
        m_peer_id(peer_id_),
@@ -766,6 +757,11 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_):
        m_time_from_last_punch(0),
        m_wield_index(0),
        m_position_not_sent(false),
+       m_armor_groups_sent(false),
+       m_properties_sent(true),
+       m_privs(privs),
+       m_is_singleplayer(is_singleplayer),
+       // public
        m_teleported(false),
        m_inventory_not_sent(false),
        m_hp_not_sent(false),
@@ -775,6 +771,21 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_):
        assert(m_peer_id != 0);
        setBasePosition(m_player->getPosition());
        m_inventory = &m_player->inventory;
+       m_armor_groups["choppy"] = 2;
+       m_armor_groups["fleshy"] = 3;
+
+       m_prop.hp_max = PLAYER_MAX_HP;
+       m_prop.physical = false;
+       m_prop.weight = 75;
+       m_prop.collisionbox = core::aabbox3d<f32>(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.);
+       m_prop.visual = "upright_sprite";
+       m_prop.visual_size = v2f(1, 2);
+       m_prop.textures.clear();
+       m_prop.textures.push_back("player.png");
+       m_prop.textures.push_back("player_back.png");
+       m_prop.spritediv = v2s16(1,1);
+       m_prop.is_visible = (getHP() != 0);
+       m_prop.makes_footstep_sound = true;
 }
 
 PlayerSAO::~PlayerSAO()
@@ -824,18 +835,15 @@ bool PlayerSAO::unlimitedTransferDistance() const
 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
+       writeU8(os, 0); // version
+       os<<serializeString(m_player->getName()); // name
+       writeU8(os, 1); // is_player
+       writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0));
        writeF1000(os, m_player->getYaw());
-       // dead
-       writeU8(os, getHP() == 0);
-       // wielded item
-       os<<serializeString(getWieldedItem().getItemString());
+       writeS16(os, getHP());
+       writeU8(os, 2); // number of messages stuffed in here
+       os<<serializeLongString(getPropertyPacket()); // message 1
+       os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2
        return os.str();
 }
 
@@ -847,43 +855,69 @@ std::string PlayerSAO::getStaticData()
 
 void PlayerSAO::step(float dtime, bool send_recommended)
 {
-       m_time_from_last_punch += dtime;
+       if(!m_properties_sent)
+       {
+               m_properties_sent = true;
+               std::string str = getPropertyPacket();
+               // create message and add to list
+               ActiveObjectMessage aom(getId(), true, str);
+               m_messages_out.push_back(aom);
+       }
 
-       /*
-               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();
+       m_time_from_last_punch += dtime;
+       
+       if(m_is_singleplayer)
+       {
+               m_last_good_position = m_player->getPosition();
+               m_last_good_position_age = 0;
+       }
+       else
+       {
+               /*
+                       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 = 0;
+               float player_max_speed_up = 0;
+               if(m_privs.count("fast") != 0){
+                       // Fast speed
+                       player_max_speed = BS * 20;
+                       player_max_speed_up = BS * 20;
                } else {
-                       actionstream<<"Player "<<m_player->getName()
-                                       <<" moved too fast; resetting position"
-                                       <<std::endl;
-                       m_player->setPosition(m_last_good_position);
-                       m_teleported = true;
+                       // Normal speed
+                       player_max_speed = BS * 4.0;
+                       player_max_speed_up = BS * 4.0;
+               }
+               // Tolerance
+               player_max_speed *= 2.5;
+               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;
                }
-               m_last_good_position_age = 0;
        }
 
        if(send_recommended == false)
@@ -892,30 +926,33 @@ void PlayerSAO::step(float dtime, bool send_recommended)
        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());
+               float update_interval = m_env->getSendRecommendedInterval();
+               std::string str = gob_cmd_update_position(
+                       m_player->getPosition() + v3f(0,BS*1,0),
+                       v3f(0,0,0),
+                       v3f(0,0,0),
+                       m_player->getYaw(),
+                       true,
+                       false,
+                       update_interval
+               );
                // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
+               ActiveObjectMessage aom(getId(), false, str);
                m_messages_out.push_back(aom);
        }
 
        if(m_wielded_item_not_sent)
        {
                m_wielded_item_not_sent = false;
+               // GenericCAO has no special way to show this
+       }
 
-               std::ostringstream os(std::ios::binary);
-               // command (3 = wielded item)
-               writeU8(os, 3);
-               // wielded item
-               os<<serializeString(getWieldedItem().getItemString());
+       if(m_armor_groups_sent == false){
+               m_armor_groups_sent = true;
+               std::string str = gob_cmd_update_armor_groups(
+                               m_armor_groups);
                // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
+               ActiveObjectMessage aom(getId(), true, str);
                m_messages_out.push_back(aom);
        }
 }
@@ -956,16 +993,17 @@ int PlayerSAO::punch(v3f dir,
 
        // No effect if PvP disabled
        if(g_settings->getBool("enable_pvp") == false){
-               if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+               if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){
+                       std::string str = gob_cmd_punched(0, getHP());
+                       // create message and add to list
+                       ActiveObjectMessage aom(getId(), true, str);
+                       m_messages_out.push_back(aom);
                        return 0;
+               }
        }
 
-       // "Material" groups of the player
-       ItemGroupList groups;
-       groups["choppy"] = 2;
-       groups["fleshy"] = 3;
-
-       HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch);
+       HitParams hitparams = getHitParams(m_armor_groups, toolcap,
+                       time_from_last_punch);
 
        actionstream<<"Player "<<m_player->getName()<<" punched by "
                        <<puncher->getDescription()<<", damage "<<hitparams.hp
@@ -975,13 +1013,9 @@ int PlayerSAO::punch(v3f dir,
 
        if(hitparams.hp != 0)
        {
-               std::ostringstream os(std::ios::binary);
-               // command (1 = punched)
-               writeU8(os, 1);
-               // damage
-               writeS16(os, hitparams.hp);
+               std::string str = gob_cmd_punched(hitparams.hp, getHP());
                // create message and add to list
-               ActiveObjectMessage aom(getId(), false, os.str());
+               ActiveObjectMessage aom(getId(), true, str);
                m_messages_out.push_back(aom);
        }
 
@@ -1020,17 +1054,31 @@ void PlayerSAO::setHP(s16 hp)
        // 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());
+               // Will send new is_visible value based on (getHP()!=0)
+               m_properties_sent = false;
+               // Send new HP
+               std::string str = gob_cmd_punched(0, getHP());
+               ActiveObjectMessage aom(getId(), true, str);
                m_messages_out.push_back(aom);
        }
 }
 
+void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups)
+{
+       m_armor_groups = armor_groups;
+       m_armor_groups_sent = false;
+}
+
+ObjectProperties* PlayerSAO::accessObjectProperties()
+{
+       return &m_prop;
+}
+
+void PlayerSAO::notifyObjectPropertiesModified()
+{
+       m_properties_sent = false;
+}
+
 Inventory* PlayerSAO::getInventory()
 {
        return m_inventory;
@@ -1092,3 +1140,9 @@ void PlayerSAO::createCreativeInventory()
        scriptapi_get_creative_inventory(m_env->getLua(), this);
 }
 
+std::string PlayerSAO::getPropertyPacket()
+{
+       m_prop.is_visible = (getHP() != 0);
+       return gob_cmd_set_properties(m_prop);
+}
+