aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorCarbenium <keresztesschmidt@gmail.com>2015-04-05 00:30:02 +0200
committerCarbenium <keresztesschmidt@gmail.com>2015-04-05 01:48:45 +0200
commitd1902b40957c4ce6eb0f20a48d6bb86822d96bd0 (patch)
tree227e36b7f16fde19d3cb8a576464a578a3a268fa /src/server/game/Entities
parent0878a42b7e57c62505b4cd62d9b79b9f767345c6 (diff)
Core/Player: Implement CharSections.dbc and serverside checks
Ported from 6d4c672fb1b799e1888881282e40992a9e15a006 Original work by @ariel-
Diffstat (limited to 'src/server/game/Entities')
-rw-r--r--src/server/game/Entities/Player/Player.cpp77
-rw-r--r--src/server/game/Entities/Player/Player.h1
2 files changed, 76 insertions, 2 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 80990c1ed01..6e3f0841e77 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -948,8 +948,6 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
{
//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(ObjectGuid::Create<HighGuid::Player>(guidlow));
@@ -976,6 +974,13 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
return false;
}
+ if (!ValidateAppearance(createInfo->Race, createInfo->Class, createInfo->Sex, createInfo->HairStyle, createInfo->HairColor, createInfo->Face, createInfo->FacialHairStyle, 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;
+ }
+
SetMap(sMapMgr->CreateMap(info->mapId, this));
uint8 powertype = cEntry->PowerType;
@@ -16649,6 +16654,19 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
SetUInt32Value(PLAYER_FLAGS, fields[11].GetUInt32());
SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fields[44].GetUInt32());
+ 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;
+ }
+
// set which actionbars the client has active - DO NOT REMOVE EVER AGAIN (can be changed though, if it does change fieldwise)
SetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_ACTION_BAR_TOGGLES, fields[58].GetUInt8());
@@ -26525,3 +26543,58 @@ void Player::RemoveSocial()
sSocialMgr->RemovePlayerSocial(GetGUID());
m_social = nullptr;
}
+
+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;
+} \ No newline at end of file
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 098b653574b..1a650c509d6 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1757,6 +1757,7 @@ class Player : public Unit, public GridObject<Player>
static bool IsValidGender(uint8 Gender) { return Gender <= GENDER_FEMALE; }
static bool IsValidClass(uint8 Class) { return ((1 << (Class - 1)) & CLASSMASK_ALL_PLAYABLE) != 0; }
static bool IsValidRace(uint8 Race) { return ((1 << (Race - 1)) & RACEMASK_ALL_PLAYABLE) != 0; }
+ static bool ValidateAppearance(uint8 race, uint8 class_, uint8 gender, uint8 hairID, uint8 hairColor, uint8 faceID, uint8 facialHair, uint8 skinColor, bool create = false);
/*********************************************************/
/*** SAVE SYSTEM ***/