I want you to read this very carefully, as it is a nice long process. I will be as specific as I can be with this, so bare with me here. Don't blame me if I miss something. :P
This includes all error fixes.
#1. Configuration Option

Go into World.h and add: CONFIG_CROSSFACTIONBG inside of:

Code:
enum WorldBoolConfigs
Now head into your World.cpp and add:

Code:
m_bool_configs[CONFIG_CROSSFACTIONBG] = sConfigMgr->GetBoolDefault("MixedBGs", true);
Around line #1191 where all the other options are loading.

#2. Player source & header file
We will be doing the Player files. To start, open up Player.h and Player.cpp. Once you have those opened;

Go on line #1061 and above line #1066 add:

Code:
    //CROSSFACION BG START
private:
    bool m_ForgetBGPlayers;
    bool m_ForgetInListPlayers;
public:
    typedef std::vector<uint64> FakePlayers;
    void FitPlayerInTeam(bool action);
    void DoForgetPlayersInList();
    void DoForgetPlayersInBG(Battleground* pBattleGround);
    uint8 GetFakeRaceOrRace();
    void SetForgetBGPlayers(bool tralse) { m_ForgetBGPlayers = tralse; }
    bool ShouldForgetBGPlayers() { return m_ForgetBGPlayers; }
    void SetForgetInListPlayers(bool tralse) { m_ForgetInListPlayers = tralse; }
    bool ShouldForgetInListPlayers() { return m_ForgetInListPlayers; }
    bool SendBattleGroundChat(uint32 msgtype, std::string message);
    void MorphFit(bool value);
    bool TeamIsBGTeam() { return GetBGTeam() == GetTeam(); }
    FakePlayers m_FakePlayers;
    //CROSSFACION BG END
Now go to line #1887 and above that add:

Code:
    TeamId GetBGTeamId() const { return GetBGTeam() == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; }
That should be all of Player.h. Go to Player.cpp..

I guess on any line under a function of your choice add: (In Player.cpp)

Code:
/*####################################################################################
###############################CROSSFACTION BATTLEGROUNDS#############################
####################################################################################*/

void Player::FitPlayerInTeam(bool action)
{
    ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(GetFakeRaceOrRace());
    if(rEntry && !TeamIsBGTeam() && action)
        setFaction(rEntry->FactionID);
    else
        setFactionForRace(getRace());

    if (action)
        SetForgetBGPlayers(true);
    else
        SetForgetInListPlayers(true);

    MorphFit(action);

    if (GetBattleground() && action)
        ChatHandler(GetSession()).PSendSysMessage("You are playing for the %s%s in %s!", GetBGTeam() == ALLIANCE ? "|cff0000FFalliance|r" : "|cffFF0000horde|r", GetBattleground()->GetName());
}

uint8 Player::GetFakeRaceOrRace()
{
    if(!TeamIsBGTeam())
        return GetBGTeam() == ALLIANCE ? RACE_HUMAN : RACE_BLOODELF;
    else
        return getRace();
}

void Player::DoForgetPlayersInList()
{
    // m_FakePlayers is filled from a vector within the battleground
    // they were in previously so all players that have been in that BG will be invalidated.
    for (FakePlayers::const_iterator itr = m_FakePlayers.begin(); itr != m_FakePlayers.end(); ++itr)
    {
        WorldPacket data(SMSG_INVALIDATE_PLAYER, 8);
        data << *itr;
        GetSession()->SendPacket(&data);
        if (Player* pPlayer = ObjectAccessor::FindPlayer(*itr))
            GetSession()->SendNameQueryOpcode(*itr);
    }
    m_FakePlayers.clear();
}

void Player::DoForgetPlayersInBG(Battleground* pBattleGround)
{
    if (!pBattleGround || pBattleGround->isArena())
        return;

    for (Battleground::BattlegroundPlayerMap::const_iterator itr = pBattleGround->GetPlayers().begin(); itr != pBattleGround->GetPlayers().end(); ++itr)
    {
        // Here we invalidate players in the bg to the added player
        WorldPacket data1(SMSG_INVALIDATE_PLAYER, 8);
        data1 << itr->first;
        GetSession()->SendPacket(&data1);
        GetSession()->SendNameQueryOpcode(itr->first);

        if (Player* pPlayer = ObjectAccessor::FindPlayer(itr->first))
        {
            // Here we invalidate the player added to players in the bg
            WorldPacket data2(SMSG_INVALIDATE_PLAYER, 8);
            data2 << GetGUID();
            pPlayer->GetSession()->SendPacket(&data2);
            pPlayer->GetSession()->SendNameQueryOpcode(GetGUID());
        }
    }
}

bool BattlegroundQueue::CheckCrossFactionMatch(BattlegroundBracketId bracket_id, Battleground* bg)
{
    TC_LOG_DEBUG("misc", "BattleGroundQueue::CheckCrossFactionMatch");
    if (bg->isArena())
        return false; // Only do this if crossbg's are enabled.

    // Here we will add all players to selectionpool, later we check if there are enough and launch a bg.
    FillXPlayersToBG(bracket_id, bg, true);

    uint8 MPT = bg->GetMinPlayersPerTeam();
    if (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() < MPT || m_SelectionPools[TEAM_HORDE].GetPlayerCount() < MPT)
    {
        TC_LOG_DEBUG("misc", "Not enough players. Has: %u Need: %u", m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() + m_SelectionPools[TEAM_HORDE].GetPlayerCount(), MPT * 2);
        return false;
    }
    return true;
}

// This function will invite players in the least populated faction, which makes battleground queues much faster.
// This function will return true if cross faction battlegrounds are enabled, otherwise return false,
// which is useful in FillPlayersToBG. Because then we can interrupt the regular invitation if cross faction bg's are enabled.
bool BattlegroundQueue::FillXPlayersToBG(BattlegroundBracketId bracket_id, Battleground* bg, bool start)
{
    if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG))
    {
        int32 aliFree = start ? bg->GetMinPlayersPerTeam() : bg->GetFreeSlotsForTeam(ALLIANCE);
        int32 hordeFree = start ? bg->GetMinPlayersPerTeam() : bg->GetFreeSlotsForTeam(HORDE);
        // Empty selection pools. They will be refilled from queued groups.
        m_SelectionPools[TEAM_ALLIANCE].Init();
        m_SelectionPools[TEAM_HORDE].Init();
        int32 valiFree = aliFree;
        int32 vhordeFree = hordeFree;
        int32 diff = 0;

        TC_LOG_DEBUG("misc", "valiFree: %u vhordeFree: %u", valiFree, vhordeFree);

        for (GroupsQueueType::iterator itr = m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].end(); ++itr)
        {
            if ((*itr)->IsInvitedToBGInstanceGUID)
                continue;

            diff = abs(valiFree - vhordeFree);
            bool moreAli = valiFree < vhordeFree;

            if (diff > 0)
                (*itr)->Team = moreAli ? HORDE : ALLIANCE;

            bool alliance = (*itr)->Team == ALLIANCE;

            if (m_SelectionPools[alliance ? TEAM_ALLIANCE : TEAM_HORDE].AddGroup((*itr), alliance ? aliFree : hordeFree))
            {
                uint8 GSize = (*itr)->Players.size();
                alliance ? valiFree -= GSize : vhordeFree -= GSize;
            }
        }
        return true;
    }
    return false;
}

bool Player::SendBattleGroundChat(uint32 msgtype, std::string message)
{
    float distance = msgtype == CHAT_MSG_SAY ? sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY) : sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL);

    if (Battleground* pBattleGround = GetBattleground())
    {
        for (Battleground::BattlegroundPlayerMap::const_iterator itr = pBattleGround->GetPlayers().begin(); itr != pBattleGround->GetPlayers().end(); ++itr)
        {
            if (Player* pPlayer = ObjectAccessor::FindPlayer(itr->first))
            {
                if (GetDistance2d(pPlayer->GetPositionX(), pPlayer->GetPositionY()) <= distance)
                {
                    if (GetBGTeam() == pPlayer->GetBGTeam())
                    {
                        WorldPacket data;
                        ChatHandler::BuildChatPacket(data, ChatMsg(msgtype), LANG_UNIVERSAL, pPlayer, NULL, message);
                        pPlayer->GetSession()->SendPacket(&data);
                    }
                    else if (msgtype != CHAT_MSG_EMOTE)
                    {
                        WorldPacket data;
                        ChatHandler::BuildChatPacket(data, ChatMsg(msgtype), pPlayer->GetTeam() == ALLIANCE ? LANG_ORCISH : LANG_COMMON, pPlayer, NULL, message);
                        pPlayer->GetSession()->SendPacket(&data);
                    }
                }
            }
        }
        return true;
    }
    else
        return false;
}

void Player::MorphFit(bool value)
{
    if (!TeamIsBGTeam() && value)
    {
        if (GetBGTeam() == ALLIANCE)
        {
            if (getGender() == GENDER_MALE)
            {
                SetDisplayId(19723);
                SetNativeDisplayId(19723);
            }
            else
            {
                SetDisplayId(19724);
                SetNativeDisplayId(19724);
            }
        }
        else
        {
            if (getGender() == GENDER_MALE)
            {
                SetDisplayId(20578);
                SetNativeDisplayId(20578);
            }
            else
            {
                SetDisplayId(20579);
                SetNativeDisplayId(20579);
            }
        }
    }
    else
        InitDisplayIds();
}
#3. Unit.cpp & Handlers


QueryHandler.cpp

In QueryHandler.cpp under SendNameQueryOpcode(uint64 guid), change:

(On line #51)

Code:
data << uint8(nameData->m_race);
to:



Code:
data << uint8(player ? player->GetFakeRaceOrRace() : nameData->m_race);
MiscHandler.cpp

Under void WorldSession::HandleTimeSyncResp(WorldPacket& recvData) add:

Code:
    Battleground* bg = _player->GetBattleground();
    if (bg)
    {
        if (_player->ShouldForgetBGPlayers())
        {
            _player->DoForgetPlayersInBG(bg);
            _player->SetForgetBGPlayers(false);
        }
    }
    else if (_player->ShouldForgetInListPlayers())
    {
        _player->DoForgetPlayersInList();
        _player->SetForgetInListPlayers(false);
    }
Above or below line: #1418

ChatHandler.cpp

Inside of void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) add:

Code:
            if (!GetPlayer()->IsGameMaster())
                if (GetPlayer()->SendBattleGroundChat(type, msg))
                    return;
Above line #251

CharacterHandler.cpp

Inside of void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)

Under line #1031 add:

Code:
    if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG))
    {
        float x = pCurrChar->GetPositionX();
        float y = pCurrChar->GetPositionY();
        float z = pCurrChar->GetPositionZ();
        uint32 hm = pCurrChar->m_homebindMapId;
        float hx = pCurrChar->m_homebindX;
        float hy = pCurrChar->m_homebindX;
        float hz = pCurrChar->m_homebindX;
        if (z+1 < pCurrChar->GetMap()->GetHeight(x, y, MAX_HEIGHT) && pCurrChar->GetMap()->IsOutdoors(x, y, z))
            pCurrChar->TeleportTo(hm, hx, hy, hz, 0);
    }

    if (pCurrChar->GetBattleground() && !pCurrChar->GetBattleground()->isArena())
        pCurrChar->FitPlayerInTeam(true);
    else
        pCurrChar->FitPlayerInTeam(false);
Unit.cpp

Inside of void Unit::RestoreFaction()

On line #15921, replace:

Code:
ToPlayer()->setFactionForRace(getRace());
with

Code:
ToPlayer()->setFactionForRace(ToPlayer()->GetFakeRaceOrRace());
#4. BattlegroundQueue.cpp & BattlegroundQueue.h


Open BattlegroundQueue.h..

Inside of enum BattlegroundQueueGroupTypes under BG_QUEUE_NORMAL_HORDE = 3, add:

Code:
BG_QUEUE_MIXED              = 4
It should look like this now:

Code:
enum BattlegroundQueueGroupTypes
{
    BG_QUEUE_PREMADE_ALLIANCE = 0,
    BG_QUEUE_PREMADE_HORDE = 1,
    BG_QUEUE_NORMAL_ALLIANCE = 2,
    BG_QUEUE_NORMAL_HORDE = 3,
    BG_QUEUE_MIXED              = 4
};
On line #65 replace #define BG_QUEUE_GROUP_TYPES_COUNT 4 with:

(Just change the 4 to a 5)

Code:
#define BG_QUEUE_GROUP_TYPES_COUNT 5
Now, under line #75 add:

Code:
        bool FillXPlayersToBG(BattlegroundBracketId bracket_id, Battleground* bg, bool start = false);
        bool CheckCrossFactionMatch(BattlegroundBracketId bracket_id, Battleground* bg);
You're done with BattlegroundQueue.h. Open up and go to BattlegroundQueue.cpp..

On line #840, replace:

Code:
        if (CheckNormalMatch(bg_template, bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam)
            || (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam)))
with:

Code:
        if (CheckNormalMatch(bg_template, bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam)
            || (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam))
            || CheckCrossFactionMatch(bracket_id, bg_template))

On line #747, replace:

Code:
    if (m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
        m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty() &&
        m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
        m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty())
        return;
with:

Code:
    if (m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
        m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty() &&
        m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
        m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty() &&
        m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].empty())
        return;
On line #501 add:

Code:
    if (!bg->isArena())
        if (FillXPlayersToBG(bracket_id, bg, false))
            return;
On line #313, replace:

Code:
for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_TEAMS_COUNT)
with:

Code:
for (uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; ++j)
On line #298, replace:

Code:
        TC_LOG_ERROR("bg.battleground", "BattlegroundQueue: couldn't find player %s (GUID: %u)", playerName.c_str(), GUID_LOPART(guid));
with:

Code:
        TC_LOG_DEBUG("bg.battleground", "BattlegroundQueue: couldn't find player %s (GUID: %u)", playerName.c_str(), GUID_LOPART(guid));
READ CAREFULLY:

Inside of GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, BattlegroundTypeId BgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 arenateamid)

On line #143 replace:

Code:
    ginfo->Team                      = leader->GetTeam();
with:

Code:
ginfo->Team                      = leader->GetBGTeam();
Above line #157 add:

Code:
    if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG) && ArenaType == 0)
        index = BG_QUEUE_MIXED;
ON LINE #200 replace:

Code:
            if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(ginfo->BgTypeId))
            {
                char const* bgName = bg->GetName();
                uint32 MinPlayers = bg->GetMinPlayersPerTeam();
                uint32 qHorde = 0;
                uint32 qAlliance = 0;
                uint32 q_min_level = bracketEntry->minLevel;
                uint32 q_max_level = bracketEntry->maxLevel;
                GroupsQueueType::const_iterator itr;
                for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
                    if (!(*itr)->IsInvitedToBGInstanceGUID)
                        qAlliance += (*itr)->Players.size();
                for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
                    if (!(*itr)->IsInvitedToBGInstanceGUID)
                        qHorde += (*itr)->Players.size();

                // Show queue status to player only (when joining queue)
                if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
                {
                    ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_max_level,
                        qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
                }
                // System message
                else
                {
                    sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level,
                        qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
                }
            }
with:

Code:
            if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(ginfo->BgTypeId))
            {
                if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG))
                {
                    char const* bgName = bg->GetName();
                    uint32 MinPlayers = bg->GetMinPlayersPerTeam()*2;
                    uint32 qPlayers = 0;
                    uint32 q_min_level = bracketEntry->minLevel;
                    uint32 q_max_level = bracketEntry->maxLevel;
                    for (GroupsQueueType::const_iterator itr = m_QueuedGroups[bracketId][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_MIXED].end(); ++itr)
                        if (!(*itr)->IsInvitedToBGInstanceGUID)
                            qPlayers += (*itr)->Players.size();

                    if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
                        ChatHandler(leader->GetSession()).PSendSysMessage("Queue status for %s (Lvl: %u to %u) Queued players: %u (Need at least %u more)", bgName, q_min_level, q_max_level, qPlayers, MinPlayers - qPlayers);
                    else
                    {
                        std::ostringstream ss;
                        ss << "|cffff0000[BG Queue Announcer]:|r " << bgName << " -- [" << q_min_level << "-" << q_max_level << "]" << qPlayers << "/" << MinPlayers;
                        sWorld->SendGlobalText(ss.str().c_str(), NULL);
                    } 
                }
                else
                {
                    char const* bgName = bg->GetName();
                    uint32 MinPlayers = bg->GetMinPlayersPerTeam();
                    uint32 qHorde = 0;
                    uint32 qAlliance = 0;
                    uint32 q_min_level = bracketEntry->minLevel;
                    uint32 q_max_level = bracketEntry->maxLevel;
                    GroupsQueueType::const_iterator itr;
                    for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
                        if (!(*itr)->IsInvitedToBGInstanceGUID)
                            qAlliance += (*itr)->Players.size();
                    for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
                        if (!(*itr)->IsInvitedToBGInstanceGUID)
                            qHorde += (*itr)->Players.size();

                    // Show queue status to player only (when joining queue)
                    if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
                    {
                        ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF, bgName, q_min_level, q_max_level,
                            qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
                    }
                    // System message
                    else
                    {
                        sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level,
                            qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
                    }  
                }
            }


And that should be it! Enjoy.


Credits : Tommy


› See More: Written How to setup Crossfaction Battlegrounds