Beispiel #1
0
void Game_Map::SetupFromSave() {
	SetupCommon(location.map_id, true);

	// Make main interpreter "busy" if save contained events to prevent auto-events from starting
	interpreter->SetupFromSave(Main_Data::game_data.events.commands);

	events.reserve(map->events.size());
	for (size_t i = 0; i < map->events.size(); ++i) {
		if (i < map_info.events.size()) {
			events.emplace_back(location.map_id, map->events[i], map_info.events[i]);
		}
		else {
			events.emplace_back(location.map_id, map->events[i]);
		}

		if (events.back().IsMoveRouteOverwritten())
			pending.push_back(&events.back());
	}

	for (size_t i = 0; i < Main_Data::game_data.common_events.size() && i < common_events.size(); ++i) {
		common_events[i].SetSaveData(Main_Data::game_data.common_events[i].event_data);
	}

	for (size_t i = 0; i < 3; i++)
		if (vehicles[i]->IsMoveRouteOverwritten())
			pending.push_back(vehicles[i].get());

	map_info.Fixup(GetMap());
	map_info.Fixup(GetMapInfo());
	SetChipset(map_info.chipset_id);

	SetEncounterSteps(location.encounter_steps);


	// We want to support loading rm2k3e panning chunks
	// but also not break other saves which don't have them.
	// To solve this problem, we reuse the scrolling methods
	// which always reset the position anyways when scroll_horz/vert
	// is false.
	// This produces compatible behavior for old RPG_RT saves, namely
	// the pan_x/y is always forced to 0.
	// If the later async code will load panorama, set the flag to not clear the offsets.
	Game_Map::Parallax::ChangeBG(GetParallaxParams());
}
Beispiel #2
0
void Game_Map::Setup(int _id) {
	Dispose();
	first_frame = true;
	SetupCommon(_id, false);
	map_info.encounter_rate = GetMapInfo().encounter_steps;
	SetEncounterSteps(0);
	reset_panorama_x_on_next_init = true;
	reset_panorama_y_on_next_init = true;
	panorama = {};

	Parallax::ClearChangedBG();

	SetChipset(map->chipset_id);

	for (size_t i = 0; i < map_info.lower_tiles.size(); i++) {
		map_info.lower_tiles[i] = i;
	}
	for (size_t i = 0; i < map_info.upper_tiles.size(); i++) {
		map_info.upper_tiles[i] = i;
	}

	events.reserve(map->events.size());
	for (const RPG::Event& ev : map->events) {
		events.emplace_back(location.map_id, ev);
	}

	// pan_state does not reset when you change maps.
	location.pan_speed = default_pan_speed;
	location.pan_finish_x = default_pan_x;
	location.pan_finish_y = default_pan_y;
	location.pan_current_x = default_pan_x;
	location.pan_current_y = default_pan_y;

	// Save allowed
	int current_index = GetMapIndex(location.map_id);
	int can_save = Data::treemap.maps[current_index].save;
	int can_escape = Data::treemap.maps[current_index].escape;
	int can_teleport = Data::treemap.maps[current_index].teleport;

	while (can_save == RPG::MapInfo::TriState_parent
			|| can_escape == RPG::MapInfo::TriState_parent
			|| can_teleport == RPG::MapInfo::TriState_parent)
	{
		int parent_index = GetMapIndex(Data::treemap.maps[current_index].parent_map);
		if (parent_index == 0) {
			// If parent is 0 and flag is parent, it's implicitly enabled.
			break;
		}
		if (parent_index == current_index) {
			Output::Warning("Map %d has parent pointing to itself!", current_index);
			break;
		}
		if (parent_index < 0) {
			Output::Warning("Map %d has invalid parent id %d!", Data::treemap.maps[current_index].parent_map);
			break;
		}
		current_index = parent_index;
		if (can_save == RPG::MapInfo::TriState_parent) {
			can_save = Data::treemap.maps[current_index].save;
		}
		if (can_escape == RPG::MapInfo::TriState_parent) {
			can_escape = Data::treemap.maps[current_index].escape;
		}
		if (can_teleport == RPG::MapInfo::TriState_parent) {
			can_teleport = Data::treemap.maps[current_index].teleport;
		}
	}
	Game_System::SetAllowSave(can_save != RPG::MapInfo::TriState_forbid);
	Game_System::SetAllowEscape(can_escape != RPG::MapInfo::TriState_forbid);
	Game_System::SetAllowTeleport(can_teleport != RPG::MapInfo::TriState_forbid);
}
Beispiel #3
0
void MapMgr::RemoveObject(Object *obj, bool free_guid)
{
	/////////////
	// Assertions
	/////////////

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

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

	_updates.erase( obj );
	obj->ClearUpdateMask();
	Player* plObj = (obj->GetTypeId() == TYPEID_PLAYER) ? static_cast< Player* >( obj ) : 0;

	///////////////////////////////////////
	// Remove object from all needed places
	///////////////////////////////////////
 
	switch(obj->GetTypeFromGUID())
	{
		case HIGHGUID_TYPE_UNIT:
			ASSERT(obj->GetUIdFromGUID() <= m_CreatureHighGuid);
			m_CreatureStorage[obj->GetUIdFromGUID()] = 0;
			if(((Creature*)obj)->m_spawn != NULL)
			{
				_sqlids_creatures.erase(((Creature*)obj)->m_spawn->id);
			}

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

			  break;

		case HIGHGUID_TYPE_PET:
			m_PetStorage.erase(obj->GetUIdFromGUID());
			break;

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

		case HIGHGUID_TYPE_GAMEOBJECT:
			ASSERT(obj->GetUIdFromGUID() <= m_GOHighGuid);
			m_GOStorage[obj->GetUIdFromGUID()] = 0;
			if(((GameObject*)obj)->m_spawn != NULL)
			{
				_sqlids_gameobjects.erase(((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->GetTypeId() == TYPEID_ITEM || obj->GetTypeId() == TYPEID_CONTAINER || obj->GetTypeId()==10)
	{
		return;
	}

	if(obj->GetTypeId() == TYPEID_CORPSE)
	{
		m_corpses.erase(((Corpse*)obj));
	}

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

	if(obj->GetMapCell())
	{
		ASSERT(obj->GetMapCell());
	
		// Remove object from cell
		obj->GetMapCell()->RemoveObject(obj);
	
		// Unset object's cell
		obj->SetMapCell(NULL);
	}

	// Clear any updates pending
	if(obj->GetTypeId() == TYPEID_PLAYER)
	{
		_processQueue.erase( static_cast< Player* >( obj ) );
		static_cast< Player* >( obj )->ClearAllPendingUpdates();
	}
	
	// Remove object from all objects 'seeing' him
	for (Object::InRangeSet::iterator iter = obj->GetInRangeSetBegin();
		iter != obj->GetInRangeSetEnd(); ++iter)
	{
		if( (*iter) )
		{
			if( (*iter)->GetTypeId() == TYPEID_PLAYER )
			{
				if( static_cast< Player* >( *iter )->IsVisible( obj ) && static_cast< Player* >( *iter )->m_TransporterGUID != obj->GetGUID() )
					static_cast< Player* >( *iter )->PushOutOfRange(obj->GetNewGUID());
			}
			(*iter)->RemoveInRangeObject(obj);
		}
	}
	
	// Clear object's in-range set
	obj->ClearInRangeSet();

	// If it's a player - update his nearby cells
	if(!_shutdown && obj->GetTypeId() == TYPEID_PLAYER)
	{
		// 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( static_cast< Player* >( obj )->GetLowGUID() );
	}

	// Remove the session from our set if it is a player.
	if(plObj)
	{
		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() && !InactiveMoveTime && !forced_expire && GetMapInfo()->type != INSTANCE_NULL)
	{
		InactiveMoveTime = UNIXTIME + (MAPMGR_INACTIVE_MOVE_TIME * 60);	   // 5 mins -> move to inactive
	}
}
Beispiel #4
0
bool MapMgr::Do()
{
#ifdef WIN32
	threadid=GetCurrentThreadId();
#endif
	thread_running = true;
	ThreadState =THREADSTATE_BUSY;
	SetThreadName("Map mgr - M%u|I%u",this->_mapId ,this->m_instanceID);
	ObjectSet::iterator i;
	uint32 last_exec=getMSTime();

	/* create static objects */
	for(GOSpawnList::iterator itr = _map->staticSpawns.GOSpawns.begin(); itr != _map->staticSpawns.GOSpawns.end(); ++itr)
	{
		GameObject * obj = CreateGameObject((*itr)->entry);
		obj->Load((*itr));
		_mapWideStaticObjects.insert(obj);
	}

	for(CreatureSpawnList::iterator itr = _map->staticSpawns.CreatureSpawns.begin(); itr != _map->staticSpawns.CreatureSpawns.end(); ++itr)
	{
		Creature * obj = CreateCreature((*itr)->entry);
		obj->Load(*itr, 0, pMapInfo);
		_mapWideStaticObjects.insert(obj);
	}

	/* add static objects */
	for(set<Object*>::iterator itr = _mapWideStaticObjects.begin(); itr != _mapWideStaticObjects.end(); ++itr)
		PushStaticObject(*itr);

	/* load corpses */
	objmgr.LoadCorpses(this);

	// always declare local variables outside of the loop!
	// otherwise theres a lot of sub esp; going on.

	uint32 exec_time, exec_start;
#ifdef WIN32
	HANDLE hThread = GetCurrentThread();
#endif
	while((ThreadState != THREADSTATE_TERMINATE) && !_shutdown)
	{
		exec_start=getMSTime();
		//first push to world new objects
		m_objectinsertlock.Acquire();//<<<<<<<<<<<<<<<<
		if(m_objectinsertpool.size())
		{
			for(i=m_objectinsertpool.begin();i!=m_objectinsertpool.end();i++)
			{
				//PushObject(*i);
				(*i)->PushToWorld(this);
			}
			m_objectinsertpool.clear();
		}
		m_objectinsertlock.Release();//>>>>>>>>>>>>>>>>
		//-------------------------------------------------------
				
		//Now update sessions of this map + objects
		_PerformObjectDuties();

		last_exec=getMSTime();
		exec_time=last_exec-exec_start;
		if(exec_time<MAP_MGR_UPDATE_PERIOD)
		{
			/*
				The common place I see this is waiting for a Win32 thread to exit. I used to come up with all sorts of goofy,
				elaborate event-based systems to do this myself until I discovered that thread handles are waitable. Just use
				WaitForSingleObject() on the thread handle and you're done. No risking race conditions with the thread exit code.
				I think pthreads has pthread_join() for this too.

				- http://www.virtualdub.org/blog/pivot/entry.php?id=62
			*/

#ifdef WIN32
			WaitForSingleObject(hThread, MAP_MGR_UPDATE_PERIOD-exec_time);
#else
			Sleep(MAP_MGR_UPDATE_PERIOD-exec_time);
#endif
		}

		//////////////////////////////////////////////////////////////////////////
		// Check if we have to die :P
		//////////////////////////////////////////////////////////////////////////
		if(InactiveMoveTime && UNIXTIME >= InactiveMoveTime)
			break;
	}

	// Clear the instance's reference to us.
	if(m_battleground)
	{
		BattlegroundManager.DeleteBattleground(m_battleground);
		sInstanceMgr.DeleteBattlegroundInstance( GetMapId(), GetInstanceID() );
	}

	if(pInstance)
	{
		// check for a non-raid instance, these expire after 10 minutes.
		if(GetMapInfo()->type == INSTANCE_NONRAID || pInstance->m_isBattleground)
		{
			pInstance->m_mapMgr = NULL;
			sInstanceMgr._DeleteInstance(pInstance, true);
		}
		else
		{
			// just null out the pointer
			pInstance->m_mapMgr=NULL;
		}
	}
	else if(GetMapInfo()->type == INSTANCE_NULL)
		sInstanceMgr.m_singleMaps[GetMapId()] = NULL;

	// Teleport any left-over players out.
	TeleportPlayers();	

	thread_running = false;
	if(thread_kill_only)
		return false;

	// delete ourselves
	delete this;

	// already deleted, so the threadpool doesn't have to.
	return false;
}
Beispiel #5
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());
		}
	}
}
Beispiel #6
0
bool MapMgr::Do()
{
#ifdef WIN32
	threadid = GetCurrentThreadId();
#endif

	t_currentMapContext.set(this);

	thread_running = true;
	ThreadState.SetVal(THREADSTATE_BUSY);
	SetThreadName("Map mgr - M%u|I%u", this->_mapId , this->m_instanceID);
	ObjectSet::iterator i;
	uint32 last_exec = getMSTime();

	// Create Instance script
	LoadInstanceScript();

	/* create static objects */
	for(GOSpawnList::iterator itr = _map->staticSpawns.GOSpawns.begin(); itr != _map->staticSpawns.GOSpawns.end(); ++itr)
	{
		GameObject* obj = CreateGameObject((*itr)->entry);
		obj->Load((*itr));
		PushStaticObject(obj);
	}

	// Call script OnLoad virtual procedure
	CALL_INSTANCE_SCRIPT_EVENT(this, OnLoad)();

	for(CreatureSpawnList::iterator itr = _map->staticSpawns.CreatureSpawns.begin(); itr != _map->staticSpawns.CreatureSpawns.end(); ++itr)
	{
		Creature* obj = CreateCreature((*itr)->entry);
		obj->Load(*itr, 0, pMapInfo);
		PushStaticObject(obj);
	}

	/* load corpses */
	objmgr.LoadCorpses(this);
	worldstateshandler.InitWorldStates( objmgr.GetWorldStatesForMap( _mapId ) );
	worldstateshandler.setObserver( this );

	// always declare local variables outside of the loop!
	// otherwise there's a lot of sub esp; going on.

	uint32 exec_time, exec_start;

	while((GetThreadState() != THREADSTATE_TERMINATE) && !_shutdown)
	{
		exec_start = getMSTime();

///////////////////////////////////////////// first push to world new objects ////////////////////////////////////////////

		m_objectinsertlock.Acquire();

		if(m_objectinsertpool.size())
		{
			for(i = m_objectinsertpool.begin(); i != m_objectinsertpool.end(); ++i)
			{
				Object* o = *i;

				o->PushToWorld(this);
			}

			m_objectinsertpool.clear();
		}

		m_objectinsertlock.Release();

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		//Now update sessions of this map + objects
		_PerformObjectDuties();

		last_exec = getMSTime();
		exec_time = last_exec - exec_start;
		if(exec_time < MAP_MGR_UPDATE_PERIOD)
		{

			Arcemu::Sleep(MAP_MGR_UPDATE_PERIOD - exec_time);

		}

		//////////////////////////////////////////////////////////////////////////
		// Check if we have to die :P
		//////////////////////////////////////////////////////////////////////////
		if(InactiveMoveTime && UNIXTIME >= InactiveMoveTime)
			break;
	}

	// Teleport any left-over players out.
	TeleportPlayers();

	// Clear the instance's reference to us.
	if(m_battleground)
	{
		BattlegroundManager.DeleteBattleground(m_battleground);
		sInstanceMgr.DeleteBattlegroundInstance(GetMapId(), GetInstanceID());
	}

	if(pInstance)
	{
		// check for a non-raid instance, these expire after 10 minutes.
		if(GetMapInfo()->type == INSTANCE_NONRAID || pInstance->m_isBattleground)
		{
			pInstance->m_mapMgr = NULL;
			sInstanceMgr._DeleteInstance(pInstance, true);
			pInstance = NULL;
		}
		else
		{
			// just null out the pointer
			pInstance->m_mapMgr = NULL;
		}
	}
	else if(GetMapInfo()->type == INSTANCE_NULL)
		sInstanceMgr.m_singleMaps[GetMapId()] = NULL;

	thread_running = false;
	if(thread_kill_only)
		return false;

	// delete ourselves
	delete this;

	// already deleted, so the threadpool doesn't have to.
	return false;
}