mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-23 18:36:31 +01:00
*Fix an exploit that instance can be reset when there are logged-out players in it.
--HG-- branch : trunk
This commit is contained in:
1
sql/updates/3363_characters_characters.sql
Normal file
1
sql/updates/3363_characters_characters.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE `characters` ADD COLUMN `instance_id` int(11) unsigned NOT NULL default '0' AFTER `map`;
|
||||
@@ -63,7 +63,7 @@ bool LoginQueryHolder::Initialize()
|
||||
|
||||
// NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
|
||||
// !!! NOTE: including unused `zone`,`online`
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points,bgid,bgteam,bgmap,bgx,bgy,bgz,bgo,instance_id FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_mask,stackcount,amount0, amount1, amount2 ,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
|
||||
@@ -112,93 +112,51 @@ void MapInstanced::UnloadAll()
|
||||
*/
|
||||
Map* MapInstanced::GetInstance(const WorldObject* obj)
|
||||
{
|
||||
uint32 CurInstanceId = obj->GetInstanceId();
|
||||
Map* map = NULL;
|
||||
|
||||
if (obj->GetMapId() == GetId() && CurInstanceId != 0)
|
||||
if(obj->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
// the object wants to be put in a certain instance of this map
|
||||
map = _FindMap(CurInstanceId);
|
||||
if(!map)
|
||||
{
|
||||
// For players if the instanceId is set, it's assumed they are already in a map,
|
||||
// hence the map must be loaded. For Creatures, GameObjects etc the map must exist
|
||||
// prior to calling GetMap, they are not allowed to create maps for themselves.
|
||||
sLog.outError("GetInstance: object %s(%d), typeId %d, in world %d, should be in map %d,%d but that's not loaded yet.", obj->GetName(), obj->GetGUIDLow(), obj->GetTypeId(), obj->IsInWorld(), obj->GetMapId(), obj->GetInstanceId());
|
||||
assert(false);
|
||||
}
|
||||
return(map);
|
||||
assert(obj->GetMapId() == GetId() && obj->GetInstanceId());
|
||||
return _FindMap(obj->GetInstanceId());
|
||||
}
|
||||
else
|
||||
|
||||
Player* player = (Player*)obj;
|
||||
uint32 instanceId = player->GetInstanceId();
|
||||
|
||||
if(IsBattleGroundOrArena())
|
||||
{
|
||||
// instance not specified, find an existing or create a new one
|
||||
if(obj->GetTypeId() != TYPEID_PLAYER)
|
||||
{
|
||||
sLog.outError("MAPINSTANCED: WorldObject '%u' (Entry: %u TypeID: %u) is in map %d,%d and requested base map instance of map %d, this must not happen", obj->GetGUIDLow(), obj->GetEntry(), obj->GetTypeId(), obj->GetMapId(), obj->GetInstanceId(), GetId());
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
if(!instanceId)
|
||||
instanceId = player->GetBattleGroundId();
|
||||
|
||||
if(instanceId)
|
||||
return _FindMap(instanceId);
|
||||
else
|
||||
{
|
||||
uint32 NewInstanceId = 0; // instanceId of the resulting map
|
||||
Player* player = (Player*)obj;
|
||||
|
||||
if(IsBattleGroundOrArena())
|
||||
{
|
||||
// instantiate or find existing bg map for player
|
||||
// the instance id is set in battlegroundid
|
||||
NewInstanceId = player->GetBattleGroundId();
|
||||
if(!NewInstanceId)
|
||||
{
|
||||
if(player->GetSession()->PlayerLoading())
|
||||
return NULL;
|
||||
else
|
||||
assert(NewInstanceId);
|
||||
}
|
||||
map = _FindMap(NewInstanceId);
|
||||
if(!map)
|
||||
map = CreateBattleGround(NewInstanceId);
|
||||
return map;
|
||||
}
|
||||
|
||||
InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty());
|
||||
InstanceSave *pSave = pBind ? pBind->save : NULL;
|
||||
|
||||
// the player's permanet player bind is taken into consideration first
|
||||
// then the player's group bind and finally the solo bind.
|
||||
if(!pBind || !pBind->perm)
|
||||
{
|
||||
InstanceGroupBind *groupBind = NULL;
|
||||
Group *group = player->GetGroup();
|
||||
// use the player's difficulty setting (it may not be the same as the group's)
|
||||
if(group && (groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty())))
|
||||
pSave = groupBind->save;
|
||||
}
|
||||
|
||||
if(pSave)
|
||||
{
|
||||
// solo/perm/group
|
||||
NewInstanceId = pSave->GetInstanceId();
|
||||
map = _FindMap(NewInstanceId);
|
||||
// it is possible that the save exists but the map doesn't
|
||||
if(!map)
|
||||
map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty());
|
||||
return map;
|
||||
}
|
||||
else if(!player->GetSession()->PlayerLoading())
|
||||
{
|
||||
// if no instanceId via group members or instance saves is found
|
||||
// the instance will be created for the first time
|
||||
NewInstanceId = MapManager::Instance().GenerateInstanceId();
|
||||
return CreateInstance(NewInstanceId, NULL, player->GetDifficulty());
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog.outError("MAPINSTANCED: Player %s is trying to create instance (MapId %u) when login.", player->GetName(), player->GetMapId());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(instanceId)
|
||||
if(Map *map = _FindMap(instanceId))
|
||||
return map;
|
||||
|
||||
InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty());
|
||||
InstanceSave *pSave = pBind ? pBind->save : NULL;
|
||||
if(!pBind || !pBind->perm)
|
||||
{
|
||||
if(Group *group = player->GetGroup())
|
||||
if(InstanceGroupBind *groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty()))
|
||||
pSave = groupBind->save;
|
||||
}
|
||||
|
||||
if(instanceId && pSave && instanceId != pSave->GetInstanceId())
|
||||
return NULL;
|
||||
|
||||
if(!player->GetSession()->PlayerLoading()) // enter a new map
|
||||
{
|
||||
if(pSave)
|
||||
return CreateInstance(pSave->GetInstanceId(), pSave, pSave->GetDifficulty());
|
||||
else
|
||||
return CreateInstance(MapManager::Instance().GenerateInstanceId(), NULL, player->GetDifficulty());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty)
|
||||
|
||||
@@ -14262,6 +14262,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
uint32 transGUID = fields[24].GetUInt32();
|
||||
Relocate(fields[6].GetFloat(),fields[7].GetFloat(),fields[8].GetFloat(),fields[10].GetFloat());
|
||||
SetMapId(fields[9].GetUInt32());
|
||||
SetInstanceId(fields[41].GetFloat());
|
||||
SetDifficulty(fields[32].GetUInt32()); // may be changed in _LoadGroup
|
||||
|
||||
_LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP));
|
||||
@@ -14473,7 +14474,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
|
||||
// since the player may not be bound to the map yet, make sure subsequent
|
||||
// getmap calls won't create new maps
|
||||
SetInstanceId(map->GetInstanceId());
|
||||
//SetInstanceId(map->GetInstanceId());
|
||||
|
||||
// if the player is in an instance and it has been reset in the meantime teleport him to the entrance
|
||||
if(GetInstanceId() && !sInstanceSaveManager.GetInstanceSave(GetInstanceId()))
|
||||
@@ -15782,7 +15783,7 @@ void Player::SaveToDB()
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "INSERT INTO characters (guid,account,name,race,class,"
|
||||
"map, dungeon_difficulty, position_x, position_y, position_z, orientation, data, "
|
||||
"map, instance_id, dungeon_difficulty, position_x, position_y, position_z, orientation, data, "
|
||||
"taximask, online, cinematic, "
|
||||
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
|
||||
"trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, "
|
||||
@@ -15796,6 +15797,7 @@ void Player::SaveToDB()
|
||||
if(!IsBeingTeleported())
|
||||
{
|
||||
ss << GetMapId() << ", "
|
||||
<< (uint32)GetInstanceId() << ", "
|
||||
<< (uint32)GetDifficulty() << ", "
|
||||
<< finiteAlways(GetPositionX()) << ", "
|
||||
<< finiteAlways(GetPositionY()) << ", "
|
||||
@@ -15805,6 +15807,7 @@ void Player::SaveToDB()
|
||||
else
|
||||
{
|
||||
ss << GetTeleportDest().mapid << ", "
|
||||
<< (uint32)0 << ", "
|
||||
<< (uint32)GetDifficulty() << ", "
|
||||
<< finiteAlways(GetTeleportDest().x) << ", "
|
||||
<< finiteAlways(GetTeleportDest().y) << ", "
|
||||
|
||||
Reference in New Issue
Block a user