aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities/Player
diff options
context:
space:
mode:
authorCarbenium <keresztesschmidt@gmail.com>2015-04-05 00:09:03 +0200
committerCarbenium <keresztesschmidt@gmail.com>2015-04-05 00:09:03 +0200
commitbdc9beacbd5a8e86e57b043fe08cb5d586200407 (patch)
treea7ba31985e4a98400a9407462acdf97fafc59f97 /src/server/game/Entities/Player
parent548aa119ac2884bb1c34f80e2fb077a66bcdfd9f (diff)
parent6d4c672fb1b799e1888881282e40992a9e15a006 (diff)
Merge pull request #13862 from ariel-/pr_tmp
Implement CharSections.dbc and Serverside Checks.
Diffstat (limited to 'src/server/game/Entities/Player')
-rw-r--r--src/server/game/Entities/Player/Player.cpp97
-rw-r--r--src/server/game/Entities/Player/Player.h1
2 files changed, 94 insertions, 4 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 60cadab39fd..9afc8865726 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -964,8 +964,6 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo)
{
//FIXME: outfitId not used in player creating
/// @todo need more checks against packet modifications
- // should check that skin, face, hair* are valid via DBC per race/class
- // also do it in Player::BuildEnumData, Player::LoadFromDB
Object::_Create(guidlow, 0, HIGHGUID_PLAYER);
@@ -1007,6 +1005,13 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo)
return false;
}
+ if (!ValidateAppearance(createInfo->Race, createInfo->Class, createInfo->Gender, createInfo->HairStyle, createInfo->HairColor, createInfo->Face, createInfo->FacialHair, createInfo->Skin, true))
+ {
+ TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with invalid appearance attributes - refusing to do so",
+ GetSession()->GetAccountId(), m_name.c_str());
+ return false;
+ }
+
uint32 RaceClassGender = (createInfo->Race) | (createInfo->Class << 8) | (createInfo->Gender << 16);
SetUInt32Value(UNIT_FIELD_BYTES_0, (RaceClassGender | (powertype << 24)));
@@ -1979,12 +1984,29 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
*data << uint8(gender); // gender
uint32 playerBytes = fields[5].GetUInt32();
+ uint32 playerBytes2 = fields[6].GetUInt32();
+
+ uint16 atLoginFlags = fields[15].GetUInt16();
+
+ if (!ValidateAppearance(uint8(plrRace), uint8(plrClass), gender, uint8(playerBytes >> 16), uint8(playerBytes >> 24), uint8(playerBytes >> 8), uint8(playerBytes2), uint8(playerBytes)))
+ {
+ TC_LOG_ERROR("entities.player.loading", "Player %u has wrong Appearance values (Hair/Skin/Color), forcing recustomize", guid);
+
+ if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE))
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
+ stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE));
+ stmt->setUInt32(1, guid);
+ CharacterDatabase.Execute(stmt);
+ atLoginFlags |= AT_LOGIN_CUSTOMIZE;
+ }
+ }
+
*data << uint8(playerBytes); // skin
*data << uint8(playerBytes >> 8); // face
*data << uint8(playerBytes >> 16); // hair style
*data << uint8(playerBytes >> 24); // hair color
- uint32 playerBytes2 = fields[6].GetUInt32();
*data << uint8(playerBytes2 & 0xFF); // facial hair
*data << uint8(fields[7].GetUInt8()); // level
@@ -1999,7 +2021,6 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
uint32 charFlags = 0;
uint32 playerFlags = fields[14].GetUInt32();
- uint16 atLoginFlags = fields[15].GetUInt16();
if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
charFlags |= CHARACTER_FLAG_HIDE_HELM;
if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
@@ -17292,6 +17313,20 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
SetUInt32Value(PLAYER_BYTES_2, fields[10].GetUInt32());
SetByteValue(PLAYER_BYTES_3, 0, fields[5].GetUInt8());
SetByteValue(PLAYER_BYTES_3, 1, fields[49].GetUInt8());
+
+ if (!ValidateAppearance(
+ fields[3].GetUInt8(), // race
+ fields[4].GetUInt8(), // class
+ gender, GetByteValue(PLAYER_BYTES, 2), // hair type
+ GetByteValue(PLAYER_BYTES, 3), //hair color
+ uint8(fields[9].GetUInt32() >> 8), // face
+ GetByteValue(PLAYER_BYTES_2, 0), // facial hair
+ GetByteValue(PLAYER_BYTES, 0))) // skin color
+ {
+ TC_LOG_ERROR("entities.player", "Player %s has wrong Appearance values (Hair/Skin/Color), can't be loaded.", guid.ToString().c_str());
+ return false;
+ }
+
SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32());
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[48].GetUInt32());
@@ -26947,3 +26982,57 @@ void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell)
GetSession()->SendPacket(&data);
}
+bool Player::ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 hairID, uint8 hairColor, uint8 faceID, uint8 facialHair, uint8 skinColor, bool create /*=false*/)
+{
+ // Check skin color
+ // For Skin type is always 0
+ if (CharSectionsEntry const* entry = GetCharSectionEntry(race, SECTION_TYPE_SKIN, gender, 0, skinColor))
+ { // Skin Color defined as Face color, too, we check skin & face in one pass
+ if (CharSectionsEntry const* entry2 = GetCharSectionEntry(race, SECTION_TYPE_FACE, gender, faceID, skinColor))
+ {
+ // Check DeathKnight exclusive
+ if (((entry->Flags & SECTION_FLAG_DEATH_KNIGHT) || (entry2->Flags & SECTION_FLAG_DEATH_KNIGHT)) && class_ != CLASS_DEATH_KNIGHT)
+ return false;
+ if (create && !((entry->Flags & SECTION_FLAG_PLAYER) && (entry2->Flags & SECTION_FLAG_PLAYER)))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+
+ // These combinations don't have an entry of Type SECTION_TYPE_FACIAL_HAIR, exclude them from that check
+ bool excludeCheck = (race == RACE_TAUREN) || (race == RACE_DRAENEI) || (gender == GENDER_FEMALE && race != RACE_NIGHTELF && race != RACE_UNDEAD_PLAYER);
+
+ // Check Hair
+ if (CharSectionsEntry const* entry = GetCharSectionEntry(race, SECTION_TYPE_HAIR, gender, hairID, hairColor))
+ {
+ if ((entry->Flags & SECTION_FLAG_DEATH_KNIGHT) && class_ != CLASS_DEATH_KNIGHT)
+ return false;
+ if (create && !(entry->Flags & SECTION_FLAG_PLAYER))
+ return false;
+
+ if (!excludeCheck)
+ {
+ if (CharSectionsEntry const* entry2 = GetCharSectionEntry(race, SECTION_TYPE_FACIAL_HAIR, gender, facialHair, hairColor))
+ {
+ if ((entry2->Flags & SECTION_FLAG_DEATH_KNIGHT) && class_ != CLASS_DEATH_KNIGHT)
+ return false;
+ if (create && !(entry2->Flags & SECTION_FLAG_PLAYER))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ // @TODO: Bound checking for facialHair ID (used clientside for markings, tauren beard, etc.)
+ // Not present in DBC
+ }
+ }
+ else
+ return false;
+
+ return true;
+}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 1e928c80f3c..e6ff939d881 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1499,6 +1499,7 @@ class Player : public Unit, public GridObject<Player>
static bool LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid);
static bool IsValidGender(uint8 Gender) { return Gender <= GENDER_FEMALE; }
+ static bool ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 hairID, uint8 hairColor, uint8 faceID, uint8 facialHair, uint8 skinColor, bool create = false);
/*********************************************************/
/*** SAVE SYSTEM ***/