Jump to content

Fake Players on WHO List


Recommended Posts

  • Replies 81
  • Created
  • Last Reply

Top Posters In This Topic

  • 40 years later...

Hey all,

i was wondering if somebody can help me in this part of forum.So i found a arcemu patch for core for fake players in who list and sql code for database.Can somebody help me to transform it for mangos?

fake_online.patch :

Index: src/arcemu-world/Chat.h
===================================================================
--- src/arcemu-world/Chat.h    (revision 3254)
+++ src/arcemu-world/Chat.h    (working copy)
@@ -255,6 +255,7 @@
    bool HandleAnnounceCommand(const char* args, WorldSession *m_session);
    bool HandleGMAnnounceCommand(const char* args, WorldSession *m_session);
    bool HandleWAnnounceCommand(const char* args, WorldSession *m_session);
+    bool HandleFakew(const char* args, WorldSession *m_session);    
    bool HandleGMOnCommand(const char* args, WorldSession *m_session);
    bool HandleGMOffCommand(const char* args, WorldSession *m_session);
    bool HandleGPSCommand(const char* args, WorldSession *m_session);
Index: src/arcemu-world/ChatHandler.cpp
===================================================================
--- src/arcemu-world/ChatHandler.cpp    (revision 3254)
+++ src/arcemu-world/ChatHandler.cpp    (working copy)
@@ -378,11 +378,32 @@
            Player *player = objmgr.GetPlayer(to.c_str(), false);
            if(!player)
            {
-                data = new WorldPacket(SMSG_CHAT_PLAYER_NOT_FOUND, to.length() + 1);
-                *data << to;
+                //data = new WorldPacket(SMSG_CHAT_PLAYER_NOT_FOUND, to.length() + 1);
+                //*data << to;
+
+                QueryResult *result = CharacterDatabase.Query(
+                    "SELECT * FROM fake_players WHERE online=1 and name='%s'", to.c_str());
+                if(!result)
+                {
+                    data = new WorldPacket(SMSG_CHAT_PLAYER_NOT_FOUND, to.length() + 1);
+                    *data << to;
+                    SendPacket(data);
+                    delete data;
+                    return;
+                }
+
+                if(sWorld.announce_output)
+                    sLog.outString("[whisper] %s to *%s*: %s", _player->GetName(), to.c_str(), msg.c_str());
+
+                uint32 fakeuid = result->Fetch()[0].GetInt32() | 0x10000000;
+                //printf("sending fakeuid 0x%x\\n", fakeuid);
+                delete result;
+
+                data = sChatHandler.FillMessageData(CHAT_MSG_WHISPER_INFORM, LANG_UNIVERSAL,msg.c_str(), fakeuid, 0 );
+
                SendPacket(data);
                delete data;
-                break;
+                return;
            }

            // Check that the player isn't a gm with his status on
Index: src/arcemu-world/ConsoleCommands.cpp
===================================================================
--- src/arcemu-world/ConsoleCommands.cpp    (revision 3254)
+++ src/arcemu-world/ConsoleCommands.cpp    (working copy)
@@ -149,6 +149,37 @@
    pConsole->Write("Message sent.\\r\\n");
    return true;
}
+
+bool HandleFakew(BaseConsole * pConsole, int argc, const char * argv[])
+{
+    if(argc < 4) return false;
+
+    LPCSTR source = argv[1];
+    LPCSTR target = argv[2];
+    
+    CHAR msg[1024] = "";
+    for(int i = 3; i < argc; i++)
+        sprintf(msg + strlen(msg), "%s ", argv[i]);
+
+    QueryResult *result = CharacterDatabase.Query(
+        "SELECT * FROM fake_players WHERE online=1 and name='%s'", source);
+    if(!result) return false;
+
+    uint32 fakeuid = result->Fetch()[0].GetInt32() | 0x10000000;
+    delete result;
+
+    Player *player = objmgr.GetPlayer(target, false);
+    if(!player) return false;
+
+    WorldPacket *data = sChatHandler.FillMessageData(CHAT_MSG_WHISPER, LANG_UNIVERSAL, msg, fakeuid, 0 );
+    if(!data) return false;
+
+    player->GetSession()->SendPacket(data);
+    delete data;
+
+    return true;
+}
+
bool HandleWhisperCommand(BaseConsole * pConsole, int argc, const char * argv[])
{
    char pAnnounce[1024];
Index: src/arcemu-world/ConsoleCommands.h
===================================================================
--- src/arcemu-world/ConsoleCommands.h    (revision 3254)
+++ src/arcemu-world/ConsoleCommands.h    (working copy)
@@ -36,6 +36,7 @@
bool HandleShutDownCommand(BaseConsole * pConsole, int argc, const char * argv[]);
bool HandleUnbanAccountCommand(BaseConsole * pConsole, int argc, const char * argv[]);
bool HandleWAnnounceCommand(BaseConsole * pConsole, int argc, const char * argv[]);
+bool HandleFakew(BaseConsole * pConsole, int argc, const char * argv[]);
bool HandleWhisperCommand(BaseConsole * pConsole, int argc, const char * argv[]);
bool HandleNameHashCommand(BaseConsole * pConsole, int argc, const char * argv[]);
bool HandleRevivePlayer(BaseConsole * pConsole, int argc, const char * argv[]);
Index: src/arcemu-world/ConsoleListener.cpp
===================================================================
--- src/arcemu-world/ConsoleListener.cpp    (revision 3254)
+++ src/arcemu-world/ConsoleListener.cpp    (working copy)
@@ -459,6 +459,11 @@
            "wannounce", "<wannounce string>",
            "Shows the message in all client title areas."
        },
+        { 
+            &HandleFakew,
+            "fakew", "<source> <player> <message>", 
+            "Whispers a message to someone from the fake source." 
+        },                
        {
            &HandleWhisperCommand,
            "whisper","<player> <message>",
Index: src/arcemu-world/MiscHandler.cpp
===================================================================
--- src/arcemu-world/MiscHandler.cpp    (revision 3254)
+++ src/arcemu-world/MiscHandler.cpp    (working copy)
@@ -792,6 +792,43 @@
        ++sent_count;
    }
    objmgr._playerslock.ReleaseReadLock();
+
+    ////////////////////////////////////////////////////////////////////////////////////
+
+    QueryResult *result = NULL;
+    
+    if(cname)
+        result = CharacterDatabase.Query("SELECT * FROM fake_players WHERE online=1 and name='%s'", chatname.c_str());
+
+    else if(zone_count)
+        result = CharacterDatabase.Query("SELECT * FROM fake_players WHERE online=1 and zoneid=%u order by name", zones[0]);
+
+    else
+        result = CharacterDatabase.Query("SELECT * FROM fake_players WHERE online=1 order by name");
+
+    if(result)
+    {
+        do
+        {
+            if(sent_count < 49)
+            {
+                data << result->Fetch()[1].GetString();
+                data << result->Fetch()[2].GetString();
+                data << result->Fetch()[3].GetInt32();
+                data << result->Fetch()[4].GetInt32();
+                data << result->Fetch()[5].GetInt32();
+                data << uint8(0);
+                data << result->Fetch()[6].GetInt32();
+
+                ++sent_count;
+            }
+        }
+        while (result->NextRow());
+        delete result;
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////////
+
    data.wpos(0);
    data << sent_count;
    data << sent_count;
Index: src/arcemu-world/QueryHandler.cpp
===================================================================
--- src/arcemu-world/QueryHandler.cpp    (revision 3254)
+++ src/arcemu-world/QueryHandler.cpp    (working copy)
@@ -29,25 +29,51 @@
    uint64 guid;
    recv_data >> guid;

-    PlayerInfo *pn = objmgr.GetPlayerInfo( (uint32)guid );
+    if(guid & 0x10000000)
+    {
+        int32 real_guid = int32(guid) & ~0x10000000;
+        //printf("  its a fake 0x%x, %d\\n", int32(guid), real_guid);
+ 
+        QueryResult *result = CharacterDatabase.Query(
+            "SELECT * FROM fake_players WHERE online=1 and entry=%d", real_guid);
+        if(!result) return;
+ 
+        const char *name = result->Fetch()[1].GetString();
+        //printf("  found %s\\n", name);
+ 
+        WorldPacket data(SMSG_NAME_QUERY_RESPONSE, strlen(name) + 35);
+        data << int32(guid) << uint32(0);    //highguid
+        data << name;
+        data << uint8(0);       // this is a string showed besides players name (eg. in combat log), a custom title ?
+        data << result->Fetch()[5].GetInt32() << int32(0) << result->Fetch()[4].GetInt32();
+//        data << uint8(0);            // 2.4.0, why do i get the feeling blizz is adding custom classes or custom titles? (same thing in who list)
+        SendPacket( &data );

-    if(!pn)
-        return;
+        delete result;
+    }

-    sLog.outDebug( "Received CMSG_NAME_QUERY for: %s", pn->name );
+    else
+    {
+        PlayerInfo *pn = objmgr.GetPlayerInfo( (uint32)guid );

-    WoWGuid pguid((uint64)pn->guid); //VLack: The usual new style guid handling on 3.1.2
-    WorldPacket data(SMSG_NAME_QUERY_RESPONSE, strlen(pn->name) + 35);
-//    data << pn->guid << uint32(0);    //highguid
-    data << pguid << uint8(0); //VLack: usual, new-style guid with an uint8
-    data << pn->name;
-    data << uint8(0);       // this is a string showed besides players name (eg. in combat log), a custom title ?
-    data << uint8(pn->race) << uint8(pn->gender) << uint8(pn->cl);
-//    data << uint8(0);            // 2.4.0, why do i get the feeling blizz is adding custom classes or custom titles? (same thing in who list)
-    data << uint8(0); //VLack: tell the server this name is not declined... (3.1 fix?)
-    SendPacket( &data );
+        if(!pn)
+            return;
+
+            sLog.outDebug( "Received CMSG_NAME_QUERY for: %s", pn->name );
+            WoWGuid pguid((uint64)pn->guid);
+            WorldPacket data(SMSG_NAME_QUERY_RESPONSE, strlen(pn->name) + 35);
+            data << pguid << uint8(0); //VLack: usual, new-style guid with an uint8
+            data << pn->name;
+            data << uint8(0);       // this is a string showed besides players name (eg. in combat log), a custom title ?
+            data << uint8(pn->race) << uint8(pn->gender) << uint8(pn->cl);
+        //    data << uint8(0);            // 2.4.0, why do i get the feeling blizz is adding custom classes or custom titles? (same thing in who list)
+            data << uint8(0); //VLack: tell the server this name is not declined... (3.1 fix?)
+            SendPacket( &data );
+    }
+
}

+
//////////////////////////////////////////////////////////////
/// This function handles CMSG_QUERY_TIME:
//////////////////////////////////////////////////////////////

fake_players.sql

CREATE TABLE `fake_players` (
 `entry` int(11) NOT NULL auto_increment,
 `name` varchar(1024) default NULL,
 `guild` varchar(1024) default NULL,
 `level` int(11) default NULL,
 `classe` int(11) default NULL,
 `race` int(11) default NULL,
 `zoneid` int(11) default NULL,
 `online` int(11) default NULL,
 UNIQUE KEY `entry` (`entry`)
)

Link to comment
Share on other sites

maybe something like this would work

MiscHandler.cpp

@@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )

   QueryResult *result = CharacterDatabase.PQuery("SELECT guid,name,race,class,gender,level,zone,guild FROM fake_characters WHERE online!=0 order by level");

       Field *fields = result->Fetch();

uint32 level_min = fields[5].GetUInt32();
uint32 level_max = fields[5].GetUInt32();
uint32 racemask = fields[2].GetUInt32();
uint32 classmask = fields[3].GetUInt32();
uint32 zones_count = fields[6].GetUInt32();

std::string player_name  = fields[1].GetCppString();
   if(player_name.empty())
       player_name = "Unknown";
   std::string guild_name  = fields[7].GetCppString();
   if(guild_name.empty())
       guild_name = "Unknown";

std::string wplayer_name  = fields[1].GetCppString();
   if(wplayer_name.empty())
       wplayer_name = "Unknown";
   std::string wguild_name  = fields[7].GetCppString();
   if(wguild_name.empty())
       wguild_name = "Unknown";

std::string pname  = fields[1].GetCppString();
   if(pname.empty())
       pname = "Unknown";
   std::string gname  = fields[7].GetCppString();
   if(gname.empty())
       gname = "Unknown";
   std::string wpname  = fields[1].GetCppString();
   if(wpname.empty())
       wpname = "Unknown";
   std::string wgname  = fields[7].GetCppString();
   if(wgname.empty())
       wgname = "Unknown";
   std::string aname  = fields[6].GetCppString();
   if(aname.empty())
       aname = "Unknown";

uint32 race = fields[2].GetUInt32();
uint32 class_ = fields[3].GetUInt32();
uint32 lvl = fields[5].GetUInt32();
uint32 pzoneid = fields[6].GetUInt32();

       data << pname;                                      // player name
       data << gname;                                      // guild name
       data << uint32( lvl );                              // player level
       data << uint32( class_ );                           // player class
       data << uint32( race );                             // player race
       data << uint8(0);                                   // new 2.4.0
       data << uint32( pzoneid );                          // player zone id

ofc this is not complete patch

Link to comment
Share on other sites

I think there is a easy way for this , change this

QueryResult *result = CharacterDatabase.PQuery("SELECT guid,name,race,class,gender,level,zone,guild FROM fake_characters WHERE online=1 order by level");

to

 QueryResult *result = CharacterDatabase.PQuery("SELECT guid,name,race,class,gender,level,zone,guild FROM characters WHERE online=1 AND online=2 order by level");

now you just need modify online in database to "2" and you dnt need to create fake characters . But maybe this modification need improvment (login phase check,logout phase).

OR

 QueryResult *result = CharacterDatabase.PQuery("SELECT guid,name,race,class,gender,level,zone,guild FROM characters WHERE online!=0 order by level");

But with this solution you just need modify sql query and database . :D

Link to comment
Share on other sites

still I dont know if this is gonna work because of

HashMapHolder<Player>::MapType& m = sObjectAccessor.GetPlayers();
   for(HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)

test it before and if it dosnt work he just need a exeption wich jump this code .

Link to comment
Share on other sites

here is my first attempt, I haven't tested it, if anyone interested please test...

doesn't require any additional SQL just set online=1 to few chars in your DB

diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index a598130..ef573cc 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -73,169 +73,71 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
    sLog.outDebug( "WORLD: Recvd CMSG_WHO Message" );
    //recv_data.hexlike();

-    uint32 clientcount = 0;
+/*//KICHO: GUILD selection (still in progress - not implemented yet)
+    QueryResult *resultGuild = CharacterDatabase.PQuery("SELECT guildid FROM guild_member WHERE guid IN (SELECT guid FROM characters WHERE online!=0 order by guid)");

-    uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
-    uint32 zoneids[10];                                     // 10 is client limit
-    std::string player_name, guild_name;
+    Field *fields3 = resultGuild->Fetch();
+    
+    std::string guild_name  = fields3[0].GetCppString();
+    std::string wguild_name  = fields3[0].GetCppString();
+    std::string gname  = fields3[0].GetCppString();
+    std::string wgname  = fields3[0].GetCppString();*/

-    recv_data >> level_min;                                 // maximal player level, default 0
-    recv_data >> level_max;                                 // minimal player level, default 100 (MAX_LEVEL)
-    recv_data >> player_name;                               // player name, case sensitive...
-
-    recv_data >> guild_name;                                // guild name, case sensitive...
-
-    recv_data >> racemask;                                  // race mask
-    recv_data >> classmask;                                 // class mask
-    recv_data >> zones_count;                               // zones count, client limit=10 (2.0.10)
-
-    if(zones_count > 10)
-        return;                                             // can't be received from real client or broken packet
-
-    for(uint32 i = 0; i < zones_count; ++i)
-    {
-        uint32 temp;
-        recv_data >> temp;                                  // zone id, 0 if zone is unknown...
-        zoneids[i] = temp;
-        sLog.outDebug("Zone %u: %u", i, zoneids[i]);
-    }
+//KICHO: count "online" players via DB
+    QueryResult *resultClient = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE online!=0");

-    recv_data >> str_count;                                 // user entered strings count, client limit=4 (checked on 2.0.10)
+    Field *fields2 = resultClient->Fetch();

-    if(str_count > 4)
-        return;                                             // can't be received from real client or broken packet
+    uint32 clientcount = fields2[0].GetUInt32();

-    sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
+//KICHO: Get "online" players stats for who list            0      1       2     3     4      5   6
+    QueryResult *result = CharacterDatabase.PQuery("SELECT guid,name,race,class,gender,level,zone FROM characters WHERE guid IN (SELECT guid FROM characters WHERE online!=0 order by name)");

-    std::wstring str[4];                                    // 4 is client limit
-    for(uint32 i = 0; i < str_count; ++i)
-    {
-        std::string temp;
-        recv_data >> temp;                                  // user entered string, it used as universal search pattern(guild+player name)?
+    Field *fields = result->Fetch();

-        if(!Utf8toWStr(temp,str[i]))
-            continue;
+    //KICHO: values taken from query
+    uint32 level_min = fields[5].GetUInt32();
+    uint32 level_max = fields[5].GetUInt32();
+    uint32 racemask = fields[2].GetUInt32();
+    uint32 classmask = fields[3].GetUInt32();
+    uint32 zones_count = fields[6].GetUInt32();

-        wstrToLower(str[i]);
+    std::string player_name  = fields[1].GetCppString();    //player name
+    std::string guild_name  = fields[1].GetCppString();        //guild name (not implemented yet)

-        sLog.outDebug("String %u: %s", i, temp.c_str());
-    }
+    //KICHO: recv_data
+    recv_data >> level_min;                                 // maximal player level, default 0
+    recv_data >> level_max;                                 // minimal player level, default 100 (MAX_LEVEL)
+    recv_data >> player_name;                               // player name, case sensitive...

-    std::wstring wplayer_name;
-    std::wstring wguild_name;
-    if(!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
-        return;
-    wstrToLower(wplayer_name);
-    wstrToLower(wguild_name);
+    recv_data >> guild_name;                                // guild name, case sensitive...

-    // client send in case not set max level value 100 but mangos support 255 max level,
-    // update it to show GMs with characters after 100 level
-    if(level_max >= MAX_LEVEL)
-        level_max = STRONG_MAX_LEVEL;
+    recv_data >> racemask;                                  // race mask
+    recv_data >> classmask;                                 // class mask
+    recv_data >> zones_count;                               // zones count, client limit=10 (2.0.10)

-    uint32 team = _player->GetTeam();
-    uint32 security = GetSecurity();
-    bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST);
-    AccountTypes gmLevelInWhoList = (AccountTypes)sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST);
+    //KICHO: more string values
+    std::string wplayer_name  = fields[1].GetCppString();    //player name
+    std::string wguild_name  = fields[1].GetCppString();    //guild name (not implemented yet)

+    //KICHO: client count packet
    WorldPacket data( SMSG_WHO, 50 );                       // guess size
    data << uint32(clientcount);                            // clientcount place holder, listed count
    data << uint32(clientcount);                            // clientcount place holder, online count

-    // TODO: Guard Player map
-    HashMapHolder<Player>::MapType& m = sObjectAccessor.GetPlayers();
-    for(HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
-    {
-        if (security == SEC_PLAYER)
-        {
-            // player can see member of other team only if CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST
-            if (itr->second->GetTeam() != team && !allowTwoSideWhoList )
-                continue;
+    //KICHO: values taken from query
+    uint32 race = fields[2].GetUInt32();    //player race
+    uint32 class_ = fields[3].GetUInt32();    //player class
+    uint32 lvl = fields[5].GetUInt32();        //player level
+    uint32 pzoneid = fields[6].GetUInt32();    //player in zone

-            // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
-            if (itr->second->GetSession()->GetSecurity() > gmLevelInWhoList)
-                continue;
-        }
-
-        // do not process players which are not in world
-        if(!(itr->second->IsInWorld()))
-            continue;
-
-        // check if target is globally visible for player
-        if (!(itr->second->IsVisibleGloballyFor(_player)))
-            continue;
-
-        // check if target's level is in level range
-        uint32 lvl = itr->second->getLevel();
-        if (lvl < level_min || lvl > level_max)
-            continue;
-
-        // check if class matches classmask
-        uint32 class_ = itr->second->getClass();
-        if (!(classmask & (1 << class_)))
-            continue;
-
-        // check if race matches racemask
-        uint32 race = itr->second->getRace();
-        if (!(racemask & (1 << race)))
-            continue;
-
-        uint32 pzoneid = itr->second->GetZoneId();
-
-        bool z_show = true;
-        for(uint32 i = 0; i < zones_count; ++i)
-        {
-            if(zoneids[i] == pzoneid)
-            {
-                z_show = true;
-                break;
-            }
-
-            z_show = false;
-        }
-        if (!z_show)
-            continue;
-
-        std::string pname = itr->second->GetName();
-        std::wstring wpname;
-        if(!Utf8toWStr(pname,wpname))
-            continue;
-        wstrToLower(wpname);
-
-        if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
-            continue;
-
-        std::string gname = sObjectMgr.GetGuildNameById(itr->second->GetGuildId());
-        std::wstring wgname;
-        if(!Utf8toWStr(gname,wgname))
-            continue;
-        wstrToLower(wgname);
-
-        if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
-            continue;
-
-        std::string aname;
-        if(AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
-            aname = areaEntry->area_name[GetSessionDbcLocale()];
-
-        bool s_show = true;
-        for(uint32 i = 0; i < str_count; ++i)
-        {
-            if (!str[i].empty())
-            {
-                if (wgname.find(str[i]) != std::wstring::npos ||
-                    wpname.find(str[i]) != std::wstring::npos ||
-                    Utf8FitTo(aname, str[i]) )
-                {
-                    s_show = true;
-                    break;
-                }
-                s_show = false;
-            }
-        }
-        if (!s_show)
-            continue;
+    //KICHO: more string values
+    std::string pname  = fields[1].GetCppString();    //player name
+    std::string gname  = fields[1].GetCppString();    //guild name (not implemented yet)
+    std::string wpname  = fields[1].GetCppString();    //player name
+    std::string wgname  = fields[1].GetCppString();    //guild name (not implemented yet)

+    //KICHO: sending data from query
        data << pname;                                      // player name
        data << gname;                                      // guild name
        data << uint32( lvl );                              // player level
@@ -244,14 +146,9 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
        data << uint8(0);                                   // new 2.4.0
        data << uint32( pzoneid );                          // player zone id

-        // 50 is maximum player count sent to client
-        if ((++clientcount) == 50)
-            break;
-    }

-    uint32 count = m.size();
-    data.put( 0, clientcount );                             // insert right count, listed count
-    data.put( 4, count > 50 ? count : clientcount );        // insert right count, online count
+    data.put( 0, clientcount );        // insert right count, listed count
+    data.put( 4, clientcount );        // insert right count, online count

    SendPacket(&data);
    sLog.outDebug( "WORLD: Send SMSG_WHO Message" );

Link to comment
Share on other sites

seems like all files got deleted - reuploaded

here is my first attempt, I haven't tested it, if anyone interested please test...

doesn't require any additional SQL just set online=1 to few chars in your DB

diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index a598130..ef573cc 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -73,169 +73,71 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
    sLog.outDebug( "WORLD: Recvd CMSG_WHO Message" );
    //recv_data.hexlike();

-    uint32 clientcount = 0;
+/*//KICHO: GUILD selection (still in progress - not implemented yet)
+    QueryResult *resultGuild = CharacterDatabase.PQuery("SELECT guildid FROM guild_member WHERE guid IN (SELECT guid FROM characters WHERE online!=0 order by guid)");

-    uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
-    uint32 zoneids[10];                                     // 10 is client limit
-    std::string player_name, guild_name;
+    Field *fields3 = resultGuild->Fetch();
+    
+    std::string guild_name  = fields3[0].GetCppString();
+    std::string wguild_name  = fields3[0].GetCppString();
+    std::string gname  = fields3[0].GetCppString();
+    std::string wgname  = fields3[0].GetCppString();*/

-    recv_data >> level_min;                                 // maximal player level, default 0
-    recv_data >> level_max;                                 // minimal player level, default 100 (MAX_LEVEL)
-    recv_data >> player_name;                               // player name, case sensitive...
-
-    recv_data >> guild_name;                                // guild name, case sensitive...
-
-    recv_data >> racemask;                                  // race mask
-    recv_data >> classmask;                                 // class mask
-    recv_data >> zones_count;                               // zones count, client limit=10 (2.0.10)
-
-    if(zones_count > 10)
-        return;                                             // can't be received from real client or broken packet
-
-    for(uint32 i = 0; i < zones_count; ++i)
-    {
-        uint32 temp;
-        recv_data >> temp;                                  // zone id, 0 if zone is unknown...
-        zoneids[i] = temp;
-        sLog.outDebug("Zone %u: %u", i, zoneids[i]);
-    }
+//KICHO: count "online" players via DB
+    QueryResult *resultClient = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE online!=0");

-    recv_data >> str_count;                                 // user entered strings count, client limit=4 (checked on 2.0.10)
+    Field *fields2 = resultClient->Fetch();

-    if(str_count > 4)
-        return;                                             // can't be received from real client or broken packet
+    uint32 clientcount = fields2[0].GetUInt32();

-    sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
+//KICHO: Get "online" players stats for who list            0      1       2     3     4      5   6
+    QueryResult *result = CharacterDatabase.PQuery("SELECT guid,name,race,class,gender,level,zone FROM characters WHERE guid IN (SELECT guid FROM characters WHERE online!=0 order by guid)");

-    std::wstring str[4];                                    // 4 is client limit
-    for(uint32 i = 0; i < str_count; ++i)
-    {
-        std::string temp;
-        recv_data >> temp;                                  // user entered string, it used as universal search pattern(guild+player name)?
+    Field *fields = result->Fetch();

-        if(!Utf8toWStr(temp,str[i]))
-            continue;
+    //KICHO: values taken from query
+    uint32 level_min = fields[5].GetUInt32();
+    uint32 level_max = fields[5].GetUInt32();
+    uint32 racemask = fields[2].GetUInt32();
+    uint32 classmask = fields[3].GetUInt32();
+    uint32 zones_count = fields[6].GetUInt32();

-        wstrToLower(str[i]);
+    std::string player_name  = fields[1].GetCppString();    //player name
+    std::string guild_name  = fields[1].GetCppString();        //guild name (not implemented yet)

-        sLog.outDebug("String %u: %s", i, temp.c_str());
-    }
+    //KICHO: recv_data
+    recv_data >> level_min;                                 // maximal player level, default 0
+    recv_data >> level_max;                                 // minimal player level, default 100 (MAX_LEVEL)
+    recv_data >> player_name;                               // player name, case sensitive...

-    std::wstring wplayer_name;
-    std::wstring wguild_name;
-    if(!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
-        return;
-    wstrToLower(wplayer_name);
-    wstrToLower(wguild_name);
+    recv_data >> guild_name;                                // guild name, case sensitive...

-    // client send in case not set max level value 100 but mangos support 255 max level,
-    // update it to show GMs with characters after 100 level
-    if(level_max >= MAX_LEVEL)
-        level_max = STRONG_MAX_LEVEL;
+    recv_data >> racemask;                                  // race mask
+    recv_data >> classmask;                                 // class mask
+    recv_data >> zones_count;                               // zones count, client limit=10 (2.0.10)

-    uint32 team = _player->GetTeam();
-    uint32 security = GetSecurity();
-    bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST);
-    AccountTypes gmLevelInWhoList = (AccountTypes)sWorld.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST);
+    //KICHO: more string values
+    std::string wplayer_name  = fields[1].GetCppString();    //player name
+    std::string wguild_name  = fields[1].GetCppString();    //guild name (not implemented yet)

+    //KICHO: client count packet
    WorldPacket data( SMSG_WHO, 50 );                       // guess size
    data << uint32(clientcount);                            // clientcount place holder, listed count
    data << uint32(clientcount);                            // clientcount place holder, online count

-    // TODO: Guard Player map
-    HashMapHolder<Player>::MapType& m = sObjectAccessor.GetPlayers();
-    for(HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
-    {
-        if (security == SEC_PLAYER)
-        {
-            // player can see member of other team only if CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST
-            if (itr->second->GetTeam() != team && !allowTwoSideWhoList )
-                continue;
+    //KICHO: values taken from query
+    uint32 race = fields[2].GetUInt32();    //player race
+    uint32 class_ = fields[3].GetUInt32();    //player class
+    uint32 lvl = fields[5].GetUInt32();        //player level
+    uint32 pzoneid = fields[6].GetUInt32();    //player in zone

-            // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
-            if (itr->second->GetSession()->GetSecurity() > gmLevelInWhoList)
-                continue;
-        }
-
-        // do not process players which are not in world
-        if(!(itr->second->IsInWorld()))
-            continue;
-
-        // check if target is globally visible for player
-        if (!(itr->second->IsVisibleGloballyFor(_player)))
-            continue;
-
-        // check if target's level is in level range
-        uint32 lvl = itr->second->getLevel();
-        if (lvl < level_min || lvl > level_max)
-            continue;
-
-        // check if class matches classmask
-        uint32 class_ = itr->second->getClass();
-        if (!(classmask & (1 << class_)))
-            continue;
-
-        // check if race matches racemask
-        uint32 race = itr->second->getRace();
-        if (!(racemask & (1 << race)))
-            continue;
-
-        uint32 pzoneid = itr->second->GetZoneId();
-
-        bool z_show = true;
-        for(uint32 i = 0; i < zones_count; ++i)
-        {
-            if(zoneids[i] == pzoneid)
-            {
-                z_show = true;
-                break;
-            }
-
-            z_show = false;
-        }
-        if (!z_show)
-            continue;
-
-        std::string pname = itr->second->GetName();
-        std::wstring wpname;
-        if(!Utf8toWStr(pname,wpname))
-            continue;
-        wstrToLower(wpname);
-
-        if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
-            continue;
-
-        std::string gname = sObjectMgr.GetGuildNameById(itr->second->GetGuildId());
-        std::wstring wgname;
-        if(!Utf8toWStr(gname,wgname))
-            continue;
-        wstrToLower(wgname);
-
-        if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
-            continue;
-
-        std::string aname;
-        if(AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
-            aname = areaEntry->area_name[GetSessionDbcLocale()];
-
-        bool s_show = true;
-        for(uint32 i = 0; i < str_count; ++i)
-        {
-            if (!str[i].empty())
-            {
-                if (wgname.find(str[i]) != std::wstring::npos ||
-                    wpname.find(str[i]) != std::wstring::npos ||
-                    Utf8FitTo(aname, str[i]) )
-                {
-                    s_show = true;
-                    break;
-                }
-                s_show = false;
-            }
-        }
-        if (!s_show)
-            continue;
+    //KICHO: more string values
+    std::string pname  = fields[1].GetCppString();    //player name
+    std::string gname  = fields[1].GetCppString();    //guild name (not implemented yet)
+    std::string wpname  = fields[1].GetCppString();    //player name
+    std::string wgname  = fields[1].GetCppString();    //guild name (not implemented yet)

+    //KICHO: sending data from query
        data << pname;                                      // player name
        data << gname;                                      // guild name
        data << uint32( lvl );                              // player level
@@ -244,14 +146,9 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
        data << uint8(0);                                   // new 2.4.0
        data << uint32( pzoneid );                          // player zone id

-        // 50 is maximum player count sent to client
-        if ((++clientcount) == 50)
-            break;
-    }

-    uint32 count = m.size();
-    data.put( 0, clientcount );                             // insert right count, listed count
-    data.put( 4, count > 50 ? count : clientcount );        // insert right count, online count
+    data.put( 0, clientcount );        // insert right count, listed count
+    data.put( 4, clientcount );        // insert right count, online count

    SendPacket(&data);
    sLog.outDebug( "WORLD: Send SMSG_WHO Message" );

Link to comment
Share on other sites

I hav'nt test yet your patch but I test a small modification i have just put 1 in field online for 1 real character , I know that this characters will not show in who list but there is as i say a bug , when you try to login the client block on loading characters , I think online = 2 for difference between fake player and true in db and whith online = 2 you can modify properly for loading characters, create just a condition in loading characters part whith sql query for check online = 2 in this case sql query to put online = 0.

Link to comment
Share on other sites

if I get what you mean right...why not just create couple of characters which will not be used by anyone and set online=2 (doesn't have to be 1 just different from 0)

Its a simple possibility to create couple of characters , but the goal is not the simplicity ,you need stuff your fake characters its take more time and at the end , the real player will see that couple of characters are fake because if its all the time the same characters are online and in the same zone (player say : they don't move?),the same level, i think we must choose between simplicity:basic way or difficulty but advanced way . With difficulty way , the fakeplayers are true player so they move zone change ,level change ,stuff change whithout that you lost more time . I will help you as soon as I have time , its a good project :D .

Best regards

Link to comment
Share on other sites

         data << uint8(0);                                   // new 2.4.0
        data << uint32( pzoneid );                          // player zone id

-        // 50 is maximum player count sent to client
-        if ((++clientcount) == 50)
-            break;
-    }

-    uint32 count = m.size();
-    data.put( 0, clientcount );                             // insert right count, listed count
-    data.put( 4, count > 50 ? count : clientcount );        // insert right count, online count
+    data.put( 0, clientcount );        // insert right count, listed count
+    data.put( 4, clientcount );        // insert right count, online count

I think you dnt need change this .

Link to comment
Share on other sites

actually I believe I do since I've only declared clientcount

QueryResult *resultClient = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE online!=0");

   Field *fields2 = resultClient->Fetch();

   uint32 clientcount = fields2[0].GetUInt32();

Link to comment
Share on other sites

Its a simple possibility to create couple of characters , but the goal is not the simplicity ,you need stuff your fake characters its take more time and at the end , the real player will see that couple of characters are fake because if its all the time the same characters are online and in the same zone (player say : they don't move?),the same level, i think we must choose between simplicity:basic way or difficulty but advanced way . With difficulty way , the fakeplayers are true player so they move zone change ,level change ,stuff change whithout that you lost more time . I will help you as soon as I have time , its a good project :D .

Best regards

maybe something like this should work ? but needs more work or it will corrupt DB

WorldSession.cpp

//No SQL injection as AccountId is uint32
-        CharacterDatabase.PExecute("UPDATE characters SET online = 0  WHERE account = '%u'",
+        CharacterDatabase.PExecute("UPDATE characters SET online = 2 WHERE account = '%u'",
           GetAccountId());
       DEBUG_LOG( "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" );

Link to comment
Share on other sites

WorldSession.cpp

//No SQL injection as AccountId is uint32
-        CharacterDatabase.PExecute("UPDATE characters SET online = 0  WHERE account = '%u'",
+        CharacterDatabase.PExecute("UPDATE characters SET online = 2 WHERE account = '%u'",
           GetAccountId());
       DEBUG_LOG( "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" );

I think , the loading part is in characterHandler.cpp more precisly in player.cpp:

bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
{
   //             0               1                2                3                 4                  5                       6                        7
   //    "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
   //     8                9               10                     11                     12                     13                    14
   //    "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
   //    15                    16                   17                     18                   19                         20
   //    "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, character_declinedname.genitive "

   Field *fields = result->Fetch();

   uint32 guid = fields[0].GetUInt32();
   uint8 pRace = fields[2].GetUInt8();
   uint8 pClass = fields[3].GetUInt8();

   PlayerInfo const *info = sObjectMgr.GetPlayerInfo(pRace, pClass);
   if(!info)
   {
       sLog.outError("Player %u has incorrect race/class pair. Don't build enum.", guid);
       return false;
   }

   *p_data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
   *p_data << fields[1].GetString();                       // name
   *p_data << uint8(pRace);                                // race
   *p_data << uint8(pClass);                               // class
   *p_data << uint8(fields[4].GetUInt8());                 // gender

   uint32 playerBytes = fields[5].GetUInt32();
   *p_data << uint8(playerBytes);                          // skin
   *p_data << uint8(playerBytes >> 8);                     // face
   *p_data << uint8(playerBytes >> 16);                    // hair style
   *p_data << uint8(playerBytes >> 24);                    // hair color

   uint32 playerBytes2 = fields[6].GetUInt32();
   *p_data << uint8(playerBytes2 & 0xFF);                  // facial hair

   *p_data << uint8(fields[7].GetUInt8());                 // level
   *p_data << uint32(fields[8].GetUInt32());               // zone
   *p_data << uint32(fields[9].GetUInt32());               // map

   *p_data << fields[10].GetFloat();                       // x
   *p_data << fields[11].GetFloat();                       // y
   *p_data << fields[12].GetFloat();                       // z

   *p_data << uint32(fields[13].GetUInt32());              // guild id

   uint32 char_flags = 0;
   uint32 playerFlags = fields[14].GetUInt32();
   uint32 atLoginFlags = fields[15].GetUInt32();
   if(playerFlags & PLAYER_FLAGS_HIDE_HELM)
       char_flags |= CHARACTER_FLAG_HIDE_HELM;
   if(playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
       char_flags |= CHARACTER_FLAG_HIDE_CLOAK;
   if(playerFlags & PLAYER_FLAGS_GHOST)
       char_flags |= CHARACTER_FLAG_GHOST;
   if(atLoginFlags & AT_LOGIN_RENAME)
       char_flags |= CHARACTER_FLAG_RENAME;
   if(sWorld.getConfig(CONFIG_BOOL_DECLINED_NAMES_USED))
   {
       if(!fields[20].GetCppString().empty())
           char_flags |= CHARACTER_FLAG_DECLINED;
   }
   else
       char_flags |= CHARACTER_FLAG_DECLINED;

   *p_data << uint32(char_flags);                          // character flags
   // character customize flags
   *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? CHAR_CUSTOMIZE_FLAG_CUSTOMIZE : CHAR_CUSTOMIZE_FLAG_NONE);
   // First login
   *p_data << uint8(atLoginFlags & AT_LOGIN_FIRST ? 1 : 0);

   // Pets info
   {
       uint32 petDisplayId = 0;
       uint32 petLevel   = 0;
       uint32 petFamily  = 0;

       // show pet at selection character in character list only for non-ghost character
       if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT))
       {
           uint32 entry = fields[16].GetUInt32();
           CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry);
           if(cInfo)
           {
               petDisplayId = fields[17].GetUInt32();
               petLevel     = fields[18].GetUInt32();
               petFamily    = cInfo->family;
           }
       }

       *p_data << uint32(petDisplayId);
       *p_data << uint32(petLevel);
       *p_data << uint32(petFamily);
   }


   Tokens data = StrSplit(fields[19].GetCppString(), " ");
   for (uint8 slot = 0; slot < EQUIPMENT_SLOT_END; slot++)
   {
       uint32 visualbase = slot * 2;
       uint32 item_id = GetUInt32ValueFromArray(data, visualbase);
       const ItemPrototype * proto = ObjectMgr::GetItemPrototype(item_id);
       if(!proto)
       {
           *p_data << uint32(0);
           *p_data << uint8(0);
           *p_data << uint32(0);
           continue;
       }

       SpellItemEnchantmentEntry const *enchant = NULL;

       uint32 enchants = GetUInt32ValueFromArray(data, visualbase + 1);
       for(uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
       {
           // values stored in 2 uint16
           uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot*16);
           if(!enchantId)
               continue;

           if ((enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId)))
               break;
       }

       *p_data << uint32(proto->DisplayInfoID);
       *p_data << uint8(proto->InventoryType);
       *p_data << uint32(enchant ? enchant->aura_id : 0);
   }

   *p_data << uint32(0);                                   // bag 1 display id
   *p_data << uint8(0);                                    // bag 1 inventory type
   *p_data << uint32(0);                                   // enchant?
   *p_data << uint32(0);                                   // bag 2 display id
   *p_data << uint8(0);                                    // bag 2 inventory type
   *p_data << uint32(0);                                   // enchant?
   *p_data << uint32(0);                                   // bag 3 display id
   *p_data << uint8(0);                                    // bag 3 inventory type
   *p_data << uint32(0);                                   // enchant?
   *p_data << uint32(0);                                   // bag 4 display id
   *p_data << uint8(0);                                    // bag 4 inventory type
   *p_data << uint32(0);                                   // enchant?

   return true;
}

You need analyse the code and insert into the sql query in top, online check then a condition for characters whith online='2' to set '0' .The better spot is just after the sql SELECT query and fetch array , just check if the field online is '2' set to '0' and continue .

Link to comment
Share on other sites

I have found for you the sql query, you need just insert online field in the two sql query (declined name and whithout):

In characterHandler.cpp

void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ )
{
   /// get all the data necessary for loading all characters (along with their pets) on the account
   CharacterDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnumCallback, GetAccountId(),
        !sWorld.getConfig(CONFIG_BOOL_DECLINED_NAMES_USED) ?
   //   ------- Query Without Declined Names --------
   //           0               1                2                3                 4                  5                       6                        7
       "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
   //   8                9               10                     11                     12                     13                    14
       "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
   //  15                    16                   17                     18                   19
       "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache "
       "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' "
       "LEFT JOIN guild_member ON characters.guid = guild_member.guid "
       "WHERE characters.account = '%u' ORDER BY characters.guid"
       :
   //   --------- Query With Declined Names ---------
   //           0               1                2                3                 4                  5                       6                        7
       "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
   //   8                9               10                     11                     12                     13                    14
       "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
   //  15                    16                   17                     18                   19                         20
       "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, character_declinedname.genitive "
       "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' "
       "LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid "
       "LEFT JOIN guild_member ON characters.guid = guild_member.guid "
       "WHERE characters.account = '%u' ORDER BY characters.guid",
       PET_SAVE_AS_CURRENT, GetAccountId());
}

After add a condition (if online = 2 set to 0) in the void bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) in player.cpp as i say in the reply above.

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use