[Skills] Fix caps out of bounds issue (#4377)

* wip

* More adjustments
This commit is contained in:
Chris Miles 2024-06-01 16:09:34 -05:00 committed by GitHub
parent 16f21893a3
commit eae05167f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 21 deletions

View File

@ -32,6 +32,7 @@
#include "../../common/repositories/skill_caps_repository.h" #include "../../common/repositories/skill_caps_repository.h"
#include "../../common/file.h" #include "../../common/file.h"
#include "../../common/events/player_event_logs.h" #include "../../common/events/player_event_logs.h"
#include "../../common/skill_caps.h"
EQEmuLogSys LogSys; EQEmuLogSys LogSys;
WorldContentService content_service; WorldContentService content_service;
@ -213,17 +214,16 @@ void ExportSkillCaps(SharedDatabase* db)
return; return;
} }
const uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) { for (uint8 class_id = Class::Warrior; class_id <= Class::Berserker; class_id++) {
for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) { for (uint8 skill_id = EQ::skills::Skill1HBlunt; skill_id <= EQ::skills::Skill2HPiercing; skill_id++) {
if (SkillUsable(db, skill_id, class_id)) { if (SkillUsable(db, skill_id, class_id)) {
uint32 previous_cap = 0; uint32 previous_cap = 0;
for (uint8 level = 1; level <= skill_cap_max_level; level++) {
for (
uint8 level = 1;
level <= SkillCaps::GetSkillCapMaxLevel(class_id, static_cast<EQ::skills::SkillType>(skill_id));
level++
) {
uint32 cap = GetSkill(db, skill_id, class_id, level); uint32 cap = GetSkill(db, skill_id, class_id, level);
if (cap < previous_cap) { if (cap < previous_cap) {
cap = previous_cap; cap = previous_cap;

View File

@ -1,6 +1,15 @@
#include "skill_caps.h" #include "skill_caps.h"
#include "timer.h" #include "timer.h"
// cache the skill cap max level in the database
std::map<uint8_t, int32_t> skill_max_level = {};
uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
SkillCaps *SkillCaps::SetContentDatabase(Database *db) SkillCaps *SkillCaps::SetContentDatabase(Database *db)
{ {
m_content_database = db; m_content_database = db;
@ -8,14 +17,29 @@ SkillCaps *SkillCaps::SetContentDatabase(Database *db)
return this; return this;
} }
int32_t SkillCaps::GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id)
{
// pull the max value defined in the database if it exists
auto it = skill_max_level.find((class_id * 1000000) + skill_id);
if (it != skill_max_level.end()) {
return it->second;
}
return skill_cap_max_level;
}
SkillCapsRepository::SkillCaps SkillCaps::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level) SkillCapsRepository::SkillCaps SkillCaps::GetSkillCap(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level)
{ {
if (!IsPlayerClass(class_id)) { if (!IsPlayerClass(class_id) || static_cast<uint32>(skill_id) > EQ::skills::HIGHEST_SKILL + 1) {
return SkillCapsRepository::NewEntity(); return SkillCapsRepository::NewEntity();
} }
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id); const uint8 max_level = GetSkillCapMaxLevel(class_id, skill_id);
if (level > max_level) {
level = max_level;
}
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
auto pos = m_skill_caps.find(key); auto pos = m_skill_caps.find(key);
if (pos != m_skill_caps.end()) { if (pos != m_skill_caps.end()) {
return pos->second; return pos->second;
@ -34,15 +58,8 @@ uint8 SkillCaps::GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_
return 0; return 0;
} }
const uint8 skill_cap_max_level = (
RuleI(Character, SkillCapMaxLevel) > 0 ?
RuleI(Character, SkillCapMaxLevel) :
RuleI(Character, MaxLevel)
);
const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level; const uint8 max_level = level > skill_cap_max_level ? level : skill_cap_max_level;
const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id); const uint64_t key = (class_id * 1000000) + (level * 1000) + static_cast<uint32>(skill_id);
for (uint8 current_level = 1; current_level <= max_level; current_level++) { for (uint8 current_level = 1; current_level <= max_level; current_level++) {
auto pos = m_skill_caps.find(key); auto pos = m_skill_caps.find(key);
if (pos != m_skill_caps.end()) { if (pos != m_skill_caps.end()) {
@ -70,6 +87,23 @@ void SkillCaps::LoadSkillCaps()
const uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id; const uint64_t key = (e.class_id * 1000000) + (e.level * 1000) + e.skill_id;
m_skill_caps[key] = e; m_skill_caps[key] = e;
const int max_level_key = (e.class_id * 1000000) + e.skill_id;
auto it = skill_max_level.find(max_level_key);
if (it != skill_max_level.end()) {
// Key found, update the value if the new level is higher
if (e.level > it->second) {
it->second = e.level;
}
// we never want to exceed the defined rule skill cap max level
if (it->second > skill_cap_max_level) {
it->second = skill_cap_max_level;
}
}
else {
// Key not found, insert the new key-value pair
skill_max_level[max_level_key] = e.level;
}
} }
LogInfo( LogInfo(

View File

@ -13,6 +13,7 @@ public:
uint8 GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level); uint8 GetSkillTrainLevel(uint8 class_id, EQ::skills::SkillType skill_id, uint8 level);
void LoadSkillCaps(); void LoadSkillCaps();
void ReloadSkillCaps(); void ReloadSkillCaps();
static int32_t GetSkillCapMaxLevel(uint8 class_id, EQ::skills::SkillType skill_id);
SkillCaps *SetContentDatabase(Database *db); SkillCaps *SetContentDatabase(Database *db);
private: private: