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.
*/
#include "gamedef.h"
#include "player.h"
#include "scriptapi.h"
+#include "genericobject.h"
core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
LuaEntitySAO
*/
-#include "luaentity_common.h"
-
// Prototype (registers item for deserialization)
LuaEntitySAO proto_LuaEntitySAO(NULL, v3f(0,0,0), "_prototype", "");
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),
lua_State *L = m_env->getLua();
scriptapi_luaentity_rm(L, m_id);
}
- delete m_prop;
}
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,
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;
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);
}
}
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();
}
<<" 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);
}
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;
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;
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);
}
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)
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);
}
// 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_),
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),
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()
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();
}
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)
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);
}
}
// 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
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);
}
// 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;
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);
+}
+