Exemple #1
0
void MapMgr::RemoveObject(Object *obj)
{
    ASSERT(obj);
    ASSERT(obj->GetMapId() == _mapId);
    ASSERT(obj->GetPositionX() > _minX && obj->GetPositionX() < _maxX);
    ASSERT(obj->GetPositionY() > _minY && obj->GetPositionY() < _maxY);
    ASSERT(_cells);

    sLog.outDetail("Removing object "I64FMT" with type %i from the world.",
        obj->GetGUID(), obj->GetTypeId());

    // That object types are not map objects. TODO: add AI groups here?
    if(obj->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER)
    {
    // remove updatable flag and exit
        obj->RemoveFromWorld();
        return;
    }

    obj->RemoveFromWorld();

    ObjectMap::iterator itr = _objects.find(obj->GetGUID());
    _objects.erase(itr);

    // remove us from updated objects list
    ObjectSet::iterator updi = _updatedObjects.find(obj);
    if(updi != _updatedObjects.end())
        _updatedObjects.erase(updi);

    MapCell *objCell = obj->GetMapCell();

    obj->SetMapCell(0);
    objCell->RemoveObject(obj);

    for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin();
        iter != obj->GetInRangeSetEnd(); iter++)
    {
        (*iter)->RemoveInRangeObject(obj);

        if((*iter)->GetTypeId() == TYPEID_PLAYER)
            obj->DestroyForPlayer( (Player*)*iter );
    }

    obj->ClearInRangeSet();
}
Exemple #2
0
void MapMgr::ChangeObjectLocation(Object* obj)
{
	/*
	if ( !obj ) return; // crashfix
	*/

	ARCEMU_ASSERT(obj != NULL);

	// Items and containers are of no interest for us
	if(obj->IsItem() || obj->IsContainer() || obj->GetMapMgr() != this)
	{
		return;
	}

	Player* plObj = NULL;
	ByteBuffer* buf = 0;

	if(obj->IsPlayer())
	{
		plObj = TO< Player* >(obj);
	}

	Object* curObj;
	float fRange = 0.0f;

	///////////////////////////////////////
	// Update in-range data for old objects
	///////////////////////////////////////

	if(obj->HasInRangeObjects())
	{
		for(Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin(); iter != obj->GetInRangeSetEnd();)
		{
			curObj = *iter;
			++iter;

			if(curObj->IsPlayer() && plObj != NULL && plObj->transporter_info.guid && plObj->transporter_info.guid == TO< Player* >(curObj)->transporter_info.guid)
				fRange = 0.0f; // unlimited distance for people on same boat
			else if(curObj->GetTypeFromGUID() == HIGHGUID_TYPE_TRANSPORTER)
				fRange = 0.0f; // unlimited distance for transporters (only up to 2 cells +/- anyway.)
			//If the object announcing its position is a transport, or other special object, then deleting it from visible objects should be avoided. - By: VLack
			else if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId())
				fRange = 0.0f;
			//If the object we're checking for possible removal is a transport or other special object, and we are players on the same map, don't remove it...
			else if(plObj && curObj->IsGameObject() && (TO< GameObject* >(curObj)->GetOverrides() & GAMEOBJECT_INFVIS) && obj->GetMapId() == curObj->GetMapId())
				fRange = 0.0f;
			else if(curObj->IsPlayer() && TO< Player* >(curObj)->GetFarsightTarget() == obj->GetGUID())
				fRange = 0.0f;//Mind Vision, Eye of Kilrogg
			else
				fRange = m_UpdateDistance; // normal distance

			if(fRange > 0.0f && (curObj->GetDistance2dSq(obj) > fRange))
			{
				if(plObj != NULL)
					plObj->RemoveIfVisible(curObj->GetGUID());

				if(curObj->IsPlayer())
					TO< Player* >(curObj)->RemoveIfVisible(obj->GetGUID());

				curObj->RemoveInRangeObject(obj);

				if(obj->GetMapMgr() != this)
				{
					/* Something removed us. */
					return;
				}
				obj->RemoveInRangeObject(curObj);
			}
		}
	}

	///////////////////////////
	// Get new cell coordinates
	///////////////////////////
	if(obj->GetMapMgr() != this)
	{
		/* Something removed us. */
		return;
	}

	if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minX ||
	        obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY)
	{
		if(plObj != NULL)
		{
			if(plObj->GetBindMapId() != GetMapId())
			{
				plObj->SafeTeleport(plObj->GetBindMapId(), 0, plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0);
				plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				return;
			}
			else
			{
				obj->GetPositionV()->ChangeCoords(plObj->GetBindPositionX(), plObj->GetBindPositionY(), plObj->GetBindPositionZ(), 0);
				plObj->GetSession()->SystemMessage("Teleported you to your hearthstone location as you were out of the map boundaries.");
				plObj->SendTeleportAckMsg(plObj->GetPosition());
			}
		}
		else
		{
			obj->GetPositionV()->ChangeCoords(0, 0, 0, 0);
		}
	}

	uint32 cellX = GetPosX(obj->GetPositionX());
	uint32 cellY = GetPosY(obj->GetPositionY());

	if(cellX >= _sizeX || cellY >= _sizeY)
	{
		return;
	}

	MapCell* objCell = GetCell(cellX, cellY);
	MapCell* pOldCell = obj->GetMapCell();
	if(objCell == NULL)
	{
		objCell = Create(cellX, cellY);
		objCell->Init(cellX, cellY, this);
	}

	ARCEMU_ASSERT(objCell != NULL);

	// If object moved cell
	if(objCell != pOldCell)
	{
		// THIS IS A HACK!
		// Current code, if a creature on a long waypoint path moves from an active
		// cell into an inactive one, it will disable itself and will never return.
		// This is to prevent cpu leaks. I will think of a better solution very soon :P

		if(!objCell->IsActive() && !plObj && obj->IsActive())
			obj->Deactivate(this);

		if(pOldCell != NULL)
			pOldCell->RemoveObject(obj);

		objCell->AddObject(obj);
		obj->SetMapCell(objCell);

		// if player we need to update cell activity
		// radius = 2 is used in order to update both
		// old and new cells
		if(obj->IsPlayer())
		{
			// have to unlock/lock here to avoid a deadlock situation.
			UpdateCellActivity(cellX, cellY, 2);
			if(pOldCell != NULL)
			{
				// only do the second check if there's -/+ 2 difference
				if(abs((int)cellX - (int)pOldCell->_x) > 2 ||
				        abs((int)cellY - (int)pOldCell->_y) > 2)
				{
					UpdateCellActivity(pOldCell->_x, pOldCell->_y, 2);
				}
			}
		}
	}


	//////////////////////////////////////
	// Update in-range set for new objects
	//////////////////////////////////////

	uint32 endX = cellX <= _sizeX ? cellX + 1 : (_sizeX - 1);
	uint32 endY = cellY <= _sizeY ? cellY + 1 : (_sizeY - 1);
	uint32 startX = cellX > 0 ? cellX - 1 : 0;
	uint32 startY = cellY > 0 ? cellY - 1 : 0;
	uint32 posX, posY;
	MapCell* cell;

	//If the object announcing it's position is a special one, then it should do so in a much wider area - like the distance between the two transport towers in Orgrimmar, or more. - By: VLack
	if(obj->IsGameObject() && (TO< GameObject* >(obj)->GetOverrides() & GAMEOBJECT_ONMOVEWIDE))
	{
		endX = cellX + 5 <= _sizeX ? cellX + 6 : (_sizeX - 1);
		endY = cellY + 5 <= _sizeY ? cellY + 6 : (_sizeY - 1);
		startX = cellX > 5 ? cellX - 6 : 0;
		startY = cellY > 5 ? cellY - 6 : 0;
	}

	for(posX = startX; posX <= endX; ++posX)
	{
		for(posY = startY; posY <= endY; ++posY)
		{
			cell = GetCell(posX, posY);
			if(cell)
				UpdateInRangeSet(obj, plObj, cell, &buf);
		}
	}

	if(buf)
		delete buf;
}
Exemple #3
0
void MapMgr::RemoveObject(Object* obj, bool free_guid)
{
	/////////////
	// Assertions
	/////////////

	ARCEMU_ASSERT(obj != NULL);
	ARCEMU_ASSERT(obj->GetMapId() == _mapId);
	//ARCEMU_ASSERT(   obj->GetPositionX() > _minX && obj->GetPositionX() < _maxX);
	//ARCEMU_ASSERT(   obj->GetPositionY() > _minY && obj->GetPositionY() < _maxY);
	ARCEMU_ASSERT(_cells != NULL);

	if(obj->IsActive())
		obj->Deactivate(this);

	//there is a very small chance that on double player ports on same update player is added to multiple insertpools but not removed
	//one clear example was the double port proc when exploiting double resurrect
	m_objectinsertlock.Acquire();
	m_objectinsertpool.erase(obj);
	m_objectinsertlock.Release();

	_updates.erase(obj);
	obj->ClearUpdateMask();

	///////////////////////////////////////
	// Remove object from all needed places
	///////////////////////////////////////

	switch(obj->GetTypeFromGUID())
	{
		case HIGHGUID_TYPE_UNIT:
		case HIGHGUID_TYPE_VEHICLE:
			ARCEMU_ASSERT(obj->GetUIdFromGUID() <= m_CreatureHighGuid);
			CreatureStorage[ obj->GetUIdFromGUID() ] = NULL;
			if(TO_CREATURE(obj)->m_spawn != NULL)
			{
				_sqlids_creatures.erase(TO_CREATURE(obj)->m_spawn->id);
			}

			if(free_guid)
				_reusable_guids_creature.push_back(obj->GetUIdFromGUID());

			break;

		case HIGHGUID_TYPE_PET:
			if(pet_iterator != m_PetStorage.end() && pet_iterator->second->GetGUID() == obj->GetGUID())
				++pet_iterator;
			m_PetStorage.erase(obj->GetUIdFromGUID());
			break;

		case HIGHGUID_TYPE_DYNAMICOBJECT:
			m_DynamicObjectStorage.erase(obj->GetLowGUID());
			break;

		case HIGHGUID_TYPE_GAMEOBJECT:
			ARCEMU_ASSERT(obj->GetUIdFromGUID() <= m_GOHighGuid);
			GOStorage[ obj->GetUIdFromGUID() ] = NULL;
			if(TO_GAMEOBJECT(obj)->m_spawn != NULL)
			{
				_sqlids_gameobjects.erase(TO_GAMEOBJECT(obj)->m_spawn->id);
			}

			if(free_guid)
				_reusable_guids_gameobject.push_back(obj->GetUIdFromGUID());

			break;
	}

	// That object types are not map objects. TODO: add AI groups here?
	if(obj->IsItem() || obj->IsContainer())
	{
		return;
	}

	if(obj->IsCorpse())
	{
		m_corpses.erase(TO< Corpse* >(obj));
	}

	MapCell* cell = GetCell(obj->GetMapCellX(), obj->GetMapCellY());
	if(cell == NULL)
	{
		/* set the map cell correctly */
		if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minY ||
		        obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY)
		{
			// do nothing
		}
		else
		{
			cell = this->GetCellByCoords(obj->GetPositionX(), obj->GetPositionY());
			obj->SetMapCell(cell);
		}
	}

	if(cell != NULL)
	{
		// Remove object from cell
		cell->RemoveObject(obj);

		// Unset object's cell
		obj->SetMapCell(NULL);
	}

	Player* plObj = NULL;
	// Clear any updates pending
	if(obj->IsPlayer())
	{
		plObj = TO_PLAYER(obj);
		_processQueue.erase(plObj);
		plObj->ClearAllPendingUpdates();
	}

	obj->RemoveSelfFromInrangeSets();

	// Clear object's in-range set
	obj->ClearInRangeSet();

	// If it's a player - update his nearby cells
	if(!_shutdown && obj->IsPlayer())
	{
		// get x/y
		if(obj->GetPositionX() >= _maxX || obj->GetPositionX() <= _minY ||
		        obj->GetPositionY() >= _maxY || obj->GetPositionY() <= _minY)
		{
			// do nothing
		}
		else
		{
			uint32 x = GetPosX(obj->GetPositionX());
			uint32 y = GetPosY(obj->GetPositionY());
			UpdateCellActivity(x, y, 2);
		}
		m_PlayerStorage.erase(TO< Player* >(obj)->GetLowGUID());
	}

	// Remove the session from our set if it is a player.
	if(obj->IsPlayer())
	{
		for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr)
		{
			plObj->PushOutOfRange((*itr)->GetNewGUID());
		}

		// Setting an instance ID here will trigger the session to be removed
		// by MapMgr::run(). :)
		plObj->GetSession()->SetInstance(0);

		// Add it to the global session set.
		// Don't "re-add" to session if it is being deleted.
		if(!plObj->GetSession()->bDeleted)
			sWorld.AddGlobalSession(plObj->GetSession());
	}

	if(!HasPlayers())
	{
		if(this->pInstance != NULL && this->pInstance->m_persistent)
			this->pInstance->m_creatorGroup = 0;
		if(!InactiveMoveTime && !forced_expire && GetMapInfo()->type != INSTANCE_NULL)
		{
			InactiveMoveTime = UNIXTIME + (MAPMGR_INACTIVE_MOVE_TIME * 60);
			Log.Debug("MapMgr", "Instance %u is now idle. (%s)", m_instanceID, GetBaseMap()->GetName());
		}
	}
}