CPDF_Type3Char* CPDF_Type3Font::LoadChar(uint32_t charcode, int level) { if (level >= _FPDF_MAX_TYPE3_FORM_LEVEL_) return nullptr; auto it = m_CacheMap.find(charcode); if (it != m_CacheMap.end()) return it->second; const FX_CHAR* name = GetAdobeCharName(m_BaseEncoding, m_pCharNames, charcode); if (!name) return nullptr; CPDF_Stream* pStream = ToStream(m_pCharProcs ? m_pCharProcs->GetDirectObjectBy(name) : nullptr); if (!pStream) return nullptr; std::unique_ptr<CPDF_Type3Char> pNewChar(new CPDF_Type3Char(new CPDF_Form( m_pDocument, m_pFontResources ? m_pFontResources : m_pPageResources, pStream, nullptr))); // This can trigger recursion into this method. The content of |m_CacheMap| // can change as a result. Thus after it returns, check the cache again for // a cache hit. pNewChar->m_pForm->ParseContent(nullptr, nullptr, pNewChar.get(), level + 1); it = m_CacheMap.find(charcode); if (it != m_CacheMap.end()) return it->second; FX_FLOAT scale = m_FontMatrix.GetXUnit(); pNewChar->m_Width = (int32_t)(pNewChar->m_Width * scale + 0.5f); FX_RECT& rcBBox = pNewChar->m_BBox; CFX_FloatRect char_rect( (FX_FLOAT)rcBBox.left / 1000.0f, (FX_FLOAT)rcBBox.bottom / 1000.0f, (FX_FLOAT)rcBBox.right / 1000.0f, (FX_FLOAT)rcBBox.top / 1000.0f); if (rcBBox.right <= rcBBox.left || rcBBox.bottom >= rcBBox.top) char_rect = pNewChar->m_pForm->CalcBoundingBox(); char_rect.Transform(&m_FontMatrix); rcBBox.left = FXSYS_round(char_rect.left * 1000); rcBBox.right = FXSYS_round(char_rect.right * 1000); rcBBox.top = FXSYS_round(char_rect.top * 1000); rcBBox.bottom = FXSYS_round(char_rect.bottom * 1000); ASSERT(!pdfium::ContainsKey(m_CacheMap, charcode)); CPDF_Type3Char* pCachedChar = pNewChar.release(); m_CacheMap[charcode] = pCachedChar; if (pCachedChar->m_pForm->GetPageObjectList()->empty()) pCachedChar->m_pForm.reset(); return pCachedChar; }
void WorldSession::HandleCharCreateOpcode(WorldPacket& recv_data) { std::string name; uint8 race_, class_; recv_data >> name; recv_data >> race_; recv_data >> class_; // extract other data required for player creating uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; recv_data >> gender >> skin >> face; recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases if (GetSecurity() == SEC_PLAYER) { if (uint32 mask = sWorld.getConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED)) { bool disabled = false; Team team = Player::TeamForRace(race_); switch (team) { case ALLIANCE: disabled = mask & (1 << 0); break; case HORDE: disabled = mask & (1 << 1); break; default: break; } if (disabled) { data << (uint8)CHAR_CREATE_DISABLED; SendPacket(&data); return; } } } ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); if (!classEntry || !raceEntry) { data << (uint8)CHAR_CREATE_FAILED; SendPacket(&data); sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_); return; } // prevent character creating with invalid name if (!normalizePlayerName(name)) { data << (uint8)CHAR_NAME_NO_NAME; SendPacket(&data); sLog.outError("Account:[%d] but tried to Create character with empty [name]", GetAccountId()); return; } // check name limitations uint8 res = ObjectMgr::CheckPlayerName(name, true); if (res != CHAR_NAME_SUCCESS) { data << uint8(res); SendPacket(&data); return; } if (GetSecurity() == SEC_PLAYER && sObjectMgr.IsReservedName(name)) { data << (uint8)CHAR_NAME_RESERVED; SendPacket(&data); return; } if (sAccountMgr.GetPlayerGuidByName(name)) { data << (uint8)CHAR_CREATE_NAME_IN_USE; SendPacket(&data); return; } if (sAccountMgr.GetCharactersCount(GetAccountId(), true) >= sWorld.getConfig(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT)) { data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT; SendPacket(&data); return; } else if (sAccountMgr.GetCharactersCount(GetAccountId(), false) >= sWorld.getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM)) { data << (uint8)CHAR_CREATE_SERVER_LIMIT; SendPacket(&data); return; } bool AllowTwoSideAccounts = sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER; CinematicsSkipMode skipCinematics = CinematicsSkipMode(sWorld.getConfig(CONFIG_UINT32_SKIP_CINEMATICS)); bool have_same_race = false; if (!AllowTwoSideAccounts || skipCinematics == CINEMATICS_SKIP_SAME_RACE) { QueryResult* result2 = CharacterDatabase.PQuery("SELECT level,race,class FROM characters WHERE account = '%u' %s", GetAccountId(), (skipCinematics == CINEMATICS_SKIP_SAME_RACE) ? "" : "LIMIT 1"); if (result2) { Team team_ = Player::TeamForRace(race_); Field* field = result2->Fetch(); uint8 acc_race = field[1].GetUInt32(); // need to check team only for first character // TODO: what to if account already has characters of both races? if (!AllowTwoSideAccounts) { if (acc_race == 0 || Player::TeamForRace(acc_race) != team_) { data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION; SendPacket(&data); delete result2; return; } } // search same race for cinematic or same class if need // TODO: check if cinematic already shown? (already logged in?; cinematic field) while ((skipCinematics == CINEMATICS_SKIP_SAME_RACE && !have_same_race)) { if (!result2->NextRow()) break; field = result2->Fetch(); acc_race = field[1].GetUInt32(); if (!have_same_race) have_same_race = race_ == acc_race; } delete result2; } } Player pNewChar(this); if (!pNewChar.Create(sObjectMgr.GeneratePlayerLowGuid(), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId)) { // Player not create (race/class problem?) data << (uint8)CHAR_CREATE_ERROR; SendPacket(&data); return; } if ((have_same_race && skipCinematics == CINEMATICS_SKIP_SAME_RACE) || skipCinematics == CINEMATICS_SKIP_ALL) pNewChar.setCinematic(1); // not show intro pNewChar.SetAtLoginFlag(AT_LOGIN_FIRST); // First login // Player created, save it now pNewChar.SaveToDB(); sAccountMgr.UpdateCharactersCount(GetAccountId(), sWorld.getConfig(CONFIG_UINT32_REALMID)); data << (uint8)CHAR_CREATE_SUCCESS; SendPacket(&data); std::string IP_str = GetRemoteAddress(); BASIC_LOG("Account: %d (IP: %s) Create Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar.GetGUIDLow()); sLog.outChar("Account: %d (IP: %s) Create Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar.GetGUIDLow()); }