Jump to content

[Patch] Implement account flags & cross-realm DK creation allowance


Recommended Posts

Posted

Scenario:

1: I get a level 55 character on realm X - not on realm Y.

2: I should now be able to create a DK on both realm X and Y - even if I don't have a level 55 on realm Y.

This is how retail does it now (since 3.1.x I think?).

This patch will allow that, through implementing account flags.

diff --git a/src/game/AccountMgr.cpp b/src/game/AccountMgr.cpp
index b3ed91c..9f9a1a1 100644
--- a/src/game/AccountMgr.cpp
+++ b/src/game/AccountMgr.cpp
@@ -188,6 +188,38 @@ bool AccountMgr::GetName(uint32 acc_id, std::string &name)
    return false;
}

+uint32 AccountMgr::GetAccountFlags(uint32 accid) const
+{
+    uint32 res = ACC_FLAG_NONE_SET;
+    if(QueryResult* result = loginDatabase.PQuery("SELECT flag FROM account WHERE id = '%u'", accid))
+        res = (*result)[0].GetUInt32();
+
+    return res;
+}
+
+bool AccountMgr::HasAccountFlag(uint32 accid, AccountFlag flag) const
+{
+    if(QueryResult* result = loginDatabase.PQuery("SELECT flag FROM account WHERE id = '%u'", accid))
+        if((*result)[0].GetUInt32() & flag)
+            return true;
+
+    return false;
+}
+
+void AccountMgr::AddAccountFlag(uint32 accid, AccountFlag flag) const
+{
+    loginDatabase.PExecute("UPDATE account SET flag = flag | '%u' WHERE id = '%u'", flag, accid);
+}
+
+void AccountMgr::DelAccountFlag(uint32 accid, AccountFlag flag) const
+{
+    loginDatabase.PExecute("UPDATE account SET flag = flag &~ '%u' WHERE id = '%u'", flag, accid);
+}
+
+void AccountMgr::SetAccountFlag(uint32 accid, AccountFlag flag) const
+{
+    loginDatabase.PExecute("UPDATE account SET flag = '%u' WHERE id = '%u'", flag, accid);
+}
+
bool AccountMgr::CheckPassword(uint32 accid, std::string passwd)
{
    normilizeString(passwd);
diff --git a/src/game/AccountMgr.h b/src/game/AccountMgr.h
index 86d0931..7aca6fd 100644
--- a/src/game/AccountMgr.h
+++ b/src/game/AccountMgr.h
@@ -33,6 +33,12 @@ enum AccountOpResult
    AOR_DB_INTERNAL_ERROR
};

+enum AccountFlag
+{
+    ACC_FLAG_NONE_SET = 0,
+    ACC_FLAG_CAN_CREATE_HEROIC = 1
+};
+
#define MAX_ACCOUNT_STR 16

class AccountMgr
@@ -50,6 +56,11 @@ class AccountMgr
        uint32 GetId(std::string username);
        uint32 GetSecurity(uint32 acc_id);
        bool GetName(uint32 acc_id, std::string &name);
+        uint32 GetAccountFlags(uint32 accid) const;
+        bool HasAccountFlag(uint32 accid, AccountFlag flag) const;
+        void AddAccountFlag(uint32 accid, AccountFlag flag) const;
+        void DelAccountFlag(uint32 accid, AccountFlag flag) const;
+        void SetAccountFlag(uint32 accid, AccountFlag flag) const;

        static bool normilizeString(std::string& utf8str);
};
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp
index f8bd12d..dedf9bb 100644
--- a/src/game/CharacterHandler.cpp
+++ b/src/game/CharacterHandler.cpp
@@ -37,6 +37,7 @@
#include "Util.h"
#include "ArenaTeam.h"
#include "Language.h"
+#include "AccountMgr.h"

class LoginQueryHolder : public SqlQueryHolder
{
@@ -315,23 +316,11 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
        return;
    }

-    // speedup check for heroic class disabled case
-    uint32 req_level_for_heroic = sWorld.getConfig(CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING);
-    if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
-    {
-        data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT;
-        SendPacket( &data );
-        return;
-    }
-
    bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER;
    uint32 skipCinematics = sWorld.getConfig(CONFIG_SKIP_CINEMATICS);

    bool have_same_race = false;

-    // if 0 then allowed creating without any characters
-    bool have_req_level_for_heroic = (req_level_for_heroic==0);
-
    if(!AllowTwoSideAccounts || skipCinematics == 1 || class_ == CLASS_DEATH_KNIGHT)
    {
        QueryResult *result2 = CharacterDatabase.PQuery("SELECT level,race,class FROM characters WHERE account = '%u' %s",
@@ -358,13 +347,6 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
                        return;
                    }
                }
-
-                if(!have_req_level_for_heroic)
-                {
-                    uint32 acc_level = field[0].GetUInt32();
-                    if(acc_level >= req_level_for_heroic)
-                        have_req_level_for_heroic = true;
-                }
            }

            // need to check team only for first character
@@ -412,20 +394,15 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
                            return;
                        }
                    }
-
-                    if(!have_req_level_for_heroic)
-                    {
-                        uint32 acc_level = field[0].GetUInt32();
-                        if(acc_level >= req_level_for_heroic)
-                            have_req_level_for_heroic = true;
-                    }
                }
            }
            delete result2;
        }
    }

-    if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && !have_req_level_for_heroic)
+    bool can_heroic_db = accmgr.HasAccountFlag(GetAccountId(), ACC_FLAG_CAN_CREATE_HEROIC);
+
+    if(GetSecurity()==SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && !can_heroic_db)
    {
        data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT;
        SendPacket( &data );
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 29456e6..c9bb79c 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -58,6 +58,7 @@
#include "Spell.h"
#include "SocialMgr.h"
#include "AchievementMgr.h"
+#include "AccountMgr.h"

#include <cmath>

@@ -2401,6 +2402,9 @@ void Player::GiveLevel(uint32 level)
        pet->SynchronizeLevelWithOwner();

    GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
+
+    if(level >= sWorld.getConfig(CONFIG_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING))
+        accmgr.AddAccountFlag(GetSession()->GetAccountId(), ACC_FLAG_CAN_CREATE_HEROIC);
}

void Player::InitTalentForLevel()

SQL:

ALTER TABLE account ADD COLUMN flag INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER locale;

EDIT: Patch updated (July 10 00:16 +1 GMT)

EDIT: Patch updated (July 10 01:39 +1 GMT)

EDIT: Patch updated (July 10 15:39 +1 GMT)

EDIT: Patch updated (July 10 19:11 +1 GMT)

EDIT: Patch updated (July 11 13:23 +1 GMT)

Posted

Let me put it like this: Cluttering the table with more and more fields for things like this is pointless, when all we need are account flags. With this, only one field is ever needed.

Posted

1 ) Is code really work as expected? For exampe if you not have anymore 55 level characters at some realm, code will anyway allow create heroic class...

Other note: in current form it too generic.

2) I not see cases when another player or server must know account flags (current) for offline characters.

That why this unneed slownees code with constant so DB access at rwad and any >55 levelup.

More funct just have flags field in WorldSession readed at loading and modify only at new value set IN db if value different from values stored in flags field in WorldSession.

If (1) real problem then use flags impossoble and need count characters that also can be bugged if level modified offline..

Posted
1 ) Is code really work as expected? For exampe if you not have anymore 55 level characters at some realm, code will anyway allow create heroic class...

Does retail really work that way? I have not been able to confirm. But anyway, to really achieve this, we need some sort of intercommunication... Which is hard to realize in C++, without using CORBA or something (see multimangos).

That why this unneed slownees code with constant so DB access at rwad and any >55 levelup.

More funct just have flags field in WorldSession readed at loading and modify only at new value set IN db if value different from values stored in flags field in WorldSession.

So you think I should load value at WorldSession creation and save at player disconnect?
  • 1 year later...
Posted

i know this is one year old, but the patch is still interesting. as Zor said, the field could be used to store informations like account ban.

any chance that anyone will finish this patch? (see vladimirs post #16)

×
×
  • 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