Esempio n. 1
0
int PlayerSAO::punch(v3f dir,
	const ToolCapabilities *toolcap,
	ServerActiveObject *puncher,
	float time_from_last_punch)
{
	// It's best that attachments cannot be punched
	if (isAttached())
		return 0;

	if (!toolcap)
		return 0;

	// No effect if PvP disabled
	if (g_settings->getBool("enable_pvp") == false) {
		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(aom);
			return 0;
		}
	}

	HitParams hitparams = getHitParams(m_armor_groups, toolcap,
			time_from_last_punch);

	std::string punchername = "nil";

	if (puncher != 0)
		punchername = puncher->getDescription();

	PlayerSAO *playersao = m_player->getPlayerSAO();

	bool damage_handled = m_env->getScriptIface()->on_punchplayer(playersao,
				puncher, time_from_last_punch, toolcap, dir,
				hitparams.hp);

	if (!damage_handled) {
		setHP(getHP() - hitparams.hp);
	} else { // override client prediction
		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(aom);
		}
	}


	actionstream << "Player " << m_player->getName() << " punched by "
			<< punchername;
	if (!damage_handled) {
		actionstream << ", damage " << hitparams.hp << " HP";
	} else {
		actionstream << ", damage handled by lua";
	}
	actionstream << std::endl;

	return hitparams.wear;
}
Esempio n. 2
0
	void step(float dtime, bool send_recommended)
	{
		ScopeProfiler sp2(g_profiler, "step avg", SPT_AVG);

		assert(m_env);

		const float interval = 0.2;
		if(m_move_interval.step(dtime, interval)==false)
			return;
		dtime = interval;
		
		core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
		collisionMoveResult moveresult;
		// Apply gravity
		m_speed_f += v3f(0, -dtime*9.81*BS, 0);
		// Maximum movement without glitches
		f32 pos_max_d = BS*0.25;
		// Limit speed
		if(m_speed_f.getLength()*dtime > pos_max_d)
			m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
		v3f pos_f = getBasePosition();
		v3f pos_f_old = pos_f;
		v3f accel_f = v3f(0,0,0);
		f32 stepheight = 0;
		IGameDef *gamedef = m_env->getGameDef();
		moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
				pos_max_d, box, stepheight, dtime,
				pos_f, m_speed_f, accel_f);
		
		if(send_recommended == false)
			return;

		if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
		{
			setBasePosition(pos_f);
			m_last_sent_position = pos_f;

			std::ostringstream os(std::ios::binary);
			// command (0 = update position)
			writeU8(os, 0);
			// pos
			writeV3F1000(os, m_base_position);
			// create message and add to list
			ActiveObjectMessage aom(getId(), false, os.str());
			m_messages_out.push_back(aom);
		}
		if(m_itemstring_changed)
		{
			m_itemstring_changed = false;

			std::ostringstream os(std::ios::binary);
			// command (1 = update itemstring)
			writeU8(os, 1);
			// itemstring
			os<<serializeString(m_itemstring);
			// create message and add to list
			ActiveObjectMessage aom(getId(), false, os.str());
			m_messages_out.push_back(aom);
		}
	}
Esempio n. 3
0
	void step(float dtime, bool send_recommended)
	{
		m_age += dtime;
		if(m_age > 10)
		{
			m_removed = true;
			return;
		}

		m_base_position.Y += dtime * BS * 2;
		if(m_base_position.Y > 8*BS)
			m_base_position.Y = 2*BS;

		if(send_recommended == false)
			return;

		m_timer1 -= dtime;
		if(m_timer1 < 0.0)
		{
			m_timer1 += 0.125;

			std::string data;

			data += itos(0); // 0 = position
			data += " ";
			data += itos(m_base_position.X);
			data += " ";
			data += itos(m_base_position.Y);
			data += " ";
			data += itos(m_base_position.Z);

			ActiveObjectMessage aom(getId(), false, data);
			m_messages_out.push(aom);
		}
	}
Esempio n. 4
0
void Oerkki1SAO::doDamage(u16 d)
{
	infostream<<"oerkki damage: "<<d<<std::endl;
	
	if(d < m_hp)
	{
		m_hp -= d;
	}
	else
	{
		// Die
		m_hp = 0;
		m_removed = true;
	}

	{
		std::ostringstream os(std::ios::binary);
		// command (1 = damage)
		writeU8(os, 1);
		// amount
		writeU8(os, d);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, os.str());
		m_messages_out.push_back(aom);
	}
}
Esempio n. 5
0
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
{
	m_last_sent_move_precision = m_base_position.getDistanceFrom(
			m_last_sent_position);
	m_last_sent_position_timer = 0;
	m_last_sent_yaw = m_yaw;
	m_last_sent_position = m_base_position;
	m_last_sent_velocity = m_velocity;
	//m_last_sent_acceleration = m_acceleration;

	float update_interval = m_env->getSendRecommendedInterval();

	std::ostringstream os(std::ios::binary);
	// command (0 = update position)
	writeU8(os, 0);

	// 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);

	// create message and add to list
	ActiveObjectMessage aom(getId(), false, os.str());
	m_messages_out.push_back(aom);
}
Esempio n. 6
0
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))
	{
		// 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);
	}
}
Esempio n. 7
0
void MobV2SAO::doDamage(u16 d)
{
	infostream<<"MobV2 hp="<<m_hp<<" damage="<<d<<std::endl;
	
	if(d < m_hp)
	{
		m_hp -= d;
	}
	else
	{
		actionstream<<"A "<<(isPeaceful()?"peaceful":"non-peaceful")
				<<" mob id="<<m_id<<" dies at "<<PP(m_base_position)<<std::endl;
		// Die
		m_hp = 0;
		m_removed = true;
	}

	{
		std::ostringstream os(std::ios::binary);
		// command (1 = damage)
		writeU8(os, 1);
		// amount
		writeU16(os, d);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, os.str());
		m_messages_out.push_back(aom);
	}
}
Esempio n. 8
0
void LuaEntitySAO::setTextureMod(const std::string &mod)
{
	std::string str = gob_cmd_set_texture_mod(mod);
	// create message and add to list
	ActiveObjectMessage aom(getId(), true, str);
	m_messages_out.push(aom);
}
Esempio n. 9
0
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
{
	m_last_sent_move_precision = m_base_position.getDistanceFrom(
			m_last_sent_position);
	m_last_sent_position_timer = 0;
	m_last_sent_yaw = m_yaw;
	m_last_sent_position = m_base_position;
	m_last_sent_velocity = m_velocity;
	//m_last_sent_acceleration = m_acceleration;

	float update_interval = m_env->getSendRecommendedInterval();

	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, str);
	m_messages_out.push_back(aom);
}
Esempio n. 10
0
void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end)
{
	// If the object is attached client-side, don't waste bandwidth sending its position to clients
	if(isAttached())
		return;

	m_last_sent_move_precision = m_base_position.getDistanceFrom(
			m_last_sent_position);
	m_last_sent_position_timer = 0;
	m_last_sent_yaw = m_yaw;
	m_last_sent_position = m_base_position;
	m_last_sent_velocity = m_velocity;
	//m_last_sent_acceleration = m_acceleration;

	float update_interval = m_env->getSendRecommendedInterval();

	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, str);
	m_messages_out.push(aom);
}
Esempio n. 11
0
int PlayerSAO::punch(v3f dir,
	const ToolCapabilities *toolcap,
	ServerActiveObject *puncher,
	float time_from_last_punch)
{
	// It's best that attachments cannot be punched 
	if(isAttached())
		return 0;

	if(!toolcap)
		return 0;

	// No effect if PvP disabled
	if(g_settings->getBool("enable_pvp") == false){
		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;
		}
	}

	HitParams hitparams = getHitParams(m_armor_groups, toolcap,
			time_from_last_punch);

	std::string punchername = "nil";

	if ( puncher != 0 )
		punchername = puncher->getDescription();

	actionstream<<"Player "<<m_player->getName()<<" punched by "
			<<punchername<<", damage "<<hitparams.hp
			<<" HP"<<std::endl;

	setHP(getHP() - hitparams.hp);

	if(hitparams.hp != 0)
	{
		std::string str = gob_cmd_punched(hitparams.hp, getHP());
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push_back(aom);
	}

	return hitparams.wear;
}
Esempio n. 12
0
int LuaEntitySAO::punch(v3f dir,
		const ToolCapabilities *toolcap,
		ServerActiveObject *puncher,
		float time_from_last_punch)
{
	if(!m_registered){
		// Delete unknown LuaEntities when punched
		m_removed = true;
		return 0;
	}

	// It's best that attachments cannot be punched 
	if(isAttached())
		return 0;
	
	ItemStack *punchitem = NULL;
	ItemStack punchitem_static;
	if(puncher){
		punchitem_static = puncher->getWieldedItem();
		punchitem = &punchitem_static;
	}

	PunchDamageResult result = getPunchDamage(
			m_armor_groups,
			toolcap,
			punchitem,
			time_from_last_punch);
	
	if(result.did_punch)
	{
		setHP(getHP() - result.damage);
		

		std::string punchername = "nil";

		if ( puncher != 0 )
			punchername = puncher->getDescription();

		actionstream<<getDescription()<<" punched by "
				<<punchername<<", damage "<<result.damage
				<<" hp, health now "<<getHP()<<" hp"<<std::endl;
		
		{
			std::string str = gob_cmd_punched(result.damage, getHP());
			// create message and add to list
			ActiveObjectMessage aom(getId(), true, str);
			m_messages_out.push_back(aom);
		}

		if(getHP() == 0)
			m_removed = true;
	}

	ENV_TO_SA(m_env)->luaentity_Punch(m_id, puncher,
			time_from_last_punch, toolcap, dir);

	return result.wear;
}
Esempio n. 13
0
int LuaEntitySAO::punch(v3f dir,
		const ToolCapabilities *toolcap,
		ServerActiveObject *puncher,
		float time_from_last_punch)
{
	if (!m_registered) {
		// Delete unknown LuaEntities when punched
		m_pending_removal = true;
		return 0;
	}

	ItemStack *punchitem = NULL;
	ItemStack punchitem_static;
	if (puncher) {
		punchitem_static = puncher->getWieldedItem();
		punchitem = &punchitem_static;
	}

	PunchDamageResult result = getPunchDamage(
			m_armor_groups,
			toolcap,
			punchitem,
			time_from_last_punch);

	bool damage_handled = m_env->getScriptIface()->luaentity_Punch(m_id, puncher,
			time_from_last_punch, toolcap, dir, result.did_punch ? result.damage : 0);

	if (!damage_handled) {
		if (result.did_punch) {
			setHP(getHP() - result.damage,
				PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));

			if (result.damage > 0) {
				std::string punchername = puncher ? puncher->getDescription() : "nil";

				actionstream << getDescription() << " punched by "
						<< punchername << ", damage " << result.damage
						<< " hp, health now " << getHP() << " hp" << std::endl;
			}

			std::string str = gob_cmd_punched(result.damage, getHP());
			// create message and add to list
			ActiveObjectMessage aom(getId(), true, str);
			m_messages_out.push(aom);
		}
	}

	if (getHP() == 0 && !isGone()) {
		m_pending_removal = true;
		clearParentAttachment();
		clearChildAttachments();
		m_env->getScriptIface()->luaentity_on_death(m_id, puncher);
	}

	return result.wear;
}
Esempio n. 14
0
void LuaEntitySAO::setTextureMod(const std::string &mod)
{
	std::ostringstream os(std::ios::binary);
	// command (1 = set texture modification)
	writeU8(os, 1);
	// parameters
	os<<serializeString(mod);
	// create message and add to list
	ActiveObjectMessage aom(getId(), false, os.str());
	m_messages_out.push_back(aom);
}
Esempio n. 15
0
void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
		bool 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(), true, str);
	m_messages_out.push(aom);
}
Esempio n. 16
0
void ItemSAO::step(float dtime, bool send_recommended)
{
	ScopeProfiler sp2(g_profiler, "ItemSAO::step avg", SPT_AVG);

	assert(m_env);

	const float interval = 0.2;
	if(m_move_interval.step(dtime, interval)==false)
		return;
	dtime = interval;
	
	core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
	collisionMoveResult moveresult;
	// Apply gravity
	m_speed_f += v3f(0, -dtime*9.81*BS, 0);
	// Maximum movement without glitches
	f32 pos_max_d = BS*0.25;
	// Limit speed
	if(m_speed_f.getLength()*dtime > pos_max_d)
		m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
	v3f pos_f = getBasePosition();
	v3f pos_f_old = pos_f;
	IGameDef *gamedef = m_env->getGameDef();
	moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
			pos_max_d, box, dtime, pos_f, m_speed_f);
	
	if(send_recommended == false)
		return;

	if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
	{
		setBasePosition(pos_f);
		m_last_sent_position = pos_f;

		std::ostringstream os(std::ios::binary);
		char buf[6];
		// command (0 = update position)
		buf[0] = 0;
		os.write(buf, 1);
		// pos
		writeS32((u8*)buf, m_base_position.X*1000);
		os.write(buf, 4);
		writeS32((u8*)buf, m_base_position.Y*1000);
		os.write(buf, 4);
		writeS32((u8*)buf, m_base_position.Z*1000);
		os.write(buf, 4);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, os.str());
		m_messages_out.push_back(aom);
	}
}
void Server::SendPlayerHP(u16 peer_id)
{
	DSTACK(FUNCTION_NAME);
	PlayerSAO *playersao = getPlayerSAO(peer_id);
	if (!playersao)
		return;
	SendHP(peer_id, playersao->getHP());
	m_script->player_event(playersao,"health_changed");

	// Send to other clients
	std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
	ActiveObjectMessage aom(playersao->getId(), true, str);
	playersao->m_messages_out.push(aom);
}
Esempio n. 18
0
void MobV2SAO::sendPosition()
{
	m_last_sent_position = m_base_position;

	std::ostringstream os(std::ios::binary);
	// command (0 = update position)
	writeU8(os, 0);
	// pos
	writeV3F1000(os, m_base_position);
	// yaw
	writeF1000(os, m_yaw);
	// create message and add to list
	ActiveObjectMessage aom(getId(), false, os.str());
	m_messages_out.push_back(aom);
}
Esempio n. 19
0
void LuaEntitySAO::setSprite(v2s16 p, int num_frames, float framelength,
		bool select_horiz_by_yawpitch)
{
	std::ostringstream os(std::ios::binary);
	// command (2 = set sprite)
	writeU8(os, 2);
	// parameters
	writeV2S16(os, p);
	writeU16(os, num_frames);
	writeF1000(os, framelength);
	writeU8(os, select_horiz_by_yawpitch);
	// create message and add to list
	ActiveObjectMessage aom(getId(), false, os.str());
	m_messages_out.push_back(aom);
}
Esempio n. 20
0
void PlayerSAO::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(aom);
	}

	// If attached, check that our parent is still there. If it isn't, detach.
	if(m_attachment_parent_id && !isAttached())
	{
		m_attachment_parent_id = 0;
		m_attachment_bone = "";
		m_attachment_position = v3f(0,0,0);
		m_attachment_rotation = v3f(0,0,0);
		m_player->setPosition(m_last_good_position);
		((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id);
	}

	//dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;

	// Set lag pool maximums based on estimated lag
	const float LAG_POOL_MIN = 5.0;
	float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
	if(lag_pool_max < LAG_POOL_MIN)
		lag_pool_max = LAG_POOL_MIN;
	m_dig_pool.setMax(lag_pool_max);
	m_move_pool.setMax(lag_pool_max);

	// Increment cheat prevention timers
	m_dig_pool.add(dtime);
	m_move_pool.add(dtime);
	m_time_from_last_punch += dtime;
	m_nocheat_dig_time += dtime;

	// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
	// If the object gets detached this comes into effect automatically from the last known origin
	if(isAttached())
	{
		v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		m_last_good_position = pos;
		m_player->setPosition(pos);
	}

	if(send_recommended == false)
		return;

	// If the object is attached client-side, don't waste bandwidth sending its position to clients
	if(m_position_not_sent && !isAttached())
	{
		m_position_not_sent = false;
		float update_interval = m_env->getSendRecommendedInterval();
		v3f pos;
		if(isAttached()) // Just in case we ever do send attachment position too
			pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		else
			pos = m_player->getPosition() + v3f(0,BS*1,0);
		std::string str = gob_cmd_update_position(
			pos,
			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, str);
		m_messages_out.push(aom);
	}

	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(), true, str);
		m_messages_out.push(aom);
	}

	if(m_physics_override_sent == false){
		m_physics_override_sent = true;
		std::string str = gob_cmd_update_physics_override(m_physics_override_speed,
				m_physics_override_jump, m_physics_override_gravity,
				m_physics_override_sneak, m_physics_override_sneak_glitch);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if(m_animation_sent == false){
		m_animation_sent = true;
		std::string str = gob_cmd_update_animation(
			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if(m_bone_position_sent == false){
		m_bone_position_sent = true;
		for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
			std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
			// create message and add to list
			ActiveObjectMessage aom(getId(), true, str);
			m_messages_out.push(aom);
		}
	}

	if(m_attachment_sent == false){
		m_attachment_sent = true;
		std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if (m_nametag_sent == false) {
		m_nametag_sent = true;
		std::string str = gob_cmd_update_nametag_attributes(m_nametag_color);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}
}
Esempio n. 21
0
void PlayerSAO::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_time_from_last_punch += dtime;
	m_nocheat_dig_time += dtime;
	
	if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
	{
		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. Altough a node-based alternative might be possible
			too, and much more lightweight.
		*/

		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 {
			// 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;
		}
	}

	if(send_recommended == false)
		return;

	if(m_position_not_sent)
	{
		m_position_not_sent = false;
		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, 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
	}

	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(), true, str);
		m_messages_out.push_back(aom);
	}
}
Esempio n. 22
0
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;
		box.MinEdge *= BS;
		box.MaxEdge *= BS;
		collisionMoveResult moveresult;
		f32 pos_max_d = BS*0.25; // Distance per iteration
		f32 stepheight = 0; // Maximum climbable step height
		v3f p_pos = m_base_position;
		v3f p_velocity = m_velocity;
		v3f p_acceleration = m_acceleration;
		IGameDef *gamedef = m_env->getGameDef();
		moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
				pos_max_d, box, stepheight, dtime,
				p_pos, p_velocity, p_acceleration);
		// Apply results
		m_base_position = p_pos;
		m_velocity = p_velocity;
		m_acceleration = p_acceleration;
	} else {
		m_base_position += dtime * m_velocity + 0.5 * dtime
				* dtime * m_acceleration;
		m_velocity += dtime * m_acceleration;
	}

	if(m_registered){
		lua_State *L = m_env->getLua();
		scriptapi_luaentity_step(L, m_id, dtime);
	}

	if(send_recommended == false)
		return;
	
	// TODO: force send when acceleration changes enough?
	float minchange = 0.2*BS;
	if(m_last_sent_position_timer > 1.0){
		minchange = 0.01*BS;
	} else if(m_last_sent_position_timer > 0.2){
		minchange = 0.05*BS;
	}
	float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
	move_d += m_last_sent_move_precision;
	float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
	if(move_d > minchange || vel_d > minchange ||
			fabs(m_yaw - m_last_sent_yaw) > 1.0){
		sendPosition(true, false);
	}

	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(), true, str);
		m_messages_out.push_back(aom);
	}
}
Esempio n. 23
0
void MobV2SAO::step(float dtime, bool send_recommended)
{
	ScopeProfiler sp2(g_profiler, "MobV2SAO::step avg", SPT_AVG);

	assert(m_env);
	Map *map = &m_env->getMap();

	m_age += dtime;

	if(m_die_age >= 0.0 && m_age >= m_die_age){
		m_removed = true;
		return;
	}

	m_random_disturb_timer += dtime;
	if(m_random_disturb_timer >= 5.0)
	{
		m_random_disturb_timer = 0;
		// Check connected players
		core::list<Player*> players = m_env->getPlayers(true);
		core::list<Player*>::Iterator i;
		for(i = players.begin();
				i != players.end(); i++)
		{
			Player *player = *i;
			v3f playerpos = player->getPosition();
			f32 dist = m_base_position.getDistanceFrom(playerpos);
			if(dist < BS*16)
			{
				if(myrand_range(0,3) == 0){
					actionstream<<"Mob id="<<m_id<<" at "
							<<PP(m_base_position/BS)
							<<" got randomly disturbed by "
							<<player->getName()<<std::endl;
					m_disturbing_player = player->getName();
					m_disturb_timer = 0;
					break;
				}
			}
		}
	}

	Player *disturbing_player =
			m_env->getPlayer(m_disturbing_player.c_str());
	v3f disturbing_player_off = v3f(0,1,0);
	v3f disturbing_player_norm = v3f(0,1,0);
	float disturbing_player_distance = 1000000;
	float disturbing_player_dir = 0;
	if(disturbing_player){
		disturbing_player_off =
				disturbing_player->getPosition() - m_base_position;
		disturbing_player_distance = disturbing_player_off.getLength();
		disturbing_player_norm = disturbing_player_off;
		disturbing_player_norm.normalize();
		disturbing_player_dir = 180./PI*atan2(disturbing_player_norm.Z,
				disturbing_player_norm.X);
	}

	m_disturb_timer += dtime;
	
	if(!m_falling)
	{
		m_shooting_timer -= dtime;
		if(m_shooting_timer <= 0.0 && m_shooting){
			m_shooting = false;
			
			std::string shoot_type = m_properties->get("shoot_type");
			v3f shoot_pos(0,0,0);
			shoot_pos.Y += m_properties->getFloat("shoot_y") * BS;
			if(shoot_type == "fireball"){
				v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
				dir.Y = m_shoot_y;
				dir.normalize();
				v3f speed = dir * BS * 10.0;
				v3f pos = m_base_position + shoot_pos;
				infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
						<<" shooting fireball from "<<PP(pos)
						<<" at speed "<<PP(speed)<<std::endl;
				Settings properties;
				properties.set("looks", "fireball");
				properties.setV3F("speed", speed);
				properties.setFloat("die_age", 5.0);
				properties.set("move_type", "constant_speed");
				properties.setFloat("hp", 1000);
				properties.set("lock_full_brightness", "true");
				properties.set("player_hit_damage", "9");
				properties.set("player_hit_distance", "2");
				properties.set("player_hit_interval", "1");
				ServerActiveObject *obj = new MobV2SAO(m_env,
						pos, &properties);
				//m_env->addActiveObjectAsStatic(obj);
				m_env->addActiveObject(obj);
			} else {
				infostream<<__FUNCTION_NAME<<": Mob id="<<m_id
						<<": Unknown shoot_type="<<shoot_type
						<<std::endl;
			}
		}

		m_shoot_reload_timer += dtime;

		float reload_time = 15.0;
		if(m_disturb_timer <= 15.0)
			reload_time = 3.0;

		bool shoot_without_player = false;
		if(m_properties->getBool("mindless_rage"))
			shoot_without_player = true;

		if(!m_shooting && m_shoot_reload_timer >= reload_time &&
				!m_next_pos_exists &&
				(m_disturb_timer <= 60.0 || shoot_without_player))
		{
			m_shoot_y = 0;
			if(m_disturb_timer < 60.0 && disturbing_player &&
					disturbing_player_distance < 16*BS &&
					fabs(disturbing_player_norm.Y) < 0.8){
				m_yaw = disturbing_player_dir;
				sendPosition();
				m_shoot_y += disturbing_player_norm.Y;
			} else {
				m_shoot_y = 0.01 * myrand_range(-30,10);
			}
			m_shoot_reload_timer = 0.0;
			m_shooting = true;
			m_shooting_timer = 1.5;
			{
				std::ostringstream os(std::ios::binary);
				// command (2 = shooting)
				writeU8(os, 2);
				// time
				writeF1000(os, m_shooting_timer + 0.1);
				// bright?
				writeU8(os, true);
				// create message and add to list
				ActiveObjectMessage aom(getId(), false, os.str());
				m_messages_out.push_back(aom);
			}
		}
	}
	
	if(m_move_type == "ground_nodes")
	{
		if(!m_shooting){
			m_walk_around_timer -= dtime;
			if(m_walk_around_timer <= 0.0){
				m_walk_around = !m_walk_around;
				if(m_walk_around)
					m_walk_around_timer = 0.1*myrand_range(10,50);
				else
					m_walk_around_timer = 0.1*myrand_range(30,70);
			}
		}

		/* Move */
		if(m_next_pos_exists){
			v3f pos_f = m_base_position;
			v3f next_pos_f = intToFloat(m_next_pos_i, BS);

			v3f v = next_pos_f - pos_f;
			m_yaw = atan2(v.Z, v.X) / PI * 180;
			
			v3f diff = next_pos_f - pos_f;
			v3f dir = diff;
			dir.normalize();
			float speed = BS * 0.5;
			if(m_falling)
				speed = BS * 3.0;
			dir *= dtime * speed;
			bool arrived = false;
			if(dir.getLength() > diff.getLength()){
				dir = diff;
				arrived = true;
			}
			pos_f += dir;
			m_base_position = pos_f;

			if((pos_f - next_pos_f).getLength() < 0.1 || arrived){
				m_next_pos_exists = false;
			}
		}

		v3s16 pos_i = floatToInt(m_base_position, BS);
		v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
		v3s16 pos_size_off(0,0,0);
		if(m_size.X >= 2.5){
			pos_size_off.X = -1;
			pos_size_off.Y = -1;
		}
		
		if(!m_next_pos_exists){
			/* Check whether to drop down */
			if(checkFreePosition(map,
					pos_i + pos_size_off + v3s16(0,-1,0), size_blocks)){
				m_next_pos_i = pos_i + v3s16(0,-1,0);
				m_next_pos_exists = true;
				m_falling = true;
			} else {
				m_falling = false;
			}
		}

		if(m_walk_around)
		{
			if(!m_next_pos_exists){
				/* Find some position where to go next */
				v3s16 dps[3*3*3];
				int num_dps = 0;
				for(int dx=-1; dx<=1; dx++)
				for(int dy=-1; dy<=1; dy++)
				for(int dz=-1; dz<=1; dz++){
					if(dx == 0 && dy == 0)
						continue;
					if(dx != 0 && dz != 0 && dy != 0)
						continue;
					dps[num_dps++] = v3s16(dx,dy,dz);
				}
				u32 order[3*3*3];
				get_random_u32_array(order, num_dps);
				for(int i=0; i<num_dps; i++){
					v3s16 p = dps[order[i]] + pos_i;
					bool is_free = checkFreeAndWalkablePosition(map,
							p + pos_size_off, size_blocks);
					if(!is_free)
						continue;
					m_next_pos_i = p;
					m_next_pos_exists = true;
					break;
				}
			}
		}
	}
	else if(m_move_type == "constant_speed")
	{
		m_base_position += m_speed * dtime;
		
		v3s16 pos_i = floatToInt(m_base_position, BS);
		v3s16 size_blocks = v3s16(m_size.X+0.5,m_size.Y+0.5,m_size.X+0.5);
		v3s16 pos_size_off(0,0,0);
		if(m_size.X >= 2.5){
			pos_size_off.X = -1;
			pos_size_off.Y = -1;
		}
		bool free = checkFreePosition(map, pos_i + pos_size_off, size_blocks);
		if(!free){
			explodeSquare(map, pos_i, v3s16(3,3,3));
			m_removed = true;
			return;
		}
	}
	else
	{
		errorstream<<"MobV2SAO::step(): id="<<m_id<<" unknown move_type=\""
				<<m_move_type<<"\""<<std::endl;
	}

	if(send_recommended == false)
		return;

	if(m_base_position.getDistanceFrom(m_last_sent_position) > 0.05*BS)
	{
		sendPosition();
	}
}
Esempio n. 24
0
void PlayerSAO::step(float dtime, bool send_recommended)
{
	if (m_drowning_interval.step(dtime, 2.0)) {
		// get head position
		v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS);
		MapNode n = m_env->getMap().getNodeNoEx(p);
		const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
		// If node generates drown
		if (c.drowning > 0 && m_hp > 0) {
			if (m_breath > 0)
				setBreath(m_breath - 1);

			// No more breath, damage player
			if (m_breath == 0) {
				setHP(m_hp - c.drowning);
				m_env->getGameDef()->SendPlayerHPOrDie(this);
			}
		}
	}

	if (m_breathing_interval.step(dtime, 0.5)) {
		// get head position
		v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS);
		MapNode n = m_env->getMap().getNodeNoEx(p);
		const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
		// If player is alive & no drowning, breath
		if (m_hp > 0 && m_breath < PLAYER_MAX_BREATH && c.drowning == 0)
			setBreath(m_breath + 1);
	}

	if (m_node_hurt_interval.step(dtime, 1.0)) {
		// Feet, middle and head
		v3s16 p1 = floatToInt(m_base_position + v3f(0, BS*0.1, 0), BS);
		MapNode n1 = m_env->getMap().getNodeNoEx(p1);
		v3s16 p2 = floatToInt(m_base_position + v3f(0, BS*0.8, 0), BS);
		MapNode n2 = m_env->getMap().getNodeNoEx(p2);
		v3s16 p3 = floatToInt(m_base_position + v3f(0, BS*1.6, 0), BS);
		MapNode n3 = m_env->getMap().getNodeNoEx(p3);

		u32 damage_per_second = 0;
		damage_per_second = MYMAX(damage_per_second,
			m_env->getGameDef()->ndef()->get(n1).damage_per_second);
		damage_per_second = MYMAX(damage_per_second,
			m_env->getGameDef()->ndef()->get(n2).damage_per_second);
		damage_per_second = MYMAX(damage_per_second,
			m_env->getGameDef()->ndef()->get(n3).damage_per_second);

		if (damage_per_second != 0 && m_hp > 0) {
			s16 newhp = ((s32) damage_per_second > m_hp ? 0 : m_hp - damage_per_second);
			setHP(newhp);
			m_env->getGameDef()->SendPlayerHPOrDie(this);
		}
	}

	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(aom);
	}

	// If attached, check that our parent is still there. If it isn't, detach.
	if(m_attachment_parent_id && !isAttached())
	{
		m_attachment_parent_id = 0;
		m_attachment_bone = "";
		m_attachment_position = v3f(0,0,0);
		m_attachment_rotation = v3f(0,0,0);
		setBasePosition(m_last_good_position);
		m_env->getGameDef()->SendMovePlayer(m_peer_id);
	}

	//dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;

	// Set lag pool maximums based on estimated lag
	const float LAG_POOL_MIN = 5.0;
	float lag_pool_max = m_env->getMaxLagEstimate() * 2.0;
	if(lag_pool_max < LAG_POOL_MIN)
		lag_pool_max = LAG_POOL_MIN;
	m_dig_pool.setMax(lag_pool_max);
	m_move_pool.setMax(lag_pool_max);

	// Increment cheat prevention timers
	m_dig_pool.add(dtime);
	m_move_pool.add(dtime);
	m_time_from_last_teleport += dtime;
	m_time_from_last_punch += dtime;
	m_nocheat_dig_time += dtime;

	// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
	// If the object gets detached this comes into effect automatically from the last known origin
	if (isAttached()) {
		v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		m_last_good_position = pos;
		setBasePosition(pos);
	}

	if (!send_recommended)
		return;

	// If the object is attached client-side, don't waste bandwidth sending its position to clients
	if(m_position_not_sent && !isAttached())
	{
		m_position_not_sent = false;
		float update_interval = m_env->getSendRecommendedInterval();
		v3f pos;
		if(isAttached()) // Just in case we ever do send attachment position too
			pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		else
			pos = m_base_position + v3f(0,BS*1,0);
		std::string str = gob_cmd_update_position(
			pos,
			v3f(0,0,0),
			v3f(0,0,0),
			m_yaw,
			true,
			false,
			update_interval
		);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, str);
		m_messages_out.push(aom);
	}

	if (!m_armor_groups_sent) {
		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(), true, str);
		m_messages_out.push(aom);
	}

	if (!m_physics_override_sent) {
		m_physics_override_sent = true;
		std::string str = gob_cmd_update_physics_override(m_physics_override_speed,
				m_physics_override_jump, m_physics_override_gravity,
				m_physics_override_sneak, m_physics_override_sneak_glitch,
				m_physics_override_new_move);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if (!m_animation_sent) {
		m_animation_sent = true;
		std::string str = gob_cmd_update_animation(
			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if (!m_bone_position_sent) {
		m_bone_position_sent = true;
		for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator
				ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) {
			std::string str = gob_cmd_update_bone_position((*ii).first,
					(*ii).second.X, (*ii).second.Y);
			// create message and add to list
			ActiveObjectMessage aom(getId(), true, str);
			m_messages_out.push(aom);
		}
	}

	if (!m_attachment_sent){
		m_attachment_sent = true;
		std::string str = gob_cmd_update_attachment(m_attachment_parent_id,
				m_attachment_bone, m_attachment_position, m_attachment_rotation);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}
}
Esempio n. 25
0
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(aom);
	}

	// If attached, check that our parent is still there. If it isn't, detach.
	if(m_attachment_parent_id && !isAttached())
	{
		m_attachment_parent_id = 0;
		m_attachment_bone = "";
		m_attachment_position = v3f(0,0,0);
		m_attachment_rotation = v3f(0,0,0);
		sendPosition(false, true);
	}

	m_last_sent_position_timer += dtime;

	// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
	// If the object gets detached this comes into effect automatically from the last known origin
	if(isAttached())
	{
		v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		m_base_position = pos;
		m_velocity = v3f(0,0,0);
		m_acceleration = v3f(0,0,0);
	}
	else
	{
		if(m_prop.physical){
			core::aabbox3d<f32> box = m_prop.collisionbox;
			box.MinEdge *= BS;
			box.MaxEdge *= BS;
			collisionMoveResult moveresult;
			f32 pos_max_d = BS*0.25; // Distance per iteration
			v3f p_pos = m_base_position;
			v3f p_velocity = m_velocity;
			v3f p_acceleration = m_acceleration;
			moveresult = collisionMoveSimple(m_env,m_env->getGameDef(),
					pos_max_d, box, m_prop.stepheight, dtime,
					p_pos, p_velocity, p_acceleration,
					this, m_prop.collideWithObjects);

			// Apply results
			m_base_position = p_pos;
			m_velocity = p_velocity;
			m_acceleration = p_acceleration;
		} else {
			m_base_position += dtime * m_velocity + 0.5 * dtime
					* dtime * m_acceleration;
			m_velocity += dtime * m_acceleration;
		}

		if((m_prop.automatic_face_movement_dir) &&
				(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)){
			m_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI + m_prop.automatic_face_movement_dir_offset;
		}
	}

	if(m_registered){
		m_env->getScriptIface()->luaentity_Step(m_id, dtime);
	}

	if(send_recommended == false)
		return;

	if(!isAttached())
	{
		// TODO: force send when acceleration changes enough?
		float minchange = 0.2*BS;
		if(m_last_sent_position_timer > 1.0){
			minchange = 0.01*BS;
		} else if(m_last_sent_position_timer > 0.2){
			minchange = 0.05*BS;
		}
		float move_d = m_base_position.getDistanceFrom(m_last_sent_position);
		move_d += m_last_sent_move_precision;
		float vel_d = m_velocity.getDistanceFrom(m_last_sent_velocity);
		if(move_d > minchange || vel_d > minchange ||
				fabs(m_yaw - m_last_sent_yaw) > 1.0){
			sendPosition(true, false);
		}
	}

	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(), true, str);
		m_messages_out.push(aom);
	}

	if(m_animation_sent == false){
		m_animation_sent = true;
		std::string str = gob_cmd_update_animation(
			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if(m_bone_position_sent == false){
		m_bone_position_sent = true;
		for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
			std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
			// create message and add to list
			ActiveObjectMessage aom(getId(), true, str);
			m_messages_out.push(aom);
		}
	}

	if(m_attachment_sent == false){
		m_attachment_sent = true;
		std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}
}
Esempio n. 26
0
void PlayerSAO::step(float dtime, bool send_recommended)
{
	if (m_drowning_interval.step(dtime, 2.0f)) {
		// Get nose/mouth position, approximate with eye position
		v3s16 p = floatToInt(getEyePosition(), BS);
		MapNode n = m_env->getMap().getNodeNoEx(p);
		const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
		// If node generates drown
		if (c.drowning > 0 && m_hp > 0) {
			if (m_breath > 0)
				setBreath(m_breath - 1);

			// No more breath, damage player
			if (m_breath == 0) {
				PlayerHPChangeReason reason(PlayerHPChangeReason::DROWNING);
				setHP(m_hp - c.drowning, reason);
				m_env->getGameDef()->SendPlayerHPOrDie(this, reason);
			}
		}
	}

	if (m_breathing_interval.step(dtime, 0.5f)) {
		// Get nose/mouth position, approximate with eye position
		v3s16 p = floatToInt(getEyePosition(), BS);
		MapNode n = m_env->getMap().getNodeNoEx(p);
		const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
		// If player is alive & no drowning, breathe
		if (m_hp > 0 && m_breath < m_prop.breath_max && c.drowning == 0)
			setBreath(m_breath + 1);
	}

	if (m_node_hurt_interval.step(dtime, 1.0f)) {
		u32 damage_per_second = 0;
		// Lowest and highest damage points are 0.1 within collisionbox
		float dam_top = m_prop.collisionbox.MaxEdge.Y - 0.1f;

		// Sequence of damage points, starting 0.1 above feet and progressing
		// upwards in 1 node intervals, stopping below top damage point.
		for (float dam_height = 0.1f; dam_height < dam_top; dam_height++) {
			v3s16 p = floatToInt(m_base_position +
				v3f(0.0f, dam_height * BS, 0.0f), BS);
			MapNode n = m_env->getMap().getNodeNoEx(p);
			damage_per_second = std::max(damage_per_second,
				m_env->getGameDef()->ndef()->get(n).damage_per_second);
		}

		// Top damage point
		v3s16 ptop = floatToInt(m_base_position +
			v3f(0.0f, dam_top * BS, 0.0f), BS);
		MapNode ntop = m_env->getMap().getNodeNoEx(ptop);
		damage_per_second = std::max(damage_per_second,
			m_env->getGameDef()->ndef()->get(ntop).damage_per_second);

		if (damage_per_second != 0 && m_hp > 0) {
			s16 newhp = ((s32) damage_per_second > m_hp ? 0 : m_hp - damage_per_second);
			PlayerHPChangeReason reason(PlayerHPChangeReason::NODE_DAMAGE);
			setHP(newhp, reason);
			m_env->getGameDef()->SendPlayerHPOrDie(this, reason);
		}
	}

	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(aom);
	}

	// If attached, check that our parent is still there. If it isn't, detach.
	if (m_attachment_parent_id && !isAttached()) {
		m_attachment_parent_id = 0;
		m_attachment_bone = "";
		m_attachment_position = v3f(0.0f, 0.0f, 0.0f);
		m_attachment_rotation = v3f(0.0f, 0.0f, 0.0f);
		setBasePosition(m_last_good_position);
		m_env->getGameDef()->SendMovePlayer(m_peer_id);
	}

	//dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl;

	// Set lag pool maximums based on estimated lag
	const float LAG_POOL_MIN = 5.0f;
	float lag_pool_max = m_env->getMaxLagEstimate() * 2.0f;
	if(lag_pool_max < LAG_POOL_MIN)
		lag_pool_max = LAG_POOL_MIN;
	m_dig_pool.setMax(lag_pool_max);
	m_move_pool.setMax(lag_pool_max);

	// Increment cheat prevention timers
	m_dig_pool.add(dtime);
	m_move_pool.add(dtime);
	m_time_from_last_teleport += dtime;
	m_time_from_last_punch += dtime;
	m_nocheat_dig_time += dtime;

	// Each frame, parent position is copied if the object is attached,
	// otherwise it's calculated normally.
	// If the object gets detached this comes into effect automatically from
	// the last known origin.
	if (isAttached()) {
		v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		m_last_good_position = pos;
		setBasePosition(pos);
	}

	if (!send_recommended)
		return;

	// If the object is attached client-side, don't waste bandwidth sending its
	// position to clients.
	if (m_position_not_sent && !isAttached()) {
		m_position_not_sent = false;
		float update_interval = m_env->getSendRecommendedInterval();
		v3f pos;
		if (isAttached()) // Just in case we ever do send attachment position too
			pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		else
			pos = m_base_position;

		std::string str = gob_cmd_update_position(
			pos,
			v3f(0.0f, 0.0f, 0.0f),
			v3f(0.0f, 0.0f, 0.0f),
			m_yaw,
			true,
			false,
			update_interval
		);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, str);
		m_messages_out.push(aom);
	}

	if (!m_armor_groups_sent) {
		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(), true, str);
		m_messages_out.push(aom);
	}

	if (!m_physics_override_sent) {
		m_physics_override_sent = true;
		std::string str = gob_cmd_update_physics_override(m_physics_override_speed,
				m_physics_override_jump, m_physics_override_gravity,
				m_physics_override_sneak, m_physics_override_sneak_glitch,
				m_physics_override_new_move);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if (!m_animation_sent) {
		m_animation_sent = true;
		std::string str = gob_cmd_update_animation(
			m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}

	if (!m_bone_position_sent) {
		m_bone_position_sent = true;
		for (std::unordered_map<std::string, core::vector2d<v3f>>::const_iterator
				ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) {
			std::string str = gob_cmd_update_bone_position((*ii).first,
					(*ii).second.X, (*ii).second.Y);
			// create message and add to list
			ActiveObjectMessage aom(getId(), true, str);
			m_messages_out.push(aom);
		}
	}

	if (!m_attachment_sent) {
		m_attachment_sent = true;
		std::string str = gob_cmd_update_attachment(m_attachment_parent_id,
				m_attachment_bone, m_attachment_position, m_attachment_rotation);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push(aom);
	}
}
Esempio n. 27
0
void Oerkki1SAO::step(float dtime, bool send_recommended)
{
	ScopeProfiler sp2(g_profiler, "Oerkki1SAO::step avg", SPT_AVG);

	assert(m_env);

	if(m_is_active == false)
	{
		if(m_inactive_interval.step(dtime, 0.5)==false)
			return;
	}

	/*
		The AI
	*/

	m_age += dtime;
	if(m_age > 120)
	{
		// Die
		m_removed = true;
		return;
	}

	m_after_jump_timer -= dtime;

	v3f old_speed = m_speed_f;

	// Apply gravity
	m_speed_f.Y -= dtime*9.81*BS;

	/*
		Move around if some player is close
	*/
	bool player_is_close = false;
	bool player_is_too_close = false;
	v3f near_player_pos;
	// Check connected players
	core::list<Player*> players = m_env->getPlayers(true);
	core::list<Player*>::Iterator i;
	for(i = players.begin();
			i != players.end(); i++)
	{
		Player *player = *i;
		v3f playerpos = player->getPosition();
		f32 dist = m_base_position.getDistanceFrom(playerpos);
		if(dist < BS*0.6)
		{
			m_removed = true;
			return;
			player_is_too_close = true;
			near_player_pos = playerpos;
		}
		else if(dist < BS*15.0 && !player_is_too_close)
		{
			player_is_close = true;
			near_player_pos = playerpos;
		}
	}

	m_is_active = player_is_close;

	v3f target_speed = m_speed_f;

	if(!player_is_close)
	{
		target_speed = v3f(0,0,0);
	}
	else
	{
		// Move around

		v3f ndir = near_player_pos - m_base_position;
		ndir.Y = 0;
		ndir.normalize();

		f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
		if(nyaw < m_yaw - 180)
			nyaw += 360;
		else if(nyaw > m_yaw + 180)
			nyaw -= 360;
		m_yaw = 0.95*m_yaw + 0.05*nyaw;
		m_yaw = wrapDegrees(m_yaw);
		
		f32 speed = 2*BS;

		if((m_touching_ground || m_after_jump_timer > 0.0)
				&& !player_is_too_close)
		{
			v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
			target_speed.X = speed * dir.X;
			target_speed.Z = speed * dir.Z;
		}

		if(m_touching_ground && (m_oldpos - m_base_position).getLength()
				< dtime*speed/2)
		{
			m_counter1 -= dtime;
			if(m_counter1 < 0.0)
			{
				m_counter1 += 0.2;
				// Jump
				target_speed.Y = 5.0*BS;
				m_after_jump_timer = 1.0;
			}
		}

		{
			m_counter2 -= dtime;
			if(m_counter2 < 0.0)
			{
				m_counter2 += (float)(myrand()%100)/100*3.0;
				//m_yaw += ((float)(myrand()%200)-100)/100*180;
				m_yaw += ((float)(myrand()%200)-100)/100*90;
				m_yaw = wrapDegrees(m_yaw);
			}
		}
	}
	
	if((m_speed_f - target_speed).getLength() > BS*4 || player_is_too_close)
		accelerate_xz(m_speed_f, target_speed, dtime*BS*8);
	else
		accelerate_xz(m_speed_f, target_speed, dtime*BS*4);
	
	m_oldpos = m_base_position;

	/*
		Move it, with collision detection
	*/

	core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
	collisionMoveResult moveresult;
	// Maximum movement without glitches
	f32 pos_max_d = BS*0.25;
	/*// Limit speed
	if(m_speed_f.getLength()*dtime > pos_max_d)
		m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
	v3f pos_f = getBasePosition();
	v3f pos_f_old = pos_f;
	IGameDef *gamedef = m_env->getGameDef();
	moveresult = collisionMovePrecise(&m_env->getMap(), gamedef,
			pos_max_d, box, dtime, pos_f, m_speed_f);
	m_touching_ground = moveresult.touching_ground;
	
	// Do collision damage
	float tolerance = BS*30;
	float factor = BS*0.5;
	v3f speed_diff = old_speed - m_speed_f;
	// Increase effect in X and Z
	speed_diff.X *= 2;
	speed_diff.Z *= 2;
	float vel = speed_diff.getLength();
	if(vel > tolerance)
	{
		f32 damage_f = (vel - tolerance)/BS*factor;
		u16 damage = (u16)(damage_f+0.5);
		doDamage(damage);
	}

	setBasePosition(pos_f);

	if(send_recommended == false && m_speed_f.getLength() < 3.0*BS)
		return;

	if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
	{
		m_last_sent_position = pos_f;

		std::ostringstream os(std::ios::binary);
		// command (0 = update position)
		writeU8(os, 0);
		// pos
		writeV3F1000(os, m_base_position);
		// yaw
		writeF1000(os, m_yaw);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, os.str());
		m_messages_out.push_back(aom);
	}
}
Esempio n. 28
0
void FireflySAO::step(float dtime, bool send_recommended)
{
	ScopeProfiler sp2(g_profiler, "FireflySAO::step avg", SPT_AVG);

	assert(m_env);

	if(m_is_active == false)
	{
		if(m_inactive_interval.step(dtime, 0.5)==false)
			return;
	}

	/*
		The AI
	*/

	// Apply (less) gravity
	m_speed_f.Y -= dtime*3*BS;

	/*
		Move around if some player is close
	*/
	bool player_is_close = false;
	// Check connected players
	core::list<Player*> players = m_env->getPlayers(true);
	core::list<Player*>::Iterator i;
	for(i = players.begin();
			i != players.end(); i++)
	{
		Player *player = *i;
		v3f playerpos = player->getPosition();
		if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
		{
			player_is_close = true;
			break;
		}
	}

	m_is_active = player_is_close;
	
	if(player_is_close == false)
	{
		m_speed_f.X = 0;
		m_speed_f.Z = 0;
	}
	else
	{
		// Move around
		v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
		f32 speed = BS/2;
		m_speed_f.X = speed * dir.X;
		m_speed_f.Z = speed * dir.Z;

		if(m_touching_ground && (m_oldpos - m_base_position).getLength()
				< dtime*speed/2)
		{
			m_counter1 -= dtime;
			if(m_counter1 < 0.0)
			{
				m_counter1 += 1.0;
				m_speed_f.Y = 5.0*BS;
			}
		}

		{
			m_counter2 -= dtime;
			if(m_counter2 < 0.0)
			{
				m_counter2 += (float)(myrand()%100)/100*3.0;
				m_yaw += ((float)(myrand()%200)-100)/100*180;
				m_yaw = wrapDegrees(m_yaw);
			}
		}
	}
	
	m_oldpos = m_base_position;

	/*
		Move it, with collision detection
	*/

	core::aabbox3d<f32> box(-BS/3.,-BS*2/3.0,-BS/3., BS/3.,BS*4./3.,BS/3.);
	collisionMoveResult moveresult;
	// Maximum movement without glitches
	f32 pos_max_d = BS*0.25;
	// Limit speed
	if(m_speed_f.getLength()*dtime > pos_max_d)
		m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
	v3f pos_f = getBasePosition();
	v3f pos_f_old = pos_f;
	IGameDef *gamedef = m_env->getGameDef();
	moveresult = collisionMoveSimple(&m_env->getMap(), gamedef,
			pos_max_d, box, dtime, pos_f, m_speed_f);
	m_touching_ground = moveresult.touching_ground;
	
	setBasePosition(pos_f);

	if(send_recommended == false)
		return;

	if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
	{
		m_last_sent_position = pos_f;

		std::ostringstream os(std::ios::binary);
		// command (0 = update position)
		writeU8(os, 0);
		// pos
		writeV3F1000(os, m_base_position);
		// yaw
		writeF1000(os, m_yaw);
		// create message and add to list
		ActiveObjectMessage aom(getId(), false, os.str());
		m_messages_out.push_back(aom);
	}
}
Esempio n. 29
0
void PlayerSAO::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);
	}

	// If attached, check that our parent is still there. If it isn't, detach.
	if(m_attachment_parent_id && !isAttached())
	{
		m_attachment_parent_id = 0;
		m_attachment_bone = "";
		m_attachment_position = v3f(0,0,0);
		m_attachment_rotation = v3f(0,0,0);
		m_player->setPosition(m_last_good_position);
		m_moved = true;
	}

	m_time_from_last_punch += dtime;
	m_nocheat_dig_time += dtime;

	// Each frame, parent position is copied if the object is attached, otherwise it's calculated normally
	// If the object gets detached this comes into effect automatically from the last known origin
	if(isAttached())
	{
		v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		m_last_good_position = pos;
		m_last_good_position_age = 0;
		m_player->setPosition(pos);
	}
	else
	{
		if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
		{
			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. Altough a node-based alternative might be possible
				too, and much more lightweight.
			*/

			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 {
				// 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_moved = true;
				}
				m_last_good_position_age = 0;
			}
		}
	}

	if(send_recommended == false)
		return;

	// If the object is attached client-side, don't waste bandwidth sending its position to clients
	if(m_position_not_sent && !isAttached())
	{
		m_position_not_sent = false;
		float update_interval = m_env->getSendRecommendedInterval();
		v3f pos;
		if(isAttached()) // Just in case we ever do send attachment position too
			pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition();
		else
			pos = m_player->getPosition() + v3f(0,BS*1,0);
		std::string str = gob_cmd_update_position(
			pos,
			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, 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
	}

	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(), true, str);
		m_messages_out.push_back(aom);
	}

	if(m_animation_sent == false){
		m_animation_sent = true;
		std::string str = gob_cmd_update_animation(m_animation_range, m_animation_speed, m_animation_blend);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push_back(aom);
	}

	if(m_bone_position_sent == false){
		m_bone_position_sent = true;
		for(std::map<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){
			std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y);
			// create message and add to list
			ActiveObjectMessage aom(getId(), true, str);
			m_messages_out.push_back(aom);
		}
	}

	if(m_attachment_sent == false){
		m_attachment_sent = true;
		std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation);
		// create message and add to list
		ActiveObjectMessage aom(getId(), true, str);
		m_messages_out.push_back(aom);
	}
}