Loading...   


void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
{
	if (IsAIControlled())
		return;

	if(dead)
		return;

	//currently accepting two sizes, one has an extra byte on the end
	if (app->size != sizeof(PlayerPositionUpdateClient_Struct)
	&& app->size != (sizeof(PlayerPositionUpdateClient_Struct)+1)
	) {
		LogFile->write(EQEMuLog::Error, "OP size error: OP_ClientUpdate expected:%i got:%i", sizeof(PlayerPositionUpdateClient_Struct), app->size);
		return;
	}
	PlayerPositionUpdateClient_Struct* ppu = (PlayerPositionUpdateClient_Struct*)app->pBuffer;

	if(ppu->spawn_id != GetID()) {
		// check if the id is for a boat the player is controlling
		if (ppu->spawn_id == BoatID) {
			Mob* boat = entity_list.GetMob(BoatID);
			if (boat == 0) {	// if the boat ID is invalid, reset the id and abort
				BoatID = 0;
				return;
			}

			// set the boat's position deltas
			boat->SetDeltas(ppu->delta_x, ppu->delta_y, ppu->delta_z, ppu->delta_heading);
			// send an update to everyone nearby except the client controlling the boat
			EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
			PlayerPositionUpdateServer_Struct* ppus = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
			boat->MakeSpawnUpdate(ppus);
			entity_list.QueueCloseClients(boat,outapp,true,300,this,false);
			safe_delete(outapp);
			// update the boat's position on the server, without sending an update
			boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ19toFloat(ppu->heading), false);
			return;
		}
		else return;	// if not a boat, do nothing
	}

	float dist = 0;
	float tmp;
	tmp = x_pos - ppu->x_pos;
	dist += tmp*tmp;
	tmp = y_pos - ppu->y_pos;
	dist += tmp*tmp;
	dist = sqrt(dist);

	//the purpose of this first block may not be readily apparent
	//basically it's so people don't do a moderate warp every 2.5 seconds
	//letting it even out and basically getting the job done without triggering
	if(dist == 0)
	{
		if(m_DistanceSinceLastPositionCheck > 0.0)
		{
			uint32 cur_time = Timer::GetCurrentTime();
			if((cur_time - m_TimeSinceLastPositionCheck) > 0)
			{
				float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
				float runs = GetRunspeed();
				if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
				{
					if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
					{
						if(IsShadowStepExempted())
						{
							if(m_DistanceSinceLastPositionCheck > 800)
							{
								CheatDetected(MQWarpShadowStep, ppu->x_pos, ppu->y_pos, ppu->z_pos);
							}
						}
						else if(IsKnockBackExempted())
						{
							//still potential to trigger this if you're knocked back off a
							//HUGE fall that takes > 2.5 seconds
							if(speed > 30.0f)
							{
								CheatDetected(MQWarpKnockBack, ppu->x_pos, ppu->y_pos, ppu->z_pos);
							}
						}
						else if(!IsPortExempted())
						{
							if(!IsMQExemptedArea(zone->GetZoneID(), ppu->x_pos, ppu->y_pos, ppu->z_pos))
							{
								if(speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor)))
								{
									m_TimeSinceLastPositionCheck = cur_time;
									m_DistanceSinceLastPositionCheck = 0.0f;
									CheatDetected(MQWarp, ppu->x_pos, ppu->y_pos, ppu->z_pos);
									//Death(this, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
								}
								else
								{
									CheatDetected(MQWarpLight, ppu->x_pos, ppu->y_pos, ppu->z_pos);
								}
							}
						}
					}
				}
				SetShadowStepExemption(false);
				SetKnockBackExemption(false);
				SetPortExemption(false);
				m_TimeSinceLastPositionCheck = cur_time;
				m_DistanceSinceLastPositionCheck = 0.0f;
				m_CheatDetectMoved = false;
			}
		}
		else
		{
			m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
			m_CheatDetectMoved = false;
		}
	}
	else
	{
		m_DistanceSinceLastPositionCheck += dist;
		m_CheatDetectMoved = true;
		if(m_TimeSinceLastPositionCheck == 0)
		{
			m_TimeSinceLastPositionCheck = Timer::GetCurrentTime();
		}
		else
		{
			uint32 cur_time = Timer::GetCurrentTime();
			if((cur_time - m_TimeSinceLastPositionCheck) > 2500)
			{
				float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck);
				float runs = GetRunspeed();
				if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor)))
				{
					if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor)))))
					{
						if(IsShadowStepExempted())
						{
							if(m_DistanceSinceLastPositionCheck > 800)
							{
								//if(!IsMQExemptedArea(zone->GetZoneID(), ppu->x_pos, ppu->y_pos, ppu->z_pos))
								//{
									CheatDetected(MQWarpShadowStep, ppu->x_pos, ppu->y_pos, ppu->z_pos);
									//Death(this, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
								//}
							}
						}
						else if(IsKnockBackExempted())
						{
							//still potential to trigger this if you're knocked back off a
							//HUGE fall that takes > 2.5 seconds
							if(speed > 30.0f)
							{
								CheatDetected(MQWarpKnockBack, ppu->x_pos, ppu->y_pos, ppu->z_pos);
							}
						}
						else if(!IsPortExempted())
						{
							if(!IsMQExemptedArea(zone->GetZoneID(), ppu->x_pos, ppu->y_pos, ppu->z_pos))
							{
								if(speed > (runs * 2 * RuleR(Zone, MQWarpDetectionDistanceFactor)))
								{
									m_TimeSinceLastPositionCheck = cur_time;
									m_DistanceSinceLastPositionCheck = 0.0f;
									CheatDetected(MQWarp, ppu->x_pos, ppu->y_pos, ppu->z_pos);
									//Death(this, 10000000, SPELL_UNKNOWN, _1H_BLUNT);
								}
								else
								{
									CheatDetected(MQWarpLight, ppu->x_pos, ppu->y_pos, ppu->z_pos);
								}
							}
						}
					}
				}
				SetShadowStepExemption(false);
				SetKnockBackExemption(false);
				SetPortExemption(false);
				m_TimeSinceLastPositionCheck = cur_time;
				m_DistanceSinceLastPositionCheck = 0.0f;
			}
		}

		if(IsDraggingCorpse())
			DragCorpses();
	}

	//Check to see if PPU should trigger an update to the rewind position.
	float rewind_x_diff = 0;
	float rewind_y_diff = 0;

	rewind_x_diff = ppu->x_pos - rewind_x;
	rewind_x_diff *= rewind_x_diff;
	rewind_y_diff = ppu->y_pos - rewind_y;
	rewind_y_diff *= rewind_y_diff;

	//We only need to store updated values if the player has moved.
	//If the player has moved more than units for x or y, then we'll store
	//his pre-PPU x and y for /rewind, in case he gets stuck.
	if ((rewind_x_diff > 750) || (rewind_y_diff > 750)) {
		rewind_x = x_pos;
		rewind_y = y_pos;
		rewind_z = z_pos;
	}

	//If the PPU was a large jump, such as a cross zone gate or Call of Hero,
	//just update rewind coords to the new ppu coords. This will prevent exploitation.

	if ((rewind_x_diff > 5000) || (rewind_y_diff > 5000)) {
		rewind_x = ppu->x_pos;
		rewind_y = ppu->y_pos;
		rewind_z = ppu->z_pos;
	}

	if(proximity_timer.Check()) {
		entity_list.ProcessMove(this, ppu->x_pos, ppu->y_pos, ppu->z_pos);
		if(RuleB(TaskSystem, EnableTaskSystem) && RuleB(TaskSystem,EnableTaskProximity))
			ProcessTaskProximities(ppu->x_pos, ppu->y_pos, ppu->z_pos);
		proximity_x = ppu->x_pos;
		proximity_y = ppu->y_pos;
		proximity_z = ppu->z_pos;
	}

	// Update internal state
	delta_x			= ppu->delta_x;
	delta_y			= ppu->delta_y;
	delta_z			= ppu->delta_z;
	delta_heading	= ppu->delta_heading;
	heading			= EQ19toFloat(ppu->heading);

	if(IsTracking() && ((x_pos!=ppu->x_pos) || (y_pos!=ppu->y_pos))){
		if(MakeRandomFloat(0, 100) < 70)//should be good
			CheckIncreaseSkill(SkillTracking, nullptr, -20);
	}

	// Break Hide if moving without sneaking and set rewind timer if moved
	if(ppu->y_pos != y_pos || ppu->x_pos != x_pos){
		if((hidden || improved_hidden) && !sneaking){
			hidden = false;
			improved_hidden = false;
			if(!invisible) {
				EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
				SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer;
				sa_out->spawn_id = GetID();
				sa_out->type = 0x03;
				sa_out->parameter = 0;
				entity_list.QueueClients(this, outapp, true);
				safe_delete(outapp);
			}
		}
		rewind_timer.Start(30000, true);
	}

	// Outgoing client packet
	if (ppu->y_pos != y_pos || ppu->x_pos != x_pos || ppu->heading != heading || ppu->animation != animation)
	{
		x_pos			= ppu->x_pos;
		y_pos			= ppu->y_pos;
		z_pos			= ppu->z_pos;
		animation		= ppu->animation;

		EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
		PlayerPositionUpdateServer_Struct* ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
		MakeSpawnUpdate(ppu);
		if (gmhideme)
			entity_list.QueueClientsStatus(this,outapp,true,Admin(),250);
		else
			entity_list.QueueCloseClients(this,outapp,true,300,nullptr,false);
		safe_delete(outapp);

		if (IsClient()) {
			std::vector<std::string> params;
			params.push_back(std::to_string((long)zone->GetZoneID()));
			params.push_back(std::to_string((long)zone->GetInstanceID()));
			params.push_back(std::to_string((long)GetID()));
			params.push_back(GetCleanName());
			params.push_back(std::to_string((double)x_pos));
			params.push_back(std::to_string((double)y_pos));
			params.push_back(std::to_string((double)z_pos));
			params.push_back(std::to_string((double)heading));
			RemoteCallSubscriptionHandler::Instance()->OnEvent("Client.Position", params);
		}
	}

	if(zone->watermap)
	{
		if(zone->watermap->InLiquid(x_pos, y_pos, z_pos))
		{
			CheckIncreaseSkill(SkillSwimming, nullptr, -17);
		}
	}

	return;
}

Raw Paste Data