mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-28 13:27:15 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b65dd3a00 | |||
| aa8b0570d6 | |||
| 4493ebebab | |||
| 77793f364e | |||
| e258aaa068 | |||
| 3b779ef301 | |||
| 3f3c0f2fda | |||
| 0f164c456e | |||
| 6172c49b08 | |||
| 66a7dd0143 | |||
| 5c6e7a8b09 | |||
| bd85fc96a0 | |||
| 8e40e5357c | |||
| 5f0b999ca9 | |||
| fe9df46a24 | |||
| 3d7cf4235c | |||
| 187ee10218 | |||
| 6bd758b3dd | |||
| 9938755517 | |||
| 630da0eee6 | |||
| 3158386aa3 | |||
| 12ada57ee8 | |||
| 7a841c11c5 | |||
| a49d1446b7 | |||
| b2d0fa6a2f |
@@ -1,3 +1,37 @@
|
|||||||
|
## [22.60.0] 11/25/2024
|
||||||
|
|
||||||
|
### Bazaar
|
||||||
|
|
||||||
|
* Further refinements for instanced bazaar ([#4544](https://github.com/EQEmu/Server/pull/4544)) @neckkola 2024-11-16
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
* Fix build with older C++ libraries ([#4549](https://github.com/EQEmu/Server/pull/4549)) @hgtw 2024-11-24
|
||||||
|
|
||||||
|
### Config
|
||||||
|
|
||||||
|
* Fix World TCP Address Configuration Default ([#4551](https://github.com/EQEmu/Server/pull/4551)) @Akkadius 2024-11-24
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Fix Issue with Perl EVENT_PAYLOAD ([#4545](https://github.com/EQEmu/Server/pull/4545)) @Kinglykrab 2024-11-24
|
||||||
|
* Fix Possible Item Loss in Trades ([#4554](https://github.com/EQEmu/Server/pull/4554)) @Kinglykrab 2024-11-24
|
||||||
|
* Fix Strings::Commify bug with #mystats ([#4547](https://github.com/EQEmu/Server/pull/4547)) @carolus21rex 2024-11-22
|
||||||
|
* Fix an edge case with augmented items inside parceled containers ([#4546](https://github.com/EQEmu/Server/pull/4546)) @neckkola 2024-11-21
|
||||||
|
* Fix for bazaar search of containers. ([#4540](https://github.com/EQEmu/Server/pull/4540)) @neckkola 2024-11-15
|
||||||
|
* Fix for mult-instanced bazaar zones ([#4541](https://github.com/EQEmu/Server/pull/4541)) @neckkola 2024-11-15
|
||||||
|
* Fix for sending money via Parcel, then changing your mind ([#4552](https://github.com/EQEmu/Server/pull/4552)) @neckkola 2024-11-24
|
||||||
|
* Fix issue where NPC's are being hidden as traders ([#4539](https://github.com/EQEmu/Server/pull/4539)) @Akkadius 2024-11-15
|
||||||
|
* Players could become flagged as a Trader when they were not trading ([#4553](https://github.com/EQEmu/Server/pull/4553)) @neckkola 2024-11-24
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
* Add Rule to Disable NPCs Facing Target ([#4543](https://github.com/EQEmu/Server/pull/4543)) @Kinglykrab 2024-11-24
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
* Update tasks in all zones if invalid zone set ([#4550](https://github.com/EQEmu/Server/pull/4550)) @hgtw 2024-11-25
|
||||||
|
|
||||||
## [22.59.1] 11/13/2024
|
## [22.59.1] 11/13/2024
|
||||||
|
|
||||||
### Hotfix
|
### Hotfix
|
||||||
|
|||||||
+28
-20
@@ -8,13 +8,14 @@ std::vector<BazaarSearchResultsFromDB_Struct>
|
|||||||
Bazaar::GetSearchResults(
|
Bazaar::GetSearchResults(
|
||||||
SharedDatabase &db,
|
SharedDatabase &db,
|
||||||
BazaarSearchCriteria_Struct search,
|
BazaarSearchCriteria_Struct search,
|
||||||
uint32 char_zone_id
|
uint32 char_zone_id,
|
||||||
|
int32 char_zone_instance_id
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] "
|
"Searching for items with search criteria - item_name [{}] min_cost [{}] max_cost [{}] min_level [{}] "
|
||||||
"max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] "
|
"max_level [{}] max_results [{}] prestige [{}] augment [{}] trader_entity_id [{}] trader_id [{}] "
|
||||||
"search_scope [{}] char_zone_id [{}]",
|
"search_scope [{}] char_zone_id [{}], char_zone_instance_id [{}]",
|
||||||
search.item_name,
|
search.item_name,
|
||||||
search.min_cost,
|
search.min_cost,
|
||||||
search.max_cost,
|
search.max_cost,
|
||||||
@@ -26,7 +27,8 @@ Bazaar::GetSearchResults(
|
|||||||
search.trader_entity_id,
|
search.trader_entity_id,
|
||||||
search.trader_id,
|
search.trader_id,
|
||||||
search.search_scope,
|
search.search_scope,
|
||||||
char_zone_id
|
char_zone_id,
|
||||||
|
char_zone_instance_id
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string search_criteria_trader("TRUE ");
|
std::string search_criteria_trader("TRUE ");
|
||||||
@@ -34,14 +36,19 @@ Bazaar::GetSearchResults(
|
|||||||
if (search.search_scope == NonRoFBazaarSearchScope) {
|
if (search.search_scope == NonRoFBazaarSearchScope) {
|
||||||
search_criteria_trader.append(
|
search_criteria_trader.append(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
" AND trader.char_entity_id = {} AND trader.char_zone_id = {}",
|
" AND trader.char_entity_id = {} AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
|
||||||
search.trader_entity_id,
|
search.trader_entity_id,
|
||||||
Zones::BAZAAR
|
Zones::BAZAAR,
|
||||||
|
char_zone_instance_id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (search.search_scope == Local_Scope) {
|
else if (search.search_scope == Local_Scope) {
|
||||||
search_criteria_trader.append(fmt::format(" AND trader.char_zone_id = {}", char_zone_id));
|
search_criteria_trader.append(fmt::format(
|
||||||
|
" AND trader.char_zone_id = {} AND trader.char_zone_instance_id = {}",
|
||||||
|
char_zone_id,
|
||||||
|
char_zone_instance_id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (search.trader_id > 0) {
|
else if (search.trader_id > 0) {
|
||||||
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
|
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
|
||||||
@@ -62,7 +69,7 @@ Bazaar::GetSearchResults(
|
|||||||
std::string query = fmt::format(
|
std::string query = fmt::format(
|
||||||
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
|
"SELECT COUNT(item_id), trader.char_id, trader.item_id, trader.item_sn, trader.item_charges, trader.item_cost, "
|
||||||
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
|
"trader.slot_id, SUM(trader.item_charges), trader.char_zone_id, trader.char_entity_id, character_data.name, "
|
||||||
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6 "
|
"aug_slot_1, aug_slot_2, aug_slot_3, aug_slot_4, aug_slot_5, aug_slot_6, trader.char_zone_instance_id "
|
||||||
"FROM trader, character_data "
|
"FROM trader, character_data "
|
||||||
"WHERE {} AND trader.char_id = character_data.id "
|
"WHERE {} AND trader.char_id = character_data.id "
|
||||||
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
|
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
|
||||||
@@ -122,19 +129,20 @@ Bazaar::GetSearchResults(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
r.count = Strings::ToInt(row[0]);
|
r.count = Strings::ToInt(row[0]);
|
||||||
r.trader_id = Strings::ToInt(row[1]);
|
r.trader_id = Strings::ToInt(row[1]);
|
||||||
r.serial_number = Strings::ToInt(row[3]);
|
r.serial_number = Strings::ToInt(row[3]);
|
||||||
r.cost = Strings::ToInt(row[5]);
|
r.cost = Strings::ToInt(row[5]);
|
||||||
r.slot_id = Strings::ToInt(row[6]);
|
r.slot_id = Strings::ToInt(row[6]);
|
||||||
r.sum_charges = Strings::ToInt(row[7]);
|
r.sum_charges = Strings::ToInt(row[7]);
|
||||||
r.stackable = item->Stackable;
|
r.stackable = item->Stackable;
|
||||||
r.icon_id = item->Icon;
|
r.icon_id = item->Icon;
|
||||||
r.trader_zone_id = Strings::ToInt(row[8]);
|
r.trader_zone_id = Strings::ToInt(row[8]);
|
||||||
r.trader_entity_id = Strings::ToInt(row[9]);
|
r.trader_zone_instance_id = Strings::ToInt(row[17]);
|
||||||
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
|
r.trader_entity_id = Strings::ToInt(row[9]);
|
||||||
r.item_name = fmt::format("{:.63}\0", item->Name);
|
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
|
||||||
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
|
r.item_name = fmt::format("{:.63}\0", item->Name);
|
||||||
|
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
|
||||||
|
|
||||||
LogTradingDetail(
|
LogTradingDetail(
|
||||||
"Searching against item [{}] ({}) for trader [{}]",
|
"Searching against item [{}] ({}) for trader [{}]",
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
class Bazaar {
|
class Bazaar {
|
||||||
public:
|
public:
|
||||||
static std::vector<BazaarSearchResultsFromDB_Struct>
|
static std::vector<BazaarSearchResultsFromDB_Struct>
|
||||||
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id);
|
GetSearchResults(SharedDatabase &db, BazaarSearchCriteria_Struct search, unsigned int char_zone_id, int char_zone_instance_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5770,6 +5770,17 @@ MODIFY COLUMN `exp_modifier` float NOT NULL DEFAULT 1.0 AFTER `aa_modifier`;
|
|||||||
CREATE INDEX idx_character_expires ON data_buckets (character_id, expires);
|
CREATE INDEX idx_character_expires ON data_buckets (character_id, expires);
|
||||||
CREATE INDEX idx_npc_expires ON data_buckets (npc_id, expires);
|
CREATE INDEX idx_npc_expires ON data_buckets (npc_id, expires);
|
||||||
CREATE INDEX idx_bot_expires ON data_buckets (bot_id, expires);
|
CREATE INDEX idx_bot_expires ON data_buckets (bot_id, expires);
|
||||||
|
)"
|
||||||
|
},
|
||||||
|
ManifestEntry{
|
||||||
|
.version = 9286,
|
||||||
|
.description = "2024_11_26_bazaar_find_trader.sql",
|
||||||
|
.check = "SHOW COLUMNS FROM `trader` LIKE 'char_zone_instance_id'",
|
||||||
|
.condition = "empty",
|
||||||
|
.match = "",
|
||||||
|
.sql = R"(
|
||||||
|
ALTER TABLE `trader`
|
||||||
|
ADD COLUMN `char_zone_instance_id` INT NULL DEFAULT '0' AFTER `char_zone_id`;
|
||||||
)"
|
)"
|
||||||
}
|
}
|
||||||
// -- template; copy/paste this when you need to create a new entry
|
// -- template; copy/paste this when you need to create a new entry
|
||||||
|
|||||||
+15
-23
@@ -140,29 +140,6 @@ std::string EQ::constants::GetLanguageName(uint8 language_id)
|
|||||||
return EQ::constants::GetLanguageMap().find(language_id)->second;
|
return EQ::constants::GetLanguageMap().find(language_id)->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<uint32, std::string>& EQ::constants::GetLDoNThemeMap()
|
|
||||||
{
|
|
||||||
static const std::map<uint32, std::string> ldon_theme_map = {
|
|
||||||
{ LDoNThemes::Unused, "Unused" },
|
|
||||||
{ LDoNThemes::GUK, "Deepest Guk" },
|
|
||||||
{ LDoNThemes::MIR, "Miragul's Menagerie" },
|
|
||||||
{ LDoNThemes::MMC, "Mistmoore Catacombs" },
|
|
||||||
{ LDoNThemes::RUJ, "Rujarkian Hills" },
|
|
||||||
{ LDoNThemes::TAK, "Takish-Hiz" },
|
|
||||||
};
|
|
||||||
|
|
||||||
return ldon_theme_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EQ::constants::GetLDoNThemeName(uint32 theme_id)
|
|
||||||
{
|
|
||||||
if (!EQ::ValueWithin(theme_id, LDoNThemes::Unused, LDoNThemes::TAK)) {
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EQ::constants::GetLDoNThemeMap().find(theme_id)->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
|
const std::map<int8, std::string>& EQ::constants::GetFlyModeMap()
|
||||||
{
|
{
|
||||||
static const std::map<int8, std::string> flymode_map = {
|
static const std::map<int8, std::string> flymode_map = {
|
||||||
@@ -459,3 +436,18 @@ bool ComparisonType::IsValid(uint8 type)
|
|||||||
{
|
{
|
||||||
return comparison_types.find(type) != comparison_types.end();
|
return comparison_types.find(type) != comparison_types.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 LDoNTheme::GetBitmask(uint32 theme_id)
|
||||||
|
{
|
||||||
|
return IsValid(theme_id) ? ldon_theme_names[theme_id].second : LDoNTheme::UnusedBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LDoNTheme::GetName(uint32 theme_id)
|
||||||
|
{
|
||||||
|
return IsValid(theme_id) ? ldon_theme_names[theme_id].first : "UNKNOWN LDON THEME";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LDoNTheme::IsValid(uint32 theme_id)
|
||||||
|
{
|
||||||
|
return ldon_theme_names.find(theme_id) != ldon_theme_names.end();
|
||||||
|
}
|
||||||
|
|||||||
+29
-3
@@ -352,9 +352,6 @@ namespace EQ
|
|||||||
extern const std::map<uint8, std::string>& GetLanguageMap();
|
extern const std::map<uint8, std::string>& GetLanguageMap();
|
||||||
std::string GetLanguageName(uint8 language_id);
|
std::string GetLanguageName(uint8 language_id);
|
||||||
|
|
||||||
extern const std::map<uint32, std::string>& GetLDoNThemeMap();
|
|
||||||
std::string GetLDoNThemeName(uint32 theme_id);
|
|
||||||
|
|
||||||
extern const std::map<int8, std::string>& GetFlyModeMap();
|
extern const std::map<int8, std::string>& GetFlyModeMap();
|
||||||
std::string GetFlyModeName(int8 flymode_id);
|
std::string GetFlyModeName(int8 flymode_id);
|
||||||
|
|
||||||
@@ -751,6 +748,35 @@ static std::map<uint32, std::string> stance_names = {
|
|||||||
{ Stance::AEBurn, "AE Burn" }
|
{ Stance::AEBurn, "AE Burn" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace LDoNTheme {
|
||||||
|
constexpr uint32 Unused = 0;
|
||||||
|
constexpr uint32 GUK = 1;
|
||||||
|
constexpr uint32 MIR = 2;
|
||||||
|
constexpr uint32 MMC = 3;
|
||||||
|
constexpr uint32 RUJ = 4;
|
||||||
|
constexpr uint32 TAK = 5;
|
||||||
|
|
||||||
|
constexpr uint32 UnusedBit = 0;
|
||||||
|
constexpr uint32 GUKBit = 1;
|
||||||
|
constexpr uint32 MIRBit = 2;
|
||||||
|
constexpr uint32 MMCBit = 4;
|
||||||
|
constexpr uint32 RUJBit = 8;
|
||||||
|
constexpr uint32 TAKBit = 16;
|
||||||
|
|
||||||
|
uint32 GetBitmask(uint32 theme_id);
|
||||||
|
std::string GetName(uint32 theme_id);
|
||||||
|
bool IsValid(uint32 theme_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<uint32, std::pair<std::string, uint32>> ldon_theme_names = {
|
||||||
|
{ LDoNTheme::Unused, { "Unused", LDoNTheme::UnusedBit }, },
|
||||||
|
{ LDoNTheme::GUK, { "Deepest Guk", LDoNTheme::GUKBit }, },
|
||||||
|
{ LDoNTheme::MIR, { "Miragul's Menagerie", LDoNTheme::MIRBit }, },
|
||||||
|
{ LDoNTheme::MMC, { "Mistmoore Catacombs", LDoNTheme::MMCBit }, },
|
||||||
|
{ LDoNTheme::RUJ, { "Rujarkian Hills", LDoNTheme::RUJBit }, },
|
||||||
|
{ LDoNTheme::TAK, { "Takish-Hiz", LDoNTheme::TAKBit }, },
|
||||||
|
};
|
||||||
|
|
||||||
namespace PCNPCOnlyFlagType {
|
namespace PCNPCOnlyFlagType {
|
||||||
constexpr int PC = 1;
|
constexpr int PC = 1;
|
||||||
constexpr int NPC = 2;
|
constexpr int NPC = 2;
|
||||||
|
|||||||
@@ -993,24 +993,6 @@ enum class DynamicZoneMemberStatus : uint8_t
|
|||||||
LinkDead
|
LinkDead
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LDoNThemes {
|
|
||||||
Unused = 0,
|
|
||||||
GUK,
|
|
||||||
MIR,
|
|
||||||
MMC,
|
|
||||||
RUJ,
|
|
||||||
TAK
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LDoNThemeBits {
|
|
||||||
UnusedBit = 0,
|
|
||||||
GUKBit = 1,
|
|
||||||
MIRBit = 2,
|
|
||||||
MMCBit = 4,
|
|
||||||
RUJBit = 8,
|
|
||||||
TAKBit = 16
|
|
||||||
};
|
|
||||||
|
|
||||||
enum StartZoneIndex {
|
enum StartZoneIndex {
|
||||||
Odus = 0,
|
Odus = 0,
|
||||||
Qeynos,
|
Qeynos,
|
||||||
|
|||||||
@@ -3742,7 +3742,8 @@ struct GetItems_Struct{
|
|||||||
|
|
||||||
struct BecomeTrader_Struct {
|
struct BecomeTrader_Struct {
|
||||||
uint32 action;
|
uint32 action;
|
||||||
uint32 zone_id;
|
uint16 zone_id;
|
||||||
|
uint16 zone_instance_id;
|
||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
uint32 entity_id;
|
uint32 entity_id;
|
||||||
char trader_name[64];
|
char trader_name[64];
|
||||||
@@ -6347,6 +6348,7 @@ enum BazaarTraderBarterActions {
|
|||||||
TraderAck2 = 22,
|
TraderAck2 = 22,
|
||||||
AddTraderToBazaarWindow = 24,
|
AddTraderToBazaarWindow = 24,
|
||||||
RemoveTraderFromBazaarWindow = 25,
|
RemoveTraderFromBazaarWindow = 25,
|
||||||
|
FirstOpenSearch = 26,
|
||||||
ClickTrader = 28,
|
ClickTrader = 28,
|
||||||
DeliveryCostUpdate = 29
|
DeliveryCostUpdate = 29
|
||||||
};
|
};
|
||||||
@@ -6386,6 +6388,7 @@ struct BazaarSearchResultsFromDB_Struct {
|
|||||||
uint32 icon_id;
|
uint32 icon_id;
|
||||||
uint32 sum_charges;
|
uint32 sum_charges;
|
||||||
uint32 trader_zone_id;
|
uint32 trader_zone_id;
|
||||||
|
int32 trader_zone_instance_id;
|
||||||
uint32 trader_entity_id;
|
uint32 trader_entity_id;
|
||||||
uint32 item_stat;
|
uint32 item_stat;
|
||||||
bool stackable;
|
bool stackable;
|
||||||
@@ -6407,6 +6410,7 @@ struct BazaarSearchResultsFromDB_Struct {
|
|||||||
CEREAL_NVP(icon_id),
|
CEREAL_NVP(icon_id),
|
||||||
CEREAL_NVP(sum_charges),
|
CEREAL_NVP(sum_charges),
|
||||||
CEREAL_NVP(trader_zone_id),
|
CEREAL_NVP(trader_zone_id),
|
||||||
|
CEREAL_NVP(trader_zone_instance_id),
|
||||||
CEREAL_NVP(trader_entity_id),
|
CEREAL_NVP(trader_entity_id),
|
||||||
CEREAL_NVP(item_stat),
|
CEREAL_NVP(item_stat),
|
||||||
CEREAL_NVP(stackable),
|
CEREAL_NVP(stackable),
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ void EQEmuConfig::parse_config()
|
|||||||
auto_database_updates = true;
|
auto_database_updates = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
|
WorldIP = _root["server"]["world"]["tcp"].get("ip", "127.0.0.1").asString();
|
||||||
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString());
|
WorldTCPPort = Strings::ToUnsignedInt(_root["server"]["world"]["tcp"].get("port", "9000").asString());
|
||||||
|
|
||||||
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
|
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
|
||||||
|
|||||||
@@ -414,6 +414,12 @@ static uint64_t MakeBits(std::span<const uint8_t> data)
|
|||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept has_from_chars = requires (const char* first, const char* last, T value)
|
||||||
|
{
|
||||||
|
std::from_chars(first, last, value);
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T FromString(std::string_view sv)
|
static T FromString(std::string_view sv)
|
||||||
{
|
{
|
||||||
@@ -422,6 +428,14 @@ static T FromString(std::string_view sv)
|
|||||||
// return false for empty (zero-length) strings
|
// return false for empty (zero-length) strings
|
||||||
return !sv.empty();
|
return !sv.empty();
|
||||||
}
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, float> && !has_from_chars<T>)
|
||||||
|
{
|
||||||
|
return std::strtof(std::string(sv).c_str(), nullptr);
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, double> && !has_from_chars<T>)
|
||||||
|
{
|
||||||
|
return std::strtod(std::string(sv).c_str(), nullptr);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// non numbers return a zero initialized T (could return nullopt instead)
|
// non numbers return a zero initialized T (could return nullopt instead)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "../eqemu_logsys.h"
|
#include "../eqemu_logsys.h"
|
||||||
#include "../servertalk.h"
|
#include "../servertalk.h"
|
||||||
#include "../rulesys.h"
|
#include "../rulesys.h"
|
||||||
|
#include "../event/timer.h"
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent, std::shared_ptr<TCPConnection> connection)
|
EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent, std::shared_ptr<TCPConnection> connection)
|
||||||
@@ -21,7 +22,11 @@ EQ::Net::ConsoleServerConnection::ConsoleServerConnection(ConsoleServer *parent,
|
|||||||
m_connection->OnDisconnect(std::bind(&ConsoleServerConnection::OnDisconnect, this, std::placeholders::_1));
|
m_connection->OnDisconnect(std::bind(&ConsoleServerConnection::OnDisconnect, this, std::placeholders::_1));
|
||||||
m_connection->Start();
|
m_connection->Start();
|
||||||
ClearBuffer();
|
ClearBuffer();
|
||||||
|
|
||||||
|
m_keepalive = std::make_unique<EQ::Timer>(1000, true, [this](EQ::Timer *t) {
|
||||||
|
m_connection->Write("", 0);
|
||||||
|
});
|
||||||
|
|
||||||
auto addr = m_connection->RemoteIP();
|
auto addr = m_connection->RemoteIP();
|
||||||
|
|
||||||
SendLine(fmt::format("Establishing connection from: {0}:{1}", addr, m_connection->RemotePort()));
|
SendLine(fmt::format("Establishing connection from: {0}:{1}", addr, m_connection->RemotePort()));
|
||||||
@@ -85,12 +90,12 @@ void EQ::Net::ConsoleServerConnection::QueueMessage(const std::string &msg)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::string cmd(m_line, m_line + m_cursor);
|
std::string cmd(m_line, m_line + m_cursor);
|
||||||
|
|
||||||
size_t len = m_user.length() + 2 + cmd.length();
|
size_t len = m_user.length() + 2 + cmd.length();
|
||||||
for (size_t i = 0; i < len; ++i) {
|
for (size_t i = 0; i < len; ++i) {
|
||||||
Send("\x08");
|
Send("\x08");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.length() < cmd.length()) {
|
if (msg.length() < cmd.length()) {
|
||||||
Send(msg);
|
Send(msg);
|
||||||
size_t blank_spaces = 2 + cmd.length() - msg.length();
|
size_t blank_spaces = 2 + cmd.length() - msg.length();
|
||||||
@@ -227,6 +232,8 @@ void EQ::Net::ConsoleServerConnection::OnRead(TCPConnection *c, const unsigned c
|
|||||||
|
|
||||||
void EQ::Net::ConsoleServerConnection::OnDisconnect(TCPConnection *c)
|
void EQ::Net::ConsoleServerConnection::OnDisconnect(TCPConnection *c)
|
||||||
{
|
{
|
||||||
|
LogInfo("Console connection disconnected");
|
||||||
|
|
||||||
m_parent->ConnectionDisconnected(this);
|
m_parent->ConnectionDisconnected(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "tcp_server.h"
|
#include "tcp_server.h"
|
||||||
|
#include "../event/timer.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
@@ -58,6 +59,7 @@ namespace EQ
|
|||||||
int m_user_id;
|
int m_user_id;
|
||||||
int m_admin;
|
int m_admin;
|
||||||
bool m_accept_messages;
|
bool m_accept_messages;
|
||||||
|
std::unique_ptr<EQ::Timer> m_keepalive;
|
||||||
|
|
||||||
size_t m_cursor;
|
size_t m_cursor;
|
||||||
char m_line[MaxConsoleLineLength];
|
char m_line[MaxConsoleLineLength];
|
||||||
|
|||||||
+26
-10
@@ -583,19 +583,21 @@ namespace RoF2
|
|||||||
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct));
|
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct));
|
||||||
auto eq = (BecomeTrader_Struct *) outapp->pBuffer;
|
auto eq = (BecomeTrader_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
eq->action = emu->action;
|
eq->action = emu->action;
|
||||||
eq->entity_id = emu->entity_id;
|
eq->entity_id = emu->entity_id;
|
||||||
eq->trader_id = emu->trader_id;
|
eq->trader_id = emu->trader_id;
|
||||||
eq->zone_id = emu->zone_id;
|
eq->zone_id = emu->zone_id;
|
||||||
|
eq->zone_instance_id = emu->zone_instance_id;
|
||||||
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
strn0cpy(eq->trader_name, emu->trader_name, sizeof(eq->trader_name));
|
||||||
|
|
||||||
LogTrading(
|
LogTrading(
|
||||||
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] zone_id <green>[{}]",
|
"(RoF2) AddTraderToBazaarWindow action <green>[{}] trader_id <green>[{}] entity_id <green>[{}] "
|
||||||
|
"zone_id <green>[{}] zone_instance_id <green>[{}]",
|
||||||
eq->action,
|
eq->action,
|
||||||
eq->trader_id,
|
eq->trader_id,
|
||||||
eq->entity_id,
|
eq->entity_id,
|
||||||
eq->zone_id
|
eq->zone_id,
|
||||||
);
|
eq->zone_instance_id);
|
||||||
dest->FastQueuePacket(&outapp);
|
dest->FastQueuePacket(&outapp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -6218,6 +6220,11 @@ namespace RoF2
|
|||||||
FINISH_DIRECT_DECODE();
|
FINISH_DIRECT_DECODE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case structs::RoF2BazaarTraderBuyerActions::FirstOpenSearch: {
|
||||||
|
__packet->SetOpcode(OP_BazaarSearch);
|
||||||
|
LogTrading("(RoF2) First time opening Bazaar Search since zoning. Action <green>[{}]", action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: {
|
case structs::RoF2BazaarTraderBuyerActions::WelcomeMessage: {
|
||||||
__packet->SetOpcode(OP_BazaarSearch);
|
__packet->SetOpcode(OP_BazaarSearch);
|
||||||
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
|
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
|
||||||
@@ -6358,9 +6365,18 @@ namespace RoF2
|
|||||||
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
//sprintf(hdr.unknown000, "06e0002Y1W00");
|
||||||
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
|
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
|
||||||
|
|
||||||
hdr.stacksize =
|
hdr.stacksize = 1;
|
||||||
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
|
|
||||||
? 0xFFFFFFFF : inst->GetCharges()) : 1);
|
if (item->ID == PARCEL_MONEY_ITEM_ID) {
|
||||||
|
hdr.stacksize = inst->GetPrice();
|
||||||
|
} else if (inst->IsStackable()) {
|
||||||
|
if (inst->GetCharges() > std::numeric_limits<int16>::max()) {
|
||||||
|
hdr.stacksize = std::numeric_limits<uint32>::max();
|
||||||
|
} else {
|
||||||
|
hdr.stacksize = inst->GetCharges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hdr.unknown004 = 0;
|
hdr.unknown004 = 0;
|
||||||
|
|
||||||
structs::InventorySlot_Struct slot_id{};
|
structs::InventorySlot_Struct slot_id{};
|
||||||
|
|||||||
@@ -3119,7 +3119,8 @@ enum RoF2BazaarTraderBuyerActions {
|
|||||||
BazaarInspect = 18,
|
BazaarInspect = 18,
|
||||||
ClickTrader = 28,
|
ClickTrader = 28,
|
||||||
ItemMove = 19,
|
ItemMove = 19,
|
||||||
ReconcileItems = 20
|
ReconcileItems = 20,
|
||||||
|
FirstOpenSearch = 26
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RoF2BuyerActions {
|
enum RoF2BuyerActions {
|
||||||
|
|||||||
@@ -49,23 +49,23 @@ public:
|
|||||||
std::string field;
|
std::string field;
|
||||||
|
|
||||||
switch (theme_id) {
|
switch (theme_id) {
|
||||||
case LDoNThemes::GUK: {
|
case LDoNTheme::GUK: {
|
||||||
field = "guk_";
|
field = "guk_";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::MIR: {
|
case LDoNTheme::MIR: {
|
||||||
field = "mir_";
|
field = "mir_";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::MMC: {
|
case LDoNTheme::MMC: {
|
||||||
field = "mmc_";
|
field = "mmc_";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::RUJ: {
|
case LDoNTheme::RUJ: {
|
||||||
field = "ruj_";
|
field = "ruj_";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::TAK: {
|
case LDoNTheme::TAK: {
|
||||||
field = "tak_";
|
field = "tak_";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ public:
|
|||||||
uint32_t aug_slot_4;
|
uint32_t aug_slot_4;
|
||||||
uint32_t aug_slot_5;
|
uint32_t aug_slot_5;
|
||||||
uint32_t aug_slot_6;
|
uint32_t aug_slot_6;
|
||||||
int32_t item_sn;
|
uint32_t item_sn;
|
||||||
int32_t item_charges;
|
int32_t item_charges;
|
||||||
uint64_t item_cost;
|
uint32_t item_cost;
|
||||||
uint8_t slot_id;
|
uint8_t slot_id;
|
||||||
uint32_t char_entity_id;
|
uint32_t char_entity_id;
|
||||||
uint32_t char_zone_id;
|
uint32_t char_zone_id;
|
||||||
int8_t active_transaction;
|
int32_t char_zone_instance_id;
|
||||||
|
uint8_t active_transaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@@ -60,6 +61,7 @@ public:
|
|||||||
"slot_id",
|
"slot_id",
|
||||||
"char_entity_id",
|
"char_entity_id",
|
||||||
"char_zone_id",
|
"char_zone_id",
|
||||||
|
"char_zone_instance_id",
|
||||||
"active_transaction",
|
"active_transaction",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -82,6 +84,7 @@ public:
|
|||||||
"slot_id",
|
"slot_id",
|
||||||
"char_entity_id",
|
"char_entity_id",
|
||||||
"char_zone_id",
|
"char_zone_id",
|
||||||
|
"char_zone_instance_id",
|
||||||
"active_transaction",
|
"active_transaction",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -123,22 +126,23 @@ public:
|
|||||||
{
|
{
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = 0;
|
e.id = 0;
|
||||||
e.char_id = 0;
|
e.char_id = 0;
|
||||||
e.item_id = 0;
|
e.item_id = 0;
|
||||||
e.aug_slot_1 = 0;
|
e.aug_slot_1 = 0;
|
||||||
e.aug_slot_2 = 0;
|
e.aug_slot_2 = 0;
|
||||||
e.aug_slot_3 = 0;
|
e.aug_slot_3 = 0;
|
||||||
e.aug_slot_4 = 0;
|
e.aug_slot_4 = 0;
|
||||||
e.aug_slot_5 = 0;
|
e.aug_slot_5 = 0;
|
||||||
e.aug_slot_6 = 0;
|
e.aug_slot_6 = 0;
|
||||||
e.item_sn = 0;
|
e.item_sn = 0;
|
||||||
e.item_charges = 0;
|
e.item_charges = 0;
|
||||||
e.item_cost = 0;
|
e.item_cost = 0;
|
||||||
e.slot_id = 0;
|
e.slot_id = 0;
|
||||||
e.char_entity_id = 0;
|
e.char_entity_id = 0;
|
||||||
e.char_zone_id = 0;
|
e.char_zone_id = 0;
|
||||||
e.active_transaction = 0;
|
e.char_zone_instance_id = 0;
|
||||||
|
e.active_transaction = 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -175,22 +179,23 @@ public:
|
|||||||
if (results.RowCount() == 1) {
|
if (results.RowCount() == 1) {
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
||||||
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
|
||||||
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||||
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
|
||||||
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -238,7 +243,8 @@ public:
|
|||||||
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
|
v.push_back(columns[12] + " = " + std::to_string(e.slot_id));
|
||||||
v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id));
|
v.push_back(columns[13] + " = " + std::to_string(e.char_entity_id));
|
||||||
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
|
v.push_back(columns[14] + " = " + std::to_string(e.char_zone_id));
|
||||||
v.push_back(columns[15] + " = " + std::to_string(e.active_transaction));
|
v.push_back(columns[15] + " = " + std::to_string(e.char_zone_instance_id));
|
||||||
|
v.push_back(columns[16] + " = " + std::to_string(e.active_transaction));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@@ -275,6 +281,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.char_entity_id));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back(std::to_string(e.char_zone_id));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
v.push_back(std::to_string(e.active_transaction));
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
@@ -320,6 +327,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.char_entity_id));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back(std::to_string(e.char_zone_id));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
v.push_back(std::to_string(e.active_transaction));
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
@@ -354,22 +362,23 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
||||||
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
|
||||||
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||||
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
|
||||||
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -394,22 +403,23 @@ public:
|
|||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
Trader e{};
|
Trader e{};
|
||||||
|
|
||||||
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
e.id = row[0] ? strtoull(row[0], nullptr, 10) : 0;
|
||||||
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
e.char_id = row[1] ? static_cast<uint32_t>(strtoul(row[1], nullptr, 10)) : 0;
|
||||||
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
e.item_id = row[2] ? static_cast<uint32_t>(strtoul(row[2], nullptr, 10)) : 0;
|
||||||
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
e.aug_slot_1 = row[3] ? static_cast<uint32_t>(strtoul(row[3], nullptr, 10)) : 0;
|
||||||
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
e.aug_slot_2 = row[4] ? static_cast<uint32_t>(strtoul(row[4], nullptr, 10)) : 0;
|
||||||
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
e.aug_slot_3 = row[5] ? static_cast<uint32_t>(strtoul(row[5], nullptr, 10)) : 0;
|
||||||
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
e.aug_slot_4 = row[6] ? static_cast<uint32_t>(strtoul(row[6], nullptr, 10)) : 0;
|
||||||
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
e.aug_slot_5 = row[7] ? static_cast<uint32_t>(strtoul(row[7], nullptr, 10)) : 0;
|
||||||
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
e.aug_slot_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 0;
|
||||||
e.item_sn = row[9] ? static_cast<int32_t>(atoi(row[9])) : 0;
|
e.item_sn = row[9] ? static_cast<uint32_t>(strtoul(row[9], nullptr, 10)) : 0;
|
||||||
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
e.item_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
|
||||||
e.item_cost = row[11] ? strtoull(row[11], nullptr, 10) : 0;
|
e.item_cost = row[11] ? static_cast<uint32_t>(strtoul(row[11], nullptr, 10)) : 0;
|
||||||
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
e.slot_id = row[12] ? static_cast<uint8_t>(strtoul(row[12], nullptr, 10)) : 0;
|
||||||
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
e.char_entity_id = row[13] ? static_cast<uint32_t>(strtoul(row[13], nullptr, 10)) : 0;
|
||||||
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
e.char_zone_id = row[14] ? static_cast<uint32_t>(strtoul(row[14], nullptr, 10)) : 0;
|
||||||
e.active_transaction = row[15] ? static_cast<int8_t>(atoi(row[15])) : 0;
|
e.char_zone_instance_id = row[15] ? static_cast<int32_t>(atoi(row[15])) : 0;
|
||||||
|
e.active_transaction = row[16] ? static_cast<uint8_t>(strtoul(row[16], nullptr, 10)) : 0;
|
||||||
|
|
||||||
all_entries.push_back(e);
|
all_entries.push_back(e);
|
||||||
}
|
}
|
||||||
@@ -499,6 +509,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.char_entity_id));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back(std::to_string(e.char_zone_id));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
v.push_back(std::to_string(e.active_transaction));
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
@@ -537,6 +548,7 @@ public:
|
|||||||
v.push_back(std::to_string(e.slot_id));
|
v.push_back(std::to_string(e.slot_id));
|
||||||
v.push_back(std::to_string(e.char_entity_id));
|
v.push_back(std::to_string(e.char_entity_id));
|
||||||
v.push_back(std::to_string(e.char_zone_id));
|
v.push_back(std::to_string(e.char_zone_id));
|
||||||
|
v.push_back(std::to_string(e.char_zone_instance_id));
|
||||||
v.push_back(std::to_string(e.active_transaction));
|
v.push_back(std::to_string(e.active_transaction));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public:
|
|||||||
struct DistinctTraders_Struct {
|
struct DistinctTraders_Struct {
|
||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
uint32 zone_id;
|
uint32 zone_id;
|
||||||
|
uint32 zone_instance_id;
|
||||||
uint32 entity_id;
|
uint32 entity_id;
|
||||||
std::string trader_name;
|
std::string trader_name;
|
||||||
};
|
};
|
||||||
@@ -35,7 +36,8 @@ public:
|
|||||||
GetBazaarSearchResults(
|
GetBazaarSearchResults(
|
||||||
SharedDatabase &db,
|
SharedDatabase &db,
|
||||||
BazaarSearchCriteria_Struct search,
|
BazaarSearchCriteria_Struct search,
|
||||||
uint32 char_zone_id
|
uint32 char_zone_id,
|
||||||
|
int32 char_zone_instance_id
|
||||||
);
|
);
|
||||||
|
|
||||||
static BulkTraders_Struct GetDistinctTraders(Database &db)
|
static BulkTraders_Struct GetDistinctTraders(Database &db)
|
||||||
@@ -44,7 +46,7 @@ public:
|
|||||||
std::vector<DistinctTraders_Struct> distinct_traders;
|
std::vector<DistinctTraders_Struct> distinct_traders;
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_entity_id, c.name "
|
"SELECT DISTINCT(t.char_id), t.char_zone_id, t.char_zone_instance_id, t.char_entity_id, c.name "
|
||||||
"FROM trader AS t "
|
"FROM trader AS t "
|
||||||
"JOIN character_data AS c ON t.char_id = c.id;"
|
"JOIN character_data AS c ON t.char_id = c.id;"
|
||||||
);
|
);
|
||||||
@@ -54,10 +56,11 @@ public:
|
|||||||
for (auto row: results) {
|
for (auto row: results) {
|
||||||
DistinctTraders_Struct e{};
|
DistinctTraders_Struct e{};
|
||||||
|
|
||||||
e.trader_id = Strings::ToInt(row[0]);
|
e.trader_id = Strings::ToInt(row[0]);
|
||||||
e.zone_id = Strings::ToInt(row[1]);
|
e.zone_id = Strings::ToInt(row[1]);
|
||||||
e.entity_id = Strings::ToInt(row[2]);
|
e.zone_instance_id = Strings::ToInt(row[2]);
|
||||||
e.trader_name = row[3] ? row[3] : "";
|
e.entity_id = Strings::ToInt(row[3]);
|
||||||
|
e.trader_name = row[4] ? row[4] : "";
|
||||||
all_entries.name_length += e.trader_name.length() + 1;
|
all_entries.name_length += e.trader_name.length() + 1;
|
||||||
|
|
||||||
all_entries.traders.push_back(e);
|
all_entries.traders.push_back(e);
|
||||||
|
|||||||
@@ -340,6 +340,9 @@ RULE_STRING(World, Rules, "", "Server Rules, change from empty to have this be u
|
|||||||
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
|
RULE_BOOL(World, EnableAutoLogin, false, "Enables or disables auto login of characters, allowing people to log characters in directly from loginserver to ingame")
|
||||||
RULE_BOOL(World, EnablePVPRegions, true, "Enables or disables PVP Regions automatically setting your PVP flag")
|
RULE_BOOL(World, EnablePVPRegions, true, "Enables or disables PVP Regions automatically setting your PVP flag")
|
||||||
RULE_STRING(World, SupportedClients, "", "Comma-delimited list of clients to restrict to. Supported values are Titanium | SoF | SoD | UF | RoF | RoF2. Example: Titanium,RoF2")
|
RULE_STRING(World, SupportedClients, "", "Comma-delimited list of clients to restrict to. Supported values are Titanium | SoF | SoD | UF | RoF | RoF2. Example: Titanium,RoF2")
|
||||||
|
RULE_STRING(World, CustomFilesKey, "", "Enable if the server requires custom files and sends a key to validate. Empty string to disable. Example: eqcustom_v1")
|
||||||
|
RULE_STRING(World, CustomFilesUrl, "github.com/knervous/eqnexus/releases", "URL to display at character select if client is missing custom files")
|
||||||
|
RULE_INT(World, CustomFilesAdminLevel, 20, "Admin level at which custom file key is not required when CustomFilesKey is specified")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Zone)
|
RULE_CATEGORY(Zone)
|
||||||
@@ -681,6 +684,7 @@ RULE_BOOL(NPC, DisableLastNames, false, "Enable to disable NPC Last Names")
|
|||||||
RULE_BOOL(NPC, NPCIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
RULE_BOOL(NPC, NPCIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
|
||||||
RULE_INT(NPC, NPCHasteCap, 150, "Haste cap for non-v3(over haste) haste")
|
RULE_INT(NPC, NPCHasteCap, 150, "Haste cap for non-v3(over haste) haste")
|
||||||
RULE_INT(NPC, NPCHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
RULE_INT(NPC, NPCHastev3Cap, 25, "Haste cap for v3(over haste) haste")
|
||||||
|
RULE_STRING(NPC, ExcludedFaceTargetRaces, "52,72,73,141,233,328,329,372,376,377,378,379,380,381,382,383,404,422,423,424,425,426,428,429,445,449,460,462,463,500,501,502,503,504,505,506,507,508,509,510,511,513,514,515,516,533,534,535,536,537,538,539,540,541,542,543,544,545,546,550,551,552,553,554,555,556,557,567,573,577,586,589,590,591,592,593,595,596,599,601,616,619,621,628,629,630,633,634,635,636,665,683,684,685,691,692,693,694,702,703,705,706,707,710,711,714,720,2250,2254", "Race IDs excluded from facing target when hailed")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Aggro)
|
RULE_CATEGORY(Aggro)
|
||||||
|
|||||||
+1
-2
@@ -319,8 +319,6 @@
|
|||||||
// player events
|
// player events
|
||||||
#define ServerOP_PlayerEvent 0x5100
|
#define ServerOP_PlayerEvent 0x5100
|
||||||
|
|
||||||
#define ServerOP_DataBucketCacheUpdate 0x5200
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CZUpdateType_Character,
|
CZUpdateType_Character,
|
||||||
CZUpdateType_Group,
|
CZUpdateType_Group,
|
||||||
@@ -1945,6 +1943,7 @@ struct ServerOP_GuildMessage_Struct {
|
|||||||
struct TraderMessaging_Struct {
|
struct TraderMessaging_Struct {
|
||||||
uint32 action;
|
uint32 action;
|
||||||
uint32 zone_id;
|
uint32 zone_id;
|
||||||
|
uint32 instance_id;
|
||||||
uint32 trader_id;
|
uint32 trader_id;
|
||||||
uint32 entity_id;
|
uint32 entity_id;
|
||||||
char trader_name[64];
|
char trader_name[64];
|
||||||
|
|||||||
+4
-3
@@ -83,7 +83,8 @@ struct ActivityInformation {
|
|||||||
if (zone_ids.empty()) {
|
if (zone_ids.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool found_zone = std::find(zone_ids.begin(), zone_ids.end(), zone_id) != zone_ids.end();
|
bool found_zone = std::any_of(zone_ids.begin(), zone_ids.end(),
|
||||||
|
[zone_id](int id) { return id <= 0 || id == zone_id; });
|
||||||
|
|
||||||
return found_zone && (zone_version == version || zone_version == -1);
|
return found_zone && (zone_version == version || zone_version == -1);
|
||||||
}
|
}
|
||||||
@@ -100,7 +101,7 @@ struct ActivityInformation {
|
|||||||
out.WriteInt32(activity_type == TaskActivityType::GiveCash ? 1 : goal_count);
|
out.WriteInt32(activity_type == TaskActivityType::GiveCash ? 1 : goal_count);
|
||||||
out.WriteLengthString(skill_list); // used in SkillOn objective type string, "-1" for none
|
out.WriteLengthString(skill_list); // used in SkillOn objective type string, "-1" for none
|
||||||
out.WriteLengthString(spell_list); // used in CastOn objective type string, "0" for none
|
out.WriteLengthString(spell_list); // used in CastOn objective type string, "0" for none
|
||||||
out.WriteString(zones); // used in objective zone column and task select "begins in" (may have multiple, "0" for "unknown zone", empty for "ALL")
|
out.WriteString(zones); // used in ui zone columns and task select "begins in" (may have multiple, invalid id for "Unknown Zone", empty for "ALL")
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -114,7 +115,7 @@ struct ActivityInformation {
|
|||||||
out.WriteString(description_override);
|
out.WriteString(description_override);
|
||||||
|
|
||||||
if (client_version >= EQ::versions::ClientVersion::RoF) {
|
if (client_version >= EQ::versions::ClientVersion::RoF) {
|
||||||
out.WriteString(zones); // serialized again after description (seems unused)
|
out.WriteString(zones); // target zone version internal id (unused client side)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
// Build variables
|
// Build variables
|
||||||
// these get injected during the build pipeline
|
// these get injected during the build pipeline
|
||||||
#define CURRENT_VERSION "22.59.1-dev" // always append -dev to the current version for custom-builds
|
#define CURRENT_VERSION "22.60.0-dev" // always append -dev to the current version for custom-builds
|
||||||
#define LOGIN_VERSION "0.8.0"
|
#define LOGIN_VERSION "0.8.0"
|
||||||
#define COMPILE_DATE __DATE__
|
#define COMPILE_DATE __DATE__
|
||||||
#define COMPILE_TIME __TIME__
|
#define COMPILE_TIME __TIME__
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9285
|
#define CURRENT_BINARY_DATABASE_VERSION 9286
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9045
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "eqemu-server",
|
"name": "eqemu-server",
|
||||||
"version": "22.59.1",
|
"version": "22.60.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/EQEmu/Server.git"
|
"url": "https://github.com/EQEmu/Server.git"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.3.2 // indirect
|
github.com/golang/protobuf v1.3.2 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
golang.org/x/crypto v0.21.0 // indirect
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/net v0.23.0 // indirect
|
golang.org/x/net v0.23.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD
|
|||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
|
|||||||
@@ -541,6 +541,17 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
|
|||||||
skip_char_info = true;
|
skip_char_info = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto& custom_files_key = RuleS(World, CustomFilesKey);
|
||||||
|
if (!skip_char_info && !custom_files_key.empty() && cle->Admin() < RuleI(World, CustomFilesAdminLevel)) {
|
||||||
|
// Modified clients can utilize this unused block in login_info to send custom payloads on login
|
||||||
|
// which indicates they are using custom client files with the correct version, based on key payload.
|
||||||
|
const auto client_key = std::string(reinterpret_cast<char*>(login_info->unknown064));
|
||||||
|
if (custom_files_key != client_key) {
|
||||||
|
std::string message = fmt::format("Missing Files [{}]", RuleS(World, CustomFilesUrl) );
|
||||||
|
SendUnsupportedClientPacket(message);
|
||||||
|
skip_char_info = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!skip_char_info) {
|
if (!skip_char_info) {
|
||||||
SendExpansionInfo();
|
SendExpansionInfo();
|
||||||
|
|||||||
@@ -1564,11 +1564,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
DynamicZone::HandleZoneMessage(pack);
|
DynamicZone::HandleZoneMessage(pack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_DataBucketCacheUpdate: {
|
|
||||||
zoneserver_list.SendPacket(pack);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_GuildTributeUpdate: {
|
case ServerOP_GuildTributeUpdate: {
|
||||||
auto data = (GuildTributeUpdate *)pack->pBuffer;
|
auto data = (GuildTributeUpdate *)pack->pBuffer;
|
||||||
auto guild = guild_mgr.GetGuildByGuildID(data->guild_id);
|
auto guild = guild_mgr.GetGuildByGuildID(data->guild_id);
|
||||||
|
|||||||
+7
-22
@@ -1550,10 +1550,7 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, boo
|
|||||||
hit.damage_done = 0;
|
hit.damage_done = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse->EventBotMerc(
|
parse->EventBotMerc(EVENT_USE_SKILL, this, nullptr,
|
||||||
EVENT_USE_SKILL,
|
|
||||||
this,
|
|
||||||
nullptr,
|
|
||||||
[&]() {
|
[&]() {
|
||||||
return fmt::format(
|
return fmt::format(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
@@ -3078,10 +3075,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
|||||||
|
|
||||||
std::vector<std::any> args = { corpse };
|
std::vector<std::any> args = { corpse };
|
||||||
|
|
||||||
parse->EventMercNPC(
|
parse->EventMercNPC(EVENT_DEATH_COMPLETE, this, owner_or_self,
|
||||||
EVENT_DEATH_COMPLETE,
|
|
||||||
this,
|
|
||||||
owner_or_self,
|
|
||||||
[&]() {
|
[&]() {
|
||||||
return fmt::format(
|
return fmt::format(
|
||||||
"{} {} {} {} {} {} {} {} {}",
|
"{} {} {} {} {} {} {} {} {}",
|
||||||
@@ -3096,8 +3090,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
|||||||
m_combat_record.GetHealingReceived()
|
m_combat_record.GetHealingReceived()
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
0,
|
0, &args
|
||||||
&args
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Zone controller process EVENT_DEATH_ZONE (Death events)
|
// Zone controller process EVENT_DEATH_ZONE (Death events)
|
||||||
@@ -4266,10 +4259,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
|||||||
if (attacker) {
|
if (attacker) {
|
||||||
args = { this };
|
args = { this };
|
||||||
|
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_DAMAGE_GIVEN, attacker, this,
|
||||||
EVENT_DAMAGE_GIVEN,
|
|
||||||
attacker,
|
|
||||||
this,
|
|
||||||
[&]() {
|
[&]() {
|
||||||
return fmt::format(
|
return fmt::format(
|
||||||
"{} {} {} {} {} {} {} {} {}",
|
"{} {} {} {} {} {} {} {} {}",
|
||||||
@@ -4284,17 +4274,13 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
|||||||
static_cast<int>(special)
|
static_cast<int>(special)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
0,
|
0, &args
|
||||||
&args
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
args = { attacker };
|
args = { attacker };
|
||||||
|
|
||||||
damage_override = parse->EventMob(
|
damage_override = parse->EventMob(EVENT_DAMAGE_TAKEN, this, attacker,
|
||||||
EVENT_DAMAGE_TAKEN,
|
|
||||||
this,
|
|
||||||
attacker,
|
|
||||||
[&]() {
|
[&]() {
|
||||||
return fmt::format(
|
return fmt::format(
|
||||||
"{} {} {} {} {} {} {} {} {}",
|
"{} {} {} {} {} {} {} {} {}",
|
||||||
@@ -4309,8 +4295,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
|
|||||||
static_cast<int>(special)
|
static_cast<int>(special)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
0,
|
0, &args
|
||||||
&args
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (damage_override > 0) {
|
if (damage_override > 0) {
|
||||||
|
|||||||
+4
-17
@@ -1265,7 +1265,7 @@ void Bot::LoadAAs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while(current) {
|
while(current) {
|
||||||
if (!CanUseAlternateAdvancementRank(current)) {
|
if (current->level_req > GetLevel() || !CanUseAlternateAdvancementRank(current)) {
|
||||||
current = nullptr;
|
current = nullptr;
|
||||||
} else {
|
} else {
|
||||||
current = current->next;
|
current = current->next;
|
||||||
@@ -3089,6 +3089,7 @@ bool Bot::Spawn(Client* botCharacterOwner) {
|
|||||||
m_targetable = true;
|
m_targetable = true;
|
||||||
entity_list.AddBot(this, true, true);
|
entity_list.AddBot(this, true, true);
|
||||||
|
|
||||||
|
ClearDataBucketCache();
|
||||||
DataBucket::GetDataBuckets(this);
|
DataBucket::GetDataBuckets(this);
|
||||||
LoadBotSpellSettings();
|
LoadBotSpellSettings();
|
||||||
if (!AI_AddBotSpells(GetBotSpellID())) {
|
if (!AI_AddBotSpells(GetBotSpellID())) {
|
||||||
@@ -4192,14 +4193,7 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client*
|
|||||||
|
|
||||||
std::vector<std::any> args = { return_iterator.return_item_instance };
|
std::vector<std::any> args = { return_iterator.return_item_instance };
|
||||||
|
|
||||||
parse->EventBot(
|
parse->EventBot(EVENT_UNEQUIP_ITEM_BOT, this, nullptr, export_string, return_iterator.return_item_instance->GetID(), &args);
|
||||||
EVENT_UNEQUIP_ITEM_BOT,
|
|
||||||
this,
|
|
||||||
nullptr,
|
|
||||||
export_string,
|
|
||||||
return_iterator.return_item_instance->GetID(),
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (return_instance) {
|
if (return_instance) {
|
||||||
@@ -4264,14 +4258,7 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client*
|
|||||||
|
|
||||||
std::vector<std::any> args = { trade_iterator.trade_item_instance };
|
std::vector<std::any> args = { trade_iterator.trade_item_instance };
|
||||||
|
|
||||||
parse->EventBot(
|
parse->EventBot(EVENT_EQUIP_ITEM_BOT, this, nullptr, export_string, trade_iterator.trade_item_instance->GetID(), &args);
|
||||||
EVENT_EQUIP_ITEM_BOT,
|
|
||||||
this,
|
|
||||||
nullptr,
|
|
||||||
export_string,
|
|
||||||
trade_iterator.trade_item_instance->GetID(),
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trade_iterator.trade_item_instance = nullptr; // actual deletion occurs in client delete below
|
trade_iterator.trade_item_instance = nullptr; // actual deletion occurs in client delete below
|
||||||
|
|||||||
+34
-34
@@ -329,7 +329,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
|
|||||||
adventure_stats_timer = nullptr;
|
adventure_stats_timer = nullptr;
|
||||||
adventure_leaderboard_timer = nullptr;
|
adventure_leaderboard_timer = nullptr;
|
||||||
adv_data = nullptr;
|
adv_data = nullptr;
|
||||||
adv_requested_theme = LDoNThemes::Unused;
|
adv_requested_theme = LDoNTheme::Unused;
|
||||||
adv_requested_id = 0;
|
adv_requested_id = 0;
|
||||||
adv_requested_member_count = 0;
|
adv_requested_member_count = 0;
|
||||||
|
|
||||||
@@ -1469,7 +1469,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
|
|||||||
bool is_loss = false;
|
bool is_loss = false;
|
||||||
|
|
||||||
switch (theme_id) {
|
switch (theme_id) {
|
||||||
case LDoNThemes::Unused: { // No theme, so distribute evenly across all
|
case LDoNTheme::Unused: { // No theme, so distribute evenly across all
|
||||||
int split_points = (points / 5);
|
int split_points = (points / 5);
|
||||||
|
|
||||||
int guk_points = (split_points + (points % 5));
|
int guk_points = (split_points + (points % 5));
|
||||||
@@ -1522,12 +1522,12 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
|
|||||||
points -= split_points;
|
points -= split_points;
|
||||||
|
|
||||||
if (split_points != 0) { // if anything left, recursively loop thru again
|
if (split_points != 0) { // if anything left, recursively loop thru again
|
||||||
UpdateLDoNPoints(LDoNThemes::Unused, split_points);
|
UpdateLDoNPoints(LDoNTheme::Unused, split_points);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::GUK: {
|
case LDoNTheme::GUK: {
|
||||||
if (points < 0) {
|
if (points < 0) {
|
||||||
if (m_pp.ldon_points_guk < (0 - points)) {
|
if (m_pp.ldon_points_guk < (0 - points)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1539,7 +1539,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
|
|||||||
m_pp.ldon_points_guk += points;
|
m_pp.ldon_points_guk += points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::MIR: {
|
case LDoNTheme::MIR: {
|
||||||
if (points < 0) {
|
if (points < 0) {
|
||||||
if (m_pp.ldon_points_mir < (0 - points)) {
|
if (m_pp.ldon_points_mir < (0 - points)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1551,7 +1551,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
|
|||||||
m_pp.ldon_points_mir += points;
|
m_pp.ldon_points_mir += points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::MMC: {
|
case LDoNTheme::MMC: {
|
||||||
if (points < 0) {
|
if (points < 0) {
|
||||||
if (m_pp.ldon_points_mmc < (0 - points)) {
|
if (m_pp.ldon_points_mmc < (0 - points)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1563,7 +1563,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
|
|||||||
m_pp.ldon_points_mmc += points;
|
m_pp.ldon_points_mmc += points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::RUJ: {
|
case LDoNTheme::RUJ: {
|
||||||
if (points < 0) {
|
if (points < 0) {
|
||||||
if (m_pp.ldon_points_ruj < (0 - points)) {
|
if (m_pp.ldon_points_ruj < (0 - points)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1575,7 +1575,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
|
|||||||
m_pp.ldon_points_ruj += points;
|
m_pp.ldon_points_ruj += points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::TAK: {
|
case LDoNTheme::TAK: {
|
||||||
if (points < 0) {
|
if (points < 0) {
|
||||||
if (m_pp.ldon_points_tak < (0 - points)) {
|
if (m_pp.ldon_points_tak < (0 - points)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1623,23 +1623,23 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
|
|||||||
void Client::SetLDoNPoints(uint32 theme_id, uint32 points)
|
void Client::SetLDoNPoints(uint32 theme_id, uint32 points)
|
||||||
{
|
{
|
||||||
switch (theme_id) {
|
switch (theme_id) {
|
||||||
case LDoNThemes::GUK: {
|
case LDoNTheme::GUK: {
|
||||||
m_pp.ldon_points_guk = points;
|
m_pp.ldon_points_guk = points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::MIR: {
|
case LDoNTheme::MIR: {
|
||||||
m_pp.ldon_points_mir = points;
|
m_pp.ldon_points_mir = points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::MMC: {
|
case LDoNTheme::MMC: {
|
||||||
m_pp.ldon_points_mmc = points;
|
m_pp.ldon_points_mmc = points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::RUJ: {
|
case LDoNTheme::RUJ: {
|
||||||
m_pp.ldon_points_ruj = points;
|
m_pp.ldon_points_ruj = points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LDoNThemes::TAK: {
|
case LDoNTheme::TAK: {
|
||||||
m_pp.ldon_points_tak = points;
|
m_pp.ldon_points_tak = points;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -5676,15 +5676,15 @@ uint32 Client::GetLDoNPointsTheme(uint32 t)
|
|||||||
{
|
{
|
||||||
switch(t)
|
switch(t)
|
||||||
{
|
{
|
||||||
case LDoNThemes::GUK:
|
case LDoNTheme::GUK:
|
||||||
return m_pp.ldon_points_guk;
|
return m_pp.ldon_points_guk;
|
||||||
case LDoNThemes::MIR:
|
case LDoNTheme::MIR:
|
||||||
return m_pp.ldon_points_mir;
|
return m_pp.ldon_points_mir;
|
||||||
case LDoNThemes::MMC:
|
case LDoNTheme::MMC:
|
||||||
return m_pp.ldon_points_mmc;
|
return m_pp.ldon_points_mmc;
|
||||||
case LDoNThemes::RUJ:
|
case LDoNTheme::RUJ:
|
||||||
return m_pp.ldon_points_ruj;
|
return m_pp.ldon_points_ruj;
|
||||||
case LDoNThemes::TAK:
|
case LDoNTheme::TAK:
|
||||||
return m_pp.ldon_points_tak;
|
return m_pp.ldon_points_tak;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5695,15 +5695,15 @@ uint32 Client::GetLDoNWinsTheme(uint32 t)
|
|||||||
{
|
{
|
||||||
switch(t)
|
switch(t)
|
||||||
{
|
{
|
||||||
case LDoNThemes::GUK:
|
case LDoNTheme::GUK:
|
||||||
return m_pp.ldon_wins_guk;
|
return m_pp.ldon_wins_guk;
|
||||||
case LDoNThemes::MIR:
|
case LDoNTheme::MIR:
|
||||||
return m_pp.ldon_wins_mir;
|
return m_pp.ldon_wins_mir;
|
||||||
case LDoNThemes::MMC:
|
case LDoNTheme::MMC:
|
||||||
return m_pp.ldon_wins_mmc;
|
return m_pp.ldon_wins_mmc;
|
||||||
case LDoNThemes::RUJ:
|
case LDoNTheme::RUJ:
|
||||||
return m_pp.ldon_wins_ruj;
|
return m_pp.ldon_wins_ruj;
|
||||||
case LDoNThemes::TAK:
|
case LDoNTheme::TAK:
|
||||||
return m_pp.ldon_wins_tak;
|
return m_pp.ldon_wins_tak;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5714,15 +5714,15 @@ uint32 Client::GetLDoNLossesTheme(uint32 t)
|
|||||||
{
|
{
|
||||||
switch(t)
|
switch(t)
|
||||||
{
|
{
|
||||||
case LDoNThemes::GUK:
|
case LDoNTheme::GUK:
|
||||||
return m_pp.ldon_losses_guk;
|
return m_pp.ldon_losses_guk;
|
||||||
case LDoNThemes::MIR:
|
case LDoNTheme::MIR:
|
||||||
return m_pp.ldon_losses_mir;
|
return m_pp.ldon_losses_mir;
|
||||||
case LDoNThemes::MMC:
|
case LDoNTheme::MMC:
|
||||||
return m_pp.ldon_losses_mmc;
|
return m_pp.ldon_losses_mmc;
|
||||||
case LDoNThemes::RUJ:
|
case LDoNTheme::RUJ:
|
||||||
return m_pp.ldon_losses_ruj;
|
return m_pp.ldon_losses_ruj;
|
||||||
case LDoNThemes::TAK:
|
case LDoNTheme::TAK:
|
||||||
return m_pp.ldon_losses_tak;
|
return m_pp.ldon_losses_tak;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5731,35 +5731,35 @@ uint32 Client::GetLDoNLossesTheme(uint32 t)
|
|||||||
|
|
||||||
void Client::UpdateLDoNWinLoss(uint32 theme_id, bool win, bool remove) {
|
void Client::UpdateLDoNWinLoss(uint32 theme_id, bool win, bool remove) {
|
||||||
switch (theme_id) {
|
switch (theme_id) {
|
||||||
case LDoNThemes::GUK:
|
case LDoNTheme::GUK:
|
||||||
if (win) {
|
if (win) {
|
||||||
m_pp.ldon_wins_guk += (remove ? -1 : 1);
|
m_pp.ldon_wins_guk += (remove ? -1 : 1);
|
||||||
} else {
|
} else {
|
||||||
m_pp.ldon_losses_guk += (remove ? -1 : 1);
|
m_pp.ldon_losses_guk += (remove ? -1 : 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LDoNThemes::MIR:
|
case LDoNTheme::MIR:
|
||||||
if (win) {
|
if (win) {
|
||||||
m_pp.ldon_wins_mir += (remove ? -1 : 1);
|
m_pp.ldon_wins_mir += (remove ? -1 : 1);
|
||||||
} else {
|
} else {
|
||||||
m_pp.ldon_losses_mir += (remove ? -1 : 1);
|
m_pp.ldon_losses_mir += (remove ? -1 : 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LDoNThemes::MMC:
|
case LDoNTheme::MMC:
|
||||||
if (win) {
|
if (win) {
|
||||||
m_pp.ldon_wins_mmc += (remove ? -1 : 1);
|
m_pp.ldon_wins_mmc += (remove ? -1 : 1);
|
||||||
} else {
|
} else {
|
||||||
m_pp.ldon_losses_mmc += (remove ? -1 : 1);
|
m_pp.ldon_losses_mmc += (remove ? -1 : 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LDoNThemes::RUJ:
|
case LDoNTheme::RUJ:
|
||||||
if (win) {
|
if (win) {
|
||||||
m_pp.ldon_wins_ruj += (remove ? -1 : 1);
|
m_pp.ldon_wins_ruj += (remove ? -1 : 1);
|
||||||
} else {
|
} else {
|
||||||
m_pp.ldon_losses_ruj += (remove ? -1 : 1);
|
m_pp.ldon_losses_ruj += (remove ? -1 : 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LDoNThemes::TAK:
|
case LDoNTheme::TAK:
|
||||||
if (win) {
|
if (win) {
|
||||||
m_pp.ldon_wins_tak += (remove ? -1 : 1);
|
m_pp.ldon_wins_tak += (remove ? -1 : 1);
|
||||||
} else {
|
} else {
|
||||||
@@ -6227,7 +6227,7 @@ void Client::NewAdventure(int id, int theme, const char *text, int member_count,
|
|||||||
void Client::ClearPendingAdventureData()
|
void Client::ClearPendingAdventureData()
|
||||||
{
|
{
|
||||||
adv_requested_id = 0;
|
adv_requested_id = 0;
|
||||||
adv_requested_theme = LDoNThemes::Unused;
|
adv_requested_theme = LDoNTheme::Unused;
|
||||||
safe_delete_array(adv_requested_data);
|
safe_delete_array(adv_requested_data);
|
||||||
adv_requested_member_count = 0;
|
adv_requested_member_count = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-134
@@ -524,7 +524,6 @@ int Client::HandlePacket(const EQApplicationPacket *app)
|
|||||||
// Finish client connecting state
|
// Finish client connecting state
|
||||||
void Client::CompleteConnect()
|
void Client::CompleteConnect()
|
||||||
{
|
{
|
||||||
|
|
||||||
UpdateWho();
|
UpdateWho();
|
||||||
client_state = CLIENT_CONNECTED;
|
client_state = CLIENT_CONNECTED;
|
||||||
SendAllPackets();
|
SendAllPackets();
|
||||||
@@ -913,10 +912,6 @@ void Client::CompleteConnect()
|
|||||||
CastToClient()->FastQueuePacket(&outapp);
|
CastToClient()->FastQueuePacket(&outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
|
|
||||||
SendBulkBazaarTraders();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: load these states
|
// TODO: load these states
|
||||||
// We at least will set them to the correct state for now
|
// We at least will set them to the correct state for now
|
||||||
if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) {
|
if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) {
|
||||||
@@ -1413,6 +1408,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
|||||||
drakkin_details = m_pp.drakkin_details;
|
drakkin_details = m_pp.drakkin_details;
|
||||||
|
|
||||||
// Load Data Buckets
|
// Load Data Buckets
|
||||||
|
ClearDataBucketCache();
|
||||||
DataBucket::GetDataBuckets(this);
|
DataBucket::GetDataBuckets(this);
|
||||||
|
|
||||||
// Max Level for Character:PerCharacterQglobalMaxLevel and Character:PerCharacterBucketMaxLevel
|
// Max Level for Character:PerCharacterQglobalMaxLevel and Character:PerCharacterBucketMaxLevel
|
||||||
@@ -2023,38 +2019,38 @@ void Client::Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->LDoNTheme <= LDoNThemeBits::TAKBit) {
|
if (item->LDoNTheme <= LDoNTheme::TAKBit) {
|
||||||
uint32 ldon_theme;
|
uint32 ldon_theme;
|
||||||
if (item->LDoNTheme & LDoNThemeBits::TAKBit) {
|
if (item->LDoNTheme & LDoNTheme::TAKBit) {
|
||||||
if (m_pp.ldon_points_tak < item_cost) {
|
if (m_pp.ldon_points_tak < item_cost) {
|
||||||
cannot_afford = true;
|
cannot_afford = true;
|
||||||
ldon_theme = LDoNThemes::TAK;
|
ldon_theme = LDoNTheme::TAK;
|
||||||
}
|
}
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::RUJBit) {
|
} else if (item->LDoNTheme & LDoNTheme::RUJBit) {
|
||||||
if (m_pp.ldon_points_ruj < item_cost) {
|
if (m_pp.ldon_points_ruj < item_cost) {
|
||||||
cannot_afford = true;
|
cannot_afford = true;
|
||||||
ldon_theme = LDoNThemes::RUJ;
|
ldon_theme = LDoNTheme::RUJ;
|
||||||
}
|
}
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::MMCBit) {
|
} else if (item->LDoNTheme & LDoNTheme::MMCBit) {
|
||||||
if (m_pp.ldon_points_mmc < item_cost) {
|
if (m_pp.ldon_points_mmc < item_cost) {
|
||||||
cannot_afford = true;
|
cannot_afford = true;
|
||||||
ldon_theme = LDoNThemes::MMC;
|
ldon_theme = LDoNTheme::MMC;
|
||||||
}
|
}
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::MIRBit) {
|
} else if (item->LDoNTheme & LDoNTheme::MIRBit) {
|
||||||
if (m_pp.ldon_points_mir < item_cost) {
|
if (m_pp.ldon_points_mir < item_cost) {
|
||||||
cannot_afford = true;
|
cannot_afford = true;
|
||||||
ldon_theme = LDoNThemes::MIR;
|
ldon_theme = LDoNTheme::MIR;
|
||||||
}
|
}
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::GUKBit) {
|
} else if (item->LDoNTheme & LDoNTheme::GUKBit) {
|
||||||
if (m_pp.ldon_points_guk < item_cost) {
|
if (m_pp.ldon_points_guk < item_cost) {
|
||||||
cannot_afford = true;
|
cannot_afford = true;
|
||||||
ldon_theme = LDoNThemes::GUK;
|
ldon_theme = LDoNTheme::GUK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
merchant_type = fmt::format(
|
merchant_type = fmt::format(
|
||||||
"{} Point{}",
|
"{} Point{}",
|
||||||
EQ::constants::GetLDoNThemeName(ldon_theme),
|
LDoNTheme::GetName(ldon_theme),
|
||||||
item_cost != 1 ? "s" : ""
|
item_cost != 1 ? "s" : ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2198,19 +2194,19 @@ void Client::Handle_OP_AdventureMerchantRequest(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
item = database.GetItem(ml.item);
|
item = database.GetItem(ml.item);
|
||||||
if (item) {
|
if (item) {
|
||||||
uint32 theme = LDoNThemes::Unused;
|
uint32 theme = LDoNTheme::Unused;
|
||||||
if (item->LDoNTheme > LDoNThemeBits::TAKBit) {
|
if (item->LDoNTheme > LDoNTheme::TAKBit) {
|
||||||
theme = LDoNThemes::Unused;
|
theme = LDoNTheme::Unused;
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::TAKBit) {
|
} else if (item->LDoNTheme & LDoNTheme::TAKBit) {
|
||||||
theme = LDoNThemes::TAK;
|
theme = LDoNTheme::TAK;
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::RUJBit) {
|
} else if (item->LDoNTheme & LDoNTheme::RUJBit) {
|
||||||
theme = LDoNThemes::RUJ;
|
theme = LDoNTheme::RUJ;
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::MMCBit) {
|
} else if (item->LDoNTheme & LDoNTheme::MMCBit) {
|
||||||
theme = LDoNThemes::MMC;
|
theme = LDoNTheme::MMC;
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::MIRBit) {
|
} else if (item->LDoNTheme & LDoNTheme::MIRBit) {
|
||||||
theme = LDoNThemes::MIR;
|
theme = LDoNTheme::MIR;
|
||||||
} else if (item->LDoNTheme & LDoNThemeBits::GUKBit) {
|
} else if (item->LDoNTheme & LDoNTheme::GUKBit) {
|
||||||
theme = LDoNThemes::GUK;
|
theme = LDoNTheme::GUK;
|
||||||
}
|
}
|
||||||
ss << "^" << item->Name << "|";
|
ss << "^" << item->Name << "|";
|
||||||
ss << item->ID << "|";
|
ss << item->ID << "|";
|
||||||
@@ -3251,30 +3247,14 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
|||||||
args.push_back(old_aug);
|
args.push_back(old_aug);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
|
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_UNAUGMENT_ITEM,
|
|
||||||
this,
|
|
||||||
tobe_auged,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.assign(1, tobe_auged);
|
args.assign(1, tobe_auged);
|
||||||
args.push_back(false);
|
args.push_back(false);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(old_aug, EVENT_AUGMENT_REMOVE)) {
|
if (parse->ItemHasQuestSub(old_aug, EVENT_AUGMENT_REMOVE)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_AUGMENT_REMOVE,
|
|
||||||
this,
|
|
||||||
old_aug,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse->PlayerHasQuestSub(EVENT_AUGMENT_REMOVE_CLIENT)) {
|
if (parse->PlayerHasQuestSub(EVENT_AUGMENT_REMOVE_CLIENT)) {
|
||||||
@@ -3306,29 +3286,13 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
|||||||
args.push_back(aug);
|
args.push_back(aug);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(tobe_auged, EVENT_AUGMENT_ITEM)) {
|
if (parse->ItemHasQuestSub(tobe_auged, EVENT_AUGMENT_ITEM)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_AUGMENT_ITEM,
|
|
||||||
this,
|
|
||||||
tobe_auged,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.assign(1, tobe_auged);
|
args.assign(1, tobe_auged);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_INSERT)) {
|
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_INSERT)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_AUGMENT_INSERT,
|
|
||||||
this,
|
|
||||||
aug,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.push_back(aug);
|
args.push_back(aug);
|
||||||
@@ -3398,30 +3362,14 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
|||||||
args.push_back(aug);
|
args.push_back(aug);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
|
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_UNAUGMENT_ITEM,
|
|
||||||
this,
|
|
||||||
tobe_auged,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.assign(1, tobe_auged);
|
args.assign(1, tobe_auged);
|
||||||
args.push_back(false);
|
args.push_back(false);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_REMOVE)) {
|
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_REMOVE)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_AUGMENT_REMOVE,
|
|
||||||
this,
|
|
||||||
aug,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.push_back(aug);
|
args.push_back(aug);
|
||||||
@@ -3486,30 +3434,14 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
|||||||
args.push_back(aug);
|
args.push_back(aug);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
|
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_UNAUGMENT_ITEM,
|
|
||||||
this,
|
|
||||||
tobe_auged,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.assign(1, tobe_auged);
|
args.assign(1, tobe_auged);
|
||||||
args.push_back(true);
|
args.push_back(true);
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_REMOVE)) {
|
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_REMOVE)) {
|
||||||
parse->EventItem(
|
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||||
EVENT_AUGMENT_REMOVE,
|
|
||||||
this,
|
|
||||||
aug,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
in_augment->augment_index,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args.push_back(aug);
|
args.push_back(aug);
|
||||||
@@ -3985,6 +3917,10 @@ void Client::Handle_OP_BazaarSearch(const EQApplicationPacket *app)
|
|||||||
SendBazaarWelcome();
|
SendBazaarWelcome();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FirstOpenSearch: {
|
||||||
|
SendBulkBazaarTraders();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
|
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
|
||||||
}
|
}
|
||||||
@@ -4479,14 +4415,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
||||||
i = parse->EventItem(
|
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
||||||
EVENT_ITEM_CLICK_CAST,
|
|
||||||
this,
|
|
||||||
p_inst,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
castspell->inventoryslot
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
||||||
@@ -4518,14 +4447,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
||||||
i = parse->EventItem(
|
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
||||||
EVENT_ITEM_CLICK_CAST,
|
|
||||||
this,
|
|
||||||
p_inst,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
castspell->inventoryslot
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
||||||
@@ -9591,14 +9513,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
||||||
i = parse->EventItem(
|
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", slot_id);
|
||||||
EVENT_ITEM_CLICK_CAST,
|
|
||||||
this,
|
|
||||||
p_inst,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
slot_id
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
||||||
@@ -9662,14 +9577,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
|
||||||
i = parse->EventItem(
|
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, clickaug, nullptr, "", slot_id);
|
||||||
EVENT_ITEM_CLICK_CAST,
|
|
||||||
this,
|
|
||||||
clickaug,
|
|
||||||
nullptr,
|
|
||||||
"",
|
|
||||||
slot_id
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
|
||||||
|
|||||||
+152
-274
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
|
|
||||||
std::vector<DataBucketCacheEntry> g_data_bucket_cache = {};
|
std::vector<DataBucketsRepository::DataBuckets> g_data_bucket_cache = {};
|
||||||
|
|
||||||
void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time)
|
void DataBucket::SetData(const std::string &bucket_key, const std::string &bucket_value, std::string expires_time)
|
||||||
{
|
{
|
||||||
@@ -58,14 +58,14 @@ void DataBucket::SetData(const DataBucketKey &k)
|
|||||||
b.value = k.value;
|
b.value = k.value;
|
||||||
|
|
||||||
if (bucket_id) {
|
if (bucket_id) {
|
||||||
// loop cache and update cache value and timestamp
|
|
||||||
for (auto &ce: g_data_bucket_cache) {
|
// update the cache if it exists
|
||||||
if (CheckBucketMatch(ce.e, k)) {
|
if (CanCache(k)) {
|
||||||
ce.e = b;
|
for (auto &e: g_data_bucket_cache) {
|
||||||
ce.updated_time = GetCurrentTimeUNIX();
|
if (CheckBucketMatch(e, k)) {
|
||||||
ce.update_action = DataBucketCacheUpdateAction::Upsert;
|
e = b;
|
||||||
SendDataBucketCacheUpdate(ce);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,28 +74,18 @@ void DataBucket::SetData(const DataBucketKey &k)
|
|||||||
else {
|
else {
|
||||||
b.key_ = k.key;
|
b.key_ = k.key;
|
||||||
b = DataBucketsRepository::InsertOne(database, b);
|
b = DataBucketsRepository::InsertOne(database, b);
|
||||||
if (!ExistsInCache(b)) {
|
|
||||||
// add data bucket and timestamp to cache
|
|
||||||
auto ce = DataBucketCacheEntry{
|
|
||||||
.e = b,
|
|
||||||
.updated_time = DataBucket::GetCurrentTimeUNIX(),
|
|
||||||
.update_action = DataBucketCacheUpdateAction::Upsert
|
|
||||||
};
|
|
||||||
|
|
||||||
g_data_bucket_cache.emplace_back(ce);
|
|
||||||
|
|
||||||
SendDataBucketCacheUpdate(ce);
|
|
||||||
|
|
||||||
|
// add to cache if it doesn't exist
|
||||||
|
if (CanCache(k) && !ExistsInCache(b)) {
|
||||||
DeleteFromMissesCache(b);
|
DeleteFromMissesCache(b);
|
||||||
|
g_data_bucket_cache.emplace_back(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DataBucket::GetData(const std::string &bucket_key)
|
std::string DataBucket::GetData(const std::string &bucket_key)
|
||||||
{
|
{
|
||||||
DataBucketKey k = {};
|
return GetData(DataBucketKey{.key = bucket_key}).value;
|
||||||
k.key = bucket_key;
|
|
||||||
return GetData(k).value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetData fetches bucket data from the database or cache if it exists
|
// GetData fetches bucket data from the database or cache if it exists
|
||||||
@@ -112,22 +102,27 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
|||||||
k.npc_id
|
k.npc_id
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const auto &ce: g_data_bucket_cache) {
|
bool can_cache = CanCache(k);
|
||||||
if (CheckBucketMatch(ce.e, k)) {
|
|
||||||
if (ce.e.expires > 0 && ce.e.expires < std::time(nullptr)) {
|
|
||||||
LogDataBuckets("Attempted to read expired key [{}] removing from cache", ce.e.key_);
|
|
||||||
DeleteData(k);
|
|
||||||
return DataBucketsRepository::NewEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a bucket miss, return empty entity
|
// check the cache first if we can cache
|
||||||
// we still cache bucket misses, so we don't have to hit the database
|
if (can_cache) {
|
||||||
if (ce.e.id == 0) {
|
for (const auto &e: g_data_bucket_cache) {
|
||||||
return DataBucketsRepository::NewEntity();
|
if (CheckBucketMatch(e, k)) {
|
||||||
}
|
if (e.expires > 0 && e.expires < std::time(nullptr)) {
|
||||||
|
LogDataBuckets("Attempted to read expired key [{}] removing from cache", e.key_);
|
||||||
|
DeleteData(k);
|
||||||
|
return DataBucketsRepository::NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
LogDataBuckets("Returning key [{}] value [{}] from cache", ce.e.key_, ce.e.value);
|
// this is a bucket miss, return empty entity
|
||||||
return ce.e;
|
// we still cache bucket misses, so we don't have to hit the database
|
||||||
|
if (e.id == 0) {
|
||||||
|
return DataBucketsRepository::NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDataBuckets("Returning key [{}] value [{}] from cache", e.key_, e.value);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,23 +139,21 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
|||||||
|
|
||||||
// if we're ignoring the misses cache, don't add to the cache
|
// if we're ignoring the misses cache, don't add to the cache
|
||||||
// the only place this is ignored is during the initial read of SetData
|
// the only place this is ignored is during the initial read of SetData
|
||||||
if (!ignore_misses_cache) {
|
bool add_to_misses_cache = !ignore_misses_cache && can_cache;
|
||||||
|
if (add_to_misses_cache) {
|
||||||
size_t size_before = g_data_bucket_cache.size();
|
size_t size_before = g_data_bucket_cache.size();
|
||||||
|
|
||||||
// cache bucket misses, so we don't have to hit the database
|
// cache bucket misses, so we don't have to hit the database
|
||||||
// when scripts try to read a bucket that doesn't exist
|
// when scripts try to read a bucket that doesn't exist
|
||||||
g_data_bucket_cache.emplace_back(
|
g_data_bucket_cache.emplace_back(
|
||||||
DataBucketCacheEntry{
|
DataBucketsRepository::DataBuckets{
|
||||||
.e = DataBucketsRepository::DataBuckets{
|
.id = 0,
|
||||||
.id = 0,
|
.key_ = k.key,
|
||||||
.key_ = k.key,
|
.value = "",
|
||||||
.value = "",
|
.expires = 0,
|
||||||
.expires = 0,
|
.character_id = k.character_id,
|
||||||
.character_id = k.character_id,
|
.npc_id = k.npc_id,
|
||||||
.npc_id = k.npc_id,
|
.bot_id = k.bot_id
|
||||||
.bot_id = k.bot_id
|
|
||||||
},
|
|
||||||
.updated_time = DataBucket::GetCurrentTimeUNIX()
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -178,60 +171,54 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto bucket = r.front();
|
||||||
|
|
||||||
// if the entry has expired, delete it
|
// if the entry has expired, delete it
|
||||||
if (r[0].expires > 0 && r[0].expires < (long long) std::time(nullptr)) {
|
if (bucket.expires > 0 && bucket.expires < (long long) std::time(nullptr)) {
|
||||||
DeleteData(k);
|
DeleteData(k);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_cache = false;
|
// add to cache if it doesn't exist
|
||||||
for (auto &ce: g_data_bucket_cache) {
|
if (can_cache) {
|
||||||
if (ce.e.id == r[0].id) {
|
bool has_cache = false;
|
||||||
has_cache = true;
|
|
||||||
break;
|
for (auto &e: g_data_bucket_cache) {
|
||||||
|
if (e.id == bucket.id) {
|
||||||
|
has_cache = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_cache) {
|
||||||
|
g_data_bucket_cache.emplace_back(bucket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_cache) {
|
return bucket;
|
||||||
// add data bucket and timestamp to cache
|
|
||||||
g_data_bucket_cache.emplace_back(
|
|
||||||
DataBucketCacheEntry{
|
|
||||||
.e = r[0],
|
|
||||||
.updated_time = DataBucket::GetCurrentTimeUNIX()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DataBucket::GetDataExpires(const std::string &bucket_key)
|
std::string DataBucket::GetDataExpires(const std::string &bucket_key)
|
||||||
{
|
{
|
||||||
DataBucketKey k = {};
|
return GetDataExpires(DataBucketKey{.key = bucket_key});
|
||||||
k.key = bucket_key;
|
|
||||||
|
|
||||||
return GetDataExpires(k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DataBucket::GetDataRemaining(const std::string &bucket_key)
|
std::string DataBucket::GetDataRemaining(const std::string &bucket_key)
|
||||||
{
|
{
|
||||||
DataBucketKey k = {};
|
return GetDataRemaining(DataBucketKey{.key = bucket_key});
|
||||||
k.key = bucket_key;
|
|
||||||
return GetDataRemaining(k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataBucket::DeleteData(const std::string &bucket_key)
|
bool DataBucket::DeleteData(const std::string &bucket_key)
|
||||||
{
|
{
|
||||||
DataBucketKey k = {};
|
return DeleteData(DataBucketKey{.key = bucket_key});
|
||||||
k.key = bucket_key;
|
|
||||||
return DeleteData(k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDataBuckets bulk loads all data buckets for a mob
|
// GetDataBuckets bulk loads all data buckets for a mob
|
||||||
bool DataBucket::GetDataBuckets(Mob *mob)
|
bool DataBucket::GetDataBuckets(Mob *mob)
|
||||||
{
|
{
|
||||||
DataBucketLoadType::Type t;
|
DataBucketLoadType::Type t{};
|
||||||
const uint32 id = mob->GetMobTypeIdentifier();
|
|
||||||
|
const uint32 id = mob->GetMobTypeIdentifier();
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return false;
|
return false;
|
||||||
@@ -243,46 +230,39 @@ bool DataBucket::GetDataBuckets(Mob *mob)
|
|||||||
else if (mob->IsClient()) {
|
else if (mob->IsClient()) {
|
||||||
t = DataBucketLoadType::Client;
|
t = DataBucketLoadType::Client;
|
||||||
}
|
}
|
||||||
else if (mob->IsNPC()) {
|
|
||||||
t = DataBucketLoadType::NPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
BulkLoadEntities(t, {id});
|
BulkLoadEntitiesToCache(t, {id});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataBucket::DeleteData(const DataBucketKey &k)
|
bool DataBucket::DeleteData(const DataBucketKey &k)
|
||||||
{
|
{
|
||||||
size_t size_before = g_data_bucket_cache.size();
|
if (CanCache(k)) {
|
||||||
|
size_t size_before = g_data_bucket_cache.size();
|
||||||
|
|
||||||
// delete from cache where contents match
|
// delete from cache where contents match
|
||||||
g_data_bucket_cache.erase(
|
g_data_bucket_cache.erase(
|
||||||
std::remove_if(
|
std::remove_if(
|
||||||
g_data_bucket_cache.begin(),
|
g_data_bucket_cache.begin(),
|
||||||
g_data_bucket_cache.end(),
|
g_data_bucket_cache.end(),
|
||||||
[&](DataBucketCacheEntry &ce) {
|
[&](DataBucketsRepository::DataBuckets &e) {
|
||||||
bool match = CheckBucketMatch(ce.e, k);
|
return CheckBucketMatch(e, k);
|
||||||
if (match) {
|
|
||||||
ce.update_action = DataBucketCacheUpdateAction::Delete;
|
|
||||||
SendDataBucketCacheUpdate(ce);
|
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
g_data_bucket_cache.end()
|
||||||
|
);
|
||||||
|
|
||||||
return match;
|
LogDataBuckets(
|
||||||
}
|
"Deleting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
|
||||||
),
|
k.key,
|
||||||
g_data_bucket_cache.end()
|
k.bot_id,
|
||||||
);
|
k.character_id,
|
||||||
|
k.npc_id,
|
||||||
LogDataBuckets(
|
size_before,
|
||||||
"Deleting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
|
g_data_bucket_cache.size()
|
||||||
k.key,
|
);
|
||||||
k.bot_id,
|
}
|
||||||
k.character_id,
|
|
||||||
k.npc_id,
|
|
||||||
size_before,
|
|
||||||
g_data_bucket_cache.size()
|
|
||||||
);
|
|
||||||
|
|
||||||
return DataBucketsRepository::DeleteWhere(
|
return DataBucketsRepository::DeleteWhere(
|
||||||
database,
|
database,
|
||||||
@@ -371,23 +351,21 @@ bool DataBucket::CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataBucket::BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32> ids)
|
void DataBucket::BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector<uint32> ids)
|
||||||
{
|
{
|
||||||
if (ids.empty()) {
|
if (ids.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ids.size() == 1) {
|
if (ids.size() == 1) {
|
||||||
bool has_cache = false;
|
bool has_cache = false;
|
||||||
for (const auto &ce: g_data_bucket_cache) {
|
|
||||||
|
for (const auto &e: g_data_bucket_cache) {
|
||||||
if (t == DataBucketLoadType::Bot) {
|
if (t == DataBucketLoadType::Bot) {
|
||||||
has_cache = ce.e.bot_id == ids[0];
|
has_cache = e.bot_id == ids[0];
|
||||||
}
|
}
|
||||||
else if (t == DataBucketLoadType::Client) {
|
else if (t == DataBucketLoadType::Client) {
|
||||||
has_cache = ce.e.character_id == ids[0];
|
has_cache = e.character_id == ids[0];
|
||||||
}
|
|
||||||
else if (t == DataBucketLoadType::NPC) {
|
|
||||||
has_cache = ce.e.npc_id == ids[0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,9 +384,6 @@ void DataBucket::BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32
|
|||||||
case DataBucketLoadType::Client:
|
case DataBucketLoadType::Client:
|
||||||
column = "character_id";
|
column = "character_id";
|
||||||
break;
|
break;
|
||||||
case DataBucketLoadType::NPC:
|
|
||||||
column = "npc_id";
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
LogError("Incorrect LoadType [{}]", static_cast<int>(t));
|
LogError("Incorrect LoadType [{}]", static_cast<int>(t));
|
||||||
break;
|
break;
|
||||||
@@ -442,12 +417,7 @@ void DataBucket::BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32
|
|||||||
if (!ExistsInCache(e)) {
|
if (!ExistsInCache(e)) {
|
||||||
LogDataBucketsDetail("bucket id [{}] bucket key [{}] bucket value [{}]", e.id, e.key_, e.value);
|
LogDataBucketsDetail("bucket id [{}] bucket key [{}] bucket value [{}]", e.id, e.key_, e.value);
|
||||||
|
|
||||||
g_data_bucket_cache.emplace_back(
|
g_data_bucket_cache.emplace_back(e);
|
||||||
DataBucketCacheEntry{
|
|
||||||
.e = e,
|
|
||||||
.updated_time = GetCurrentTimeUNIX()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +431,7 @@ void DataBucket::BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id)
|
void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type type, uint32 id)
|
||||||
{
|
{
|
||||||
size_t size_before = g_data_bucket_cache.size();
|
size_t size_before = g_data_bucket_cache.size();
|
||||||
|
|
||||||
@@ -469,11 +439,10 @@ void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id)
|
|||||||
std::remove_if(
|
std::remove_if(
|
||||||
g_data_bucket_cache.begin(),
|
g_data_bucket_cache.begin(),
|
||||||
g_data_bucket_cache.end(),
|
g_data_bucket_cache.end(),
|
||||||
[&](DataBucketCacheEntry &ce) {
|
[&](DataBucketsRepository::DataBuckets &e) {
|
||||||
return (
|
return (
|
||||||
(t == DataBucketLoadType::Bot && ce.e.bot_id == id) ||
|
(type == DataBucketLoadType::Bot && e.bot_id == id) ||
|
||||||
(t == DataBucketLoadType::Client && ce.e.character_id == id) ||
|
(type == DataBucketLoadType::Client && e.character_id == id)
|
||||||
(t == DataBucketLoadType::NPC && ce.e.npc_id == id)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@@ -482,24 +451,17 @@ void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id)
|
|||||||
|
|
||||||
LogDataBuckets(
|
LogDataBuckets(
|
||||||
"LoadType [{}] id [{}] cache size before [{}] after [{}]",
|
"LoadType [{}] id [{}] cache size before [{}] after [{}]",
|
||||||
DataBucketLoadType::Name[t],
|
DataBucketLoadType::Name[type],
|
||||||
id,
|
id,
|
||||||
size_before,
|
size_before,
|
||||||
g_data_bucket_cache.size()
|
g_data_bucket_cache.size()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t DataBucket::GetCurrentTimeUNIX()
|
bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &entry)
|
||||||
{
|
{
|
||||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
for (const auto &e: g_data_bucket_cache) {
|
||||||
std::chrono::system_clock::now().time_since_epoch()
|
if (e.id == entry.id) {
|
||||||
).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &e)
|
|
||||||
{
|
|
||||||
for (const auto &ce: g_data_bucket_cache) {
|
|
||||||
if (ce.e.id == e.id) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,134 +469,6 @@ bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &e)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DataBucket::SendDataBucketCacheUpdate(const DataBucketCacheEntry &e)
|
|
||||||
{
|
|
||||||
if (!e.e.id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EQ::Net::DynamicPacket p;
|
|
||||||
p.PutSerialize(0, e);
|
|
||||||
|
|
||||||
auto pack_size = sizeof(ServerDataBucketCacheUpdate_Struct) + p.Length();
|
|
||||||
auto pack = new ServerPacket(ServerOP_DataBucketCacheUpdate, static_cast<uint32_t>(pack_size));
|
|
||||||
auto buf = reinterpret_cast<ServerDataBucketCacheUpdate_Struct *>(pack->pBuffer);
|
|
||||||
|
|
||||||
buf->cereal_size = static_cast<uint32_t>(p.Length());
|
|
||||||
|
|
||||||
memcpy(buf->cereal_data, p.Data(), p.Length());
|
|
||||||
|
|
||||||
worldserver.SendPacket(pack);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataBucket::HandleWorldMessage(ServerPacket *p)
|
|
||||||
{
|
|
||||||
DataBucketCacheEntry n;
|
|
||||||
auto s = (ServerDataBucketCacheUpdate_Struct *) p->pBuffer;
|
|
||||||
EQ::Util::MemoryStreamReader ss(s->cereal_data, s->cereal_size);
|
|
||||||
cereal::BinaryInputArchive archive(ss);
|
|
||||||
archive(n);
|
|
||||||
|
|
||||||
LogDataBucketsDetail(
|
|
||||||
"Received cache packet for id [{}] key [{}] value [{}] action [{}]",
|
|
||||||
n.e.id,
|
|
||||||
n.e.key_,
|
|
||||||
n.e.value,
|
|
||||||
static_cast<int>(n.update_action)
|
|
||||||
);
|
|
||||||
|
|
||||||
// delete
|
|
||||||
if (n.update_action == DataBucketCacheUpdateAction::Delete) {
|
|
||||||
DeleteFromMissesCache(n.e);
|
|
||||||
|
|
||||||
g_data_bucket_cache.erase(
|
|
||||||
std::remove_if(
|
|
||||||
g_data_bucket_cache.begin(),
|
|
||||||
g_data_bucket_cache.end(),
|
|
||||||
[&](DataBucketCacheEntry &ce) {
|
|
||||||
bool match = n.e.id > 0 && ce.e.id == n.e.id;
|
|
||||||
if (match) {
|
|
||||||
LogDataBuckets(
|
|
||||||
"[delete] cache key [{}] id [{}] cache_size before [{}] after [{}]",
|
|
||||||
ce.e.key_,
|
|
||||||
ce.e.id,
|
|
||||||
g_data_bucket_cache.size(),
|
|
||||||
g_data_bucket_cache.size() - 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
),
|
|
||||||
g_data_bucket_cache.end()
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update
|
|
||||||
bool has_key = false;
|
|
||||||
for (auto &ce: g_data_bucket_cache) {
|
|
||||||
// update cache
|
|
||||||
if (ce.e.id == n.e.id) {
|
|
||||||
// reject old updates
|
|
||||||
int64 time_delta = ce.updated_time - n.updated_time;
|
|
||||||
if (ce.updated_time >= n.updated_time) {
|
|
||||||
LogDataBuckets(
|
|
||||||
"Attempted to update older cache key [{}] rejecting old time [{}] new time [{}] delta [{}] cache_size [{}]",
|
|
||||||
ce.e.key_,
|
|
||||||
ce.updated_time,
|
|
||||||
n.updated_time,
|
|
||||||
time_delta,
|
|
||||||
g_data_bucket_cache.size()
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeleteFromMissesCache(n.e);
|
|
||||||
|
|
||||||
LogDataBuckets(
|
|
||||||
"[update] cache id [{}] key [{}] value [{}] old time [{}] new time [{}] delta [{}] cache_size [{}]",
|
|
||||||
ce.e.id,
|
|
||||||
ce.e.key_,
|
|
||||||
n.e.value,
|
|
||||||
ce.updated_time,
|
|
||||||
n.updated_time,
|
|
||||||
time_delta,
|
|
||||||
g_data_bucket_cache.size()
|
|
||||||
);
|
|
||||||
ce.e = n.e;
|
|
||||||
ce.updated_time = n.updated_time;
|
|
||||||
has_key = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create
|
|
||||||
if (!has_key) {
|
|
||||||
DeleteFromMissesCache(n.e);
|
|
||||||
|
|
||||||
size_t size_before = g_data_bucket_cache.size();
|
|
||||||
|
|
||||||
g_data_bucket_cache.emplace_back(
|
|
||||||
DataBucketCacheEntry{
|
|
||||||
.e = n.e,
|
|
||||||
.updated_time = GetCurrentTimeUNIX()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
LogDataBuckets(
|
|
||||||
"[create] Adding new cache id [{}] key [{}] value [{}] cache size before [{}] after [{}]",
|
|
||||||
n.e.id,
|
|
||||||
n.e.key_,
|
|
||||||
n.e.value,
|
|
||||||
size_before,
|
|
||||||
g_data_bucket_cache.size()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataBucket::DeleteFromMissesCache(DataBucketsRepository::DataBuckets e)
|
void DataBucket::DeleteFromMissesCache(DataBucketsRepository::DataBuckets e)
|
||||||
{
|
{
|
||||||
// delete from cache where there might have been a written bucket miss to the cache
|
// delete from cache where there might have been a written bucket miss to the cache
|
||||||
@@ -645,11 +479,11 @@ void DataBucket::DeleteFromMissesCache(DataBucketsRepository::DataBuckets e)
|
|||||||
std::remove_if(
|
std::remove_if(
|
||||||
g_data_bucket_cache.begin(),
|
g_data_bucket_cache.begin(),
|
||||||
g_data_bucket_cache.end(),
|
g_data_bucket_cache.end(),
|
||||||
[&](DataBucketCacheEntry &ce) {
|
[&](DataBucketsRepository::DataBuckets &ce) {
|
||||||
return ce.e.id == 0 && ce.e.key_ == e.key_ &&
|
return ce.id == 0 && ce.key_ == e.key_ &&
|
||||||
ce.e.character_id == e.character_id &&
|
ce.character_id == e.character_id &&
|
||||||
ce.e.npc_id == e.npc_id &&
|
ce.npc_id == e.npc_id &&
|
||||||
ce.e.bot_id == e.bot_id;
|
ce.bot_id == e.bot_id;
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
g_data_bucket_cache.end()
|
g_data_bucket_cache.end()
|
||||||
@@ -667,3 +501,47 @@ void DataBucket::ClearCache()
|
|||||||
g_data_bucket_cache.clear();
|
g_data_bucket_cache.clear();
|
||||||
LogInfo("Cleared data buckets cache");
|
LogInfo("Cleared data buckets cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataBucket::DeleteFromCache(uint64 id, DataBucketLoadType::Type type)
|
||||||
|
{
|
||||||
|
size_t size_before = g_data_bucket_cache.size();
|
||||||
|
|
||||||
|
g_data_bucket_cache.erase(
|
||||||
|
std::remove_if(
|
||||||
|
g_data_bucket_cache.begin(),
|
||||||
|
g_data_bucket_cache.end(),
|
||||||
|
[&](DataBucketsRepository::DataBuckets &e) {
|
||||||
|
switch (type) {
|
||||||
|
case DataBucketLoadType::Bot:
|
||||||
|
return e.bot_id == id;
|
||||||
|
case DataBucketLoadType::Client:
|
||||||
|
return e.character_id == id;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
g_data_bucket_cache.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
LogDataBuckets(
|
||||||
|
"Deleted [{}] id [{}] from cache size before [{}] after [{}]",
|
||||||
|
DataBucketLoadType::Name[type],
|
||||||
|
id,
|
||||||
|
size_before,
|
||||||
|
g_data_bucket_cache.size()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanCache returns whether a bucket can be cached or not
|
||||||
|
// characters are only in one zone at a time so we can cache locally to the zone
|
||||||
|
// bots (not implemented) are only in one zone at a time so we can cache locally to the zone
|
||||||
|
// npcs (ids) can be in multiple zones so we can't cache locally to the zone
|
||||||
|
bool DataBucket::CanCache(const DataBucketKey &key)
|
||||||
|
{
|
||||||
|
if (key.character_id > 0 || key.bot_id > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
+5
-34
@@ -1,7 +1,3 @@
|
|||||||
//
|
|
||||||
// Created by Akkadius on 7/7/18.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef EQEMU_DATABUCKET_H
|
#ifndef EQEMU_DATABUCKET_H
|
||||||
#define EQEMU_DATABUCKET_H
|
#define EQEMU_DATABUCKET_H
|
||||||
|
|
||||||
@@ -12,27 +8,6 @@
|
|||||||
#include "../common/json/json_archive_single_line.h"
|
#include "../common/json/json_archive_single_line.h"
|
||||||
#include "../common/servertalk.h"
|
#include "../common/servertalk.h"
|
||||||
|
|
||||||
enum DataBucketCacheUpdateAction : uint8 {
|
|
||||||
Upsert,
|
|
||||||
Delete
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DataBucketCacheEntry {
|
|
||||||
DataBucketsRepository::DataBuckets e;
|
|
||||||
int64_t updated_time{};
|
|
||||||
DataBucketCacheUpdateAction update_action{};
|
|
||||||
|
|
||||||
template<class Archive>
|
|
||||||
void serialize(Archive &ar)
|
|
||||||
{
|
|
||||||
ar(
|
|
||||||
CEREAL_NVP(e),
|
|
||||||
CEREAL_NVP(updated_time),
|
|
||||||
CEREAL_NVP(update_action)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DataBucketKey {
|
struct DataBucketKey {
|
||||||
std::string key;
|
std::string key;
|
||||||
std::string value;
|
std::string value;
|
||||||
@@ -46,14 +21,12 @@ namespace DataBucketLoadType {
|
|||||||
enum Type : uint8 {
|
enum Type : uint8 {
|
||||||
Bot,
|
Bot,
|
||||||
Client,
|
Client,
|
||||||
NPC,
|
|
||||||
MaxType
|
MaxType
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string Name[Type::MaxType] = {
|
static const std::string Name[Type::MaxType] = {
|
||||||
"Bot",
|
"Bot",
|
||||||
"Client",
|
"Client",
|
||||||
"NPC",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,8 +41,6 @@ public:
|
|||||||
|
|
||||||
static bool GetDataBuckets(Mob *mob);
|
static bool GetDataBuckets(Mob *mob);
|
||||||
|
|
||||||
static int64_t GetCurrentTimeUNIX();
|
|
||||||
|
|
||||||
// scoped bucket methods
|
// scoped bucket methods
|
||||||
static void SetData(const DataBucketKey &k);
|
static void SetData(const DataBucketKey &k);
|
||||||
static bool DeleteData(const DataBucketKey &k);
|
static bool DeleteData(const DataBucketKey &k);
|
||||||
@@ -80,15 +51,15 @@ public:
|
|||||||
|
|
||||||
// bucket repository versus key matching
|
// bucket repository versus key matching
|
||||||
static bool CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe, const DataBucketKey &k);
|
static bool CheckBucketMatch(const DataBucketsRepository::DataBuckets &dbe, const DataBucketKey &k);
|
||||||
static bool ExistsInCache(const DataBucketsRepository::DataBuckets &e);
|
static bool ExistsInCache(const DataBucketsRepository::DataBuckets &entry);
|
||||||
|
|
||||||
static void BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32> ids);
|
static void BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector<uint32> ids);
|
||||||
static void DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id);
|
static void DeleteCachedBuckets(DataBucketLoadType::Type type, uint32 id);
|
||||||
|
|
||||||
static bool SendDataBucketCacheUpdate(const DataBucketCacheEntry &e);
|
|
||||||
static void HandleWorldMessage(ServerPacket *p);
|
|
||||||
static void DeleteFromMissesCache(DataBucketsRepository::DataBuckets e);
|
static void DeleteFromMissesCache(DataBucketsRepository::DataBuckets e);
|
||||||
static void ClearCache();
|
static void ClearCache();
|
||||||
|
static void DeleteFromCache(uint64 id, DataBucketLoadType::Type type);
|
||||||
|
static bool CanCache(const DataBucketKey &key);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //EQEMU_DATABUCKET_H
|
#endif //EQEMU_DATABUCKET_H
|
||||||
|
|||||||
+1
-1
@@ -1736,7 +1736,7 @@ void PerlembParser::ExportEventVariables(
|
|||||||
case EVENT_PAYLOAD: {
|
case EVENT_PAYLOAD: {
|
||||||
Seperator sep(data);
|
Seperator sep(data);
|
||||||
ExportVar(package_name.c_str(), "payload_id", sep.arg[0]);
|
ExportVar(package_name.c_str(), "payload_id", sep.arg[0]);
|
||||||
ExportVar(package_name.c_str(), "payload_value", sep.arg[1]);
|
ExportVar(package_name.c_str(), "payload_value", sep.argplus[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-14
@@ -1817,25 +1817,13 @@ void EntityList::DuelMessage(Mob *winner, Mob *loser, bool flee)
|
|||||||
if (parse->PlayerHasQuestSub(EVENT_DUEL_WIN)) {
|
if (parse->PlayerHasQuestSub(EVENT_DUEL_WIN)) {
|
||||||
std::vector<std::any> args = { winner, loser };
|
std::vector<std::any> args = { winner, loser };
|
||||||
|
|
||||||
parse->EventPlayer(
|
parse->EventPlayer(EVENT_DUEL_WIN, winner->CastToClient(), loser->GetName(), loser->CastToClient()->CharacterID(), &args);
|
||||||
EVENT_DUEL_WIN,
|
|
||||||
winner->CastToClient(),
|
|
||||||
loser->GetName(),
|
|
||||||
loser->CastToClient()->CharacterID(),
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse->PlayerHasQuestSub(EVENT_DUEL_LOSE)) {
|
if (parse->PlayerHasQuestSub(EVENT_DUEL_LOSE)) {
|
||||||
std::vector<std::any> args = { winner, loser };
|
std::vector<std::any> args = { winner, loser };
|
||||||
|
|
||||||
parse->EventPlayer(
|
parse->EventPlayer(EVENT_DUEL_LOSE, loser->CastToClient(), winner->GetName(), winner->CastToClient()->CharacterID(), &args);
|
||||||
EVENT_DUEL_LOSE,
|
|
||||||
loser->CastToClient(),
|
|
||||||
winner->GetName(),
|
|
||||||
winner->CastToClient()->CharacterID(),
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "../client.h"
|
#include "../client.h"
|
||||||
#include "find/aa.cpp"
|
#include "find/aa.cpp"
|
||||||
#include "find/body_type.cpp"
|
#include "find/body_type.cpp"
|
||||||
|
#include "find/bot.cpp"
|
||||||
#include "find/bug_category.cpp"
|
#include "find/bug_category.cpp"
|
||||||
#include "find/character.cpp"
|
#include "find/character.cpp"
|
||||||
#include "find/class.cpp"
|
#include "find/class.cpp"
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
#include "find/faction.cpp"
|
#include "find/faction.cpp"
|
||||||
#include "find/item.cpp"
|
#include "find/item.cpp"
|
||||||
#include "find/language.cpp"
|
#include "find/language.cpp"
|
||||||
|
#include "find/ldon_theme.cpp"
|
||||||
#include "find/npctype.cpp"
|
#include "find/npctype.cpp"
|
||||||
#include "find/object_type.cpp"
|
#include "find/object_type.cpp"
|
||||||
#include "find/race.cpp"
|
#include "find/race.cpp"
|
||||||
@@ -47,6 +49,7 @@ void command_find(Client *c, const Seperator *sep)
|
|||||||
Cmd{.cmd = "faction", .u = "faction [Search Criteria]", .fn = FindFaction, .a = {"#findfaction"}},
|
Cmd{.cmd = "faction", .u = "faction [Search Criteria]", .fn = FindFaction, .a = {"#findfaction"}},
|
||||||
Cmd{.cmd = "item", .u = "item [Search Criteria]", .fn = FindItem, .a = {"#fi", "#finditem"}},
|
Cmd{.cmd = "item", .u = "item [Search Criteria]", .fn = FindItem, .a = {"#fi", "#finditem"}},
|
||||||
Cmd{.cmd = "language", .u = "language [Search Criteria]", .fn = FindLanguage, .a = {"#findlanguage"}},
|
Cmd{.cmd = "language", .u = "language [Search Criteria]", .fn = FindLanguage, .a = {"#findlanguage"}},
|
||||||
|
Cmd{.cmd = "ldon_theme", .u = "ldon_theme [Search Criteria]", .fn = FindLDoNTheme, .a = {"#findldontheme"}},
|
||||||
Cmd{
|
Cmd{
|
||||||
.cmd = "npctype", .u = "npctype [Search Criteria]", .fn = FindNPCType, .a = {
|
.cmd = "npctype", .u = "npctype [Search Criteria]", .fn = FindNPCType, .a = {
|
||||||
"#fn",
|
"#fn",
|
||||||
@@ -65,6 +68,16 @@ void command_find(Client *c, const Seperator *sep)
|
|||||||
Cmd{.cmd = "zone", .u = "zone [Search Criteria]", .fn = FindZone, .a = {"#fz", "#findzone"}},
|
Cmd{.cmd = "zone", .u = "zone [Search Criteria]", .fn = FindZone, .a = {"#fz", "#findzone"}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (RuleB(Bots, Enabled)) {
|
||||||
|
commands.emplace_back(
|
||||||
|
Cmd{.cmd = "bot", .u = "bot [Search Criteria]", .fn = FindBot, .a = {"#findbot"}}
|
||||||
|
);
|
||||||
|
|
||||||
|
std::sort(commands.begin(), commands.end(), [](const Cmd& a, const Cmd& b) {
|
||||||
|
return a.cmd < b.cmd;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Check for arguments
|
// Check for arguments
|
||||||
const auto arguments = sep->argnum;
|
const auto arguments = sep->argnum;
|
||||||
if (!arguments) {
|
if (!arguments) {
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#include "../../client.h"
|
||||||
|
#include "../../common/repositories/bot_data_repository.h"
|
||||||
|
|
||||||
|
void FindBot(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
if (sep->IsNumber(2)) {
|
||||||
|
const auto bot_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||||
|
|
||||||
|
const auto& e = BotDataRepository::FindOne(content_db, bot_id);
|
||||||
|
if (!e.bot_id) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Bot ID {} does not exist or is invalid.",
|
||||||
|
bot_id
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Bot ID {} | {}",
|
||||||
|
bot_id,
|
||||||
|
e.name
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto search_criteria = Strings::ToLower(sep->argplus[2]);
|
||||||
|
|
||||||
|
const auto& l = BotDataRepository::GetWhere(
|
||||||
|
content_db,
|
||||||
|
fmt::format(
|
||||||
|
"LOWER(`name`) LIKE '%%{}%%' AND `name` NOT LIKE '%-deleted-%' ORDER BY `bot_id` ASC LIMIT 50",
|
||||||
|
search_criteria
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (l.empty()) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"No bots found matching '{}'.",
|
||||||
|
sep->argplus[2]
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto found_count = 0;
|
||||||
|
|
||||||
|
for (const auto& e : l) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Bot ID {} | {}",
|
||||||
|
Strings::Commify(e.bot_id),
|
||||||
|
e.name
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
found_count++;
|
||||||
|
|
||||||
|
if (found_count == 50) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_count == 50) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"50 Bots found matching '{}', max reached.",
|
||||||
|
sep->argplus[2]
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"{} Bot{} found matching '{}'.",
|
||||||
|
found_count,
|
||||||
|
found_count != 1 ? "s" : "",
|
||||||
|
sep->argplus[2]
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ void FindCharacter(Client *c, const Seperator *sep)
|
|||||||
const auto& l = CharacterDataRepository::GetWhere(
|
const auto& l = CharacterDataRepository::GetWhere(
|
||||||
content_db,
|
content_db,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"LOWER(`name`) LIKE '%%{}%%' ORDER BY `id` ASC LIMIT 50",
|
"LOWER(`name`) LIKE '%%{}%%' AND `name` NOT LIKE '%-deleted-%' ORDER BY `id` ASC LIMIT 50",
|
||||||
search_criteria
|
search_criteria
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ void FindClass(Client *c, const Seperator *sep)
|
|||||||
(
|
(
|
||||||
IsPlayerClass(class_id) ?
|
IsPlayerClass(class_id) ?
|
||||||
fmt::format(
|
fmt::format(
|
||||||
" | ({})",
|
" ({})",
|
||||||
Strings::Commify(GetPlayerClassBit(class_id))
|
Strings::Commify(GetPlayerClassBit(class_id))
|
||||||
) :
|
) :
|
||||||
""
|
""
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#include "../../client.h"
|
||||||
|
|
||||||
|
void FindLDoNTheme(Client *c, const Seperator *sep)
|
||||||
|
{
|
||||||
|
if (sep->IsNumber(2)) {
|
||||||
|
const uint32 theme_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||||
|
if (LDoNTheme::IsValid(theme_id)) {
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Theme {} | {} ({})",
|
||||||
|
theme_id,
|
||||||
|
LDoNTheme::GetName(theme_id),
|
||||||
|
LDoNTheme::GetBitmask(theme_id)
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Theme ID {} was not found.",
|
||||||
|
theme_id
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& search_criteria = Strings::ToLower(sep->argplus[2]);
|
||||||
|
|
||||||
|
uint32 found_count = 0;
|
||||||
|
|
||||||
|
for (const auto& l : ldon_theme_names) {
|
||||||
|
const std::string& ldon_theme_name_lower = Strings::ToLower(l.second.first);
|
||||||
|
if (!Strings::Contains(ldon_theme_name_lower, search_criteria)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Theme {} | {} ({})",
|
||||||
|
l.first,
|
||||||
|
l.second.first,
|
||||||
|
l.second.second
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
found_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"{} Theme{} found matching '{}'.",
|
||||||
|
found_count,
|
||||||
|
found_count != 1 ? "s" : "",
|
||||||
|
sep->argplus[2]
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,20 +3,21 @@
|
|||||||
|
|
||||||
void SetAdventurePoints(Client *c, const Seperator *sep)
|
void SetAdventurePoints(Client *c, const Seperator *sep)
|
||||||
{
|
{
|
||||||
const auto arguments = sep->argnum;
|
const uint16 arguments = sep->argnum;
|
||||||
if (arguments < 3 || !sep->IsNumber(2) || !sep->IsNumber(3)) {
|
if (arguments < 3 || !sep->IsNumber(2) || !sep->IsNumber(3)) {
|
||||||
c->Message(Chat::White, "Usage: #set adventure_points [Theme] [Points]");
|
c->Message(Chat::White, "Usage: #set adventure_points [Theme] [Points]");
|
||||||
|
|
||||||
c->Message(Chat::White, "Valid themes are as follows:");
|
c->Message(Chat::White, "Valid themes are as follows:");
|
||||||
|
|
||||||
for (const auto& e : EQ::constants::GetLDoNThemeMap()) {
|
for (const auto& e : ldon_theme_names) {
|
||||||
if (e.first != LDoNThemes::Unused) {
|
if (e.first != LDoNTheme::Unused) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Theme {} | {}",
|
"Theme {} | {} ({})",
|
||||||
e.first,
|
e.first,
|
||||||
e.second
|
e.second.first,
|
||||||
|
e.second.second
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -25,25 +26,26 @@ void SetAdventurePoints(Client *c, const Seperator *sep)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto t = c;
|
Client* t = c;
|
||||||
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
if (c->GetTarget() && c->GetTarget()->IsClient()) {
|
||||||
t = c->GetTarget()->CastToClient();
|
t = c->GetTarget()->CastToClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32 theme_id = Strings::ToUnsignedInt(sep->arg[2]);
|
const uint32 theme_id = Strings::ToUnsignedInt(sep->arg[2]);
|
||||||
const uint32 points = Strings::ToUnsignedInt(sep->arg[3]);
|
const uint32 points = Strings::ToUnsignedInt(sep->arg[3]);
|
||||||
|
|
||||||
if (!EQ::ValueWithin(theme_id, LDoNThemes::GUK, LDoNThemes::TAK)) {
|
if (!LDoNTheme::IsValid(theme_id)) {
|
||||||
c->Message(Chat::White, "Valid themes are as follows:");
|
c->Message(Chat::White, "Valid themes are as follows:");
|
||||||
|
|
||||||
for (const auto& e : EQ::constants::GetLDoNThemeMap()) {
|
for (const auto& e : ldon_theme_names) {
|
||||||
if (e.first != LDoNThemes::Unused) {
|
if (e.first != LDoNTheme::Unused) {
|
||||||
c->Message(
|
c->Message(
|
||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Theme {} | {}",
|
"Theme {} | {} ({})",
|
||||||
e.first,
|
e.first,
|
||||||
e.second
|
e.second.first,
|
||||||
|
e.second.second
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ void SetAdventurePoints(Client *c, const Seperator *sep)
|
|||||||
Chat::White,
|
Chat::White,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"Set {} Points to {} for {}.",
|
"Set {} Points to {} for {}.",
|
||||||
EQ::constants::GetLDoNThemeName(theme_id),
|
LDoNTheme::GetName(theme_id),
|
||||||
Strings::Commify(points),
|
Strings::Commify(points),
|
||||||
c->GetTargetDescription(t)
|
c->GetTargetDescription(t)
|
||||||
).c_str()
|
).c_str()
|
||||||
|
|||||||
@@ -89,11 +89,11 @@ void ShowCurrencies(Client *c, const Seperator *sep)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& l : EQ::constants::GetLDoNThemeMap()) {
|
for (const auto& l : ldon_theme_names) {
|
||||||
const uint32 ldon_currency_value = t->GetLDoNPointsTheme(l.first);
|
const uint32 ldon_currency_value = t->GetLDoNPointsTheme(l.first);
|
||||||
if (ldon_currency_value) {
|
if (ldon_currency_value) {
|
||||||
currency_table += DialogueWindow::TableRow(
|
currency_table += DialogueWindow::TableRow(
|
||||||
DialogueWindow::TableCell(l.second) +
|
DialogueWindow::TableCell(l.second.first) +
|
||||||
DialogueWindow::TableCell(Strings::Commify(ldon_currency_value))
|
DialogueWindow::TableCell(Strings::Commify(ldon_currency_value))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2419,7 +2419,7 @@ bool Group::AmIMainAssist(const char *mob_name)
|
|||||||
if (!mob_name)
|
if (!mob_name)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return !((bool)MainTankName.compare(mob_name));
|
return !((bool)MainAssistName.compare(mob_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Group::AmIPuller(const char *mob_name)
|
bool Group::AmIPuller(const char *mob_name)
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ public:
|
|||||||
void AddMember(const std::string& new_member_name);
|
void AddMember(const std::string& new_member_name);
|
||||||
void SendUpdate(uint32 type,Mob* member);
|
void SendUpdate(uint32 type,Mob* member);
|
||||||
void SendLeadershipAAUpdate();
|
void SendLeadershipAAUpdate();
|
||||||
void SendWorldGroup(uint32 zone_id,Mob* zoningmember);
|
|
||||||
bool DelMemberOOZ(const char *Name);
|
bool DelMemberOOZ(const char *Name);
|
||||||
bool DelMember(Mob* oldmember,bool ignoresender = false);
|
bool DelMember(Mob* oldmember,bool ignoresender = false);
|
||||||
void DisbandGroup(bool joinraid = false);
|
void DisbandGroup(bool joinraid = false);
|
||||||
@@ -73,7 +72,6 @@ public:
|
|||||||
bool IsGroupMember(Mob* c);
|
bool IsGroupMember(Mob* c);
|
||||||
bool IsGroupMember(const char* name);
|
bool IsGroupMember(const char* name);
|
||||||
bool Process();
|
bool Process();
|
||||||
bool IsGroup() { return true; }
|
|
||||||
void SendGroupJoinOOZ(Mob* NewMember);
|
void SendGroupJoinOOZ(Mob* NewMember);
|
||||||
void CastGroupSpell(Mob* caster,uint16 spellid);
|
void CastGroupSpell(Mob* caster,uint16 spellid);
|
||||||
void SplitExp(ExpSource exp_source, const uint64 exp, Mob* other);
|
void SplitExp(ExpSource exp_source, const uint64 exp, Mob* other);
|
||||||
|
|||||||
+45
-32
@@ -572,6 +572,8 @@ Mob::~Mob()
|
|||||||
|
|
||||||
m_close_mobs.clear();
|
m_close_mobs.clear();
|
||||||
|
|
||||||
|
ClearDataBucketCache();
|
||||||
|
|
||||||
LeaveHealRotationTargetPool();
|
LeaveHealRotationTargetPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2048,19 +2050,19 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
case 0: {
|
case 0: {
|
||||||
mod2a_name = "Avoidance";
|
mod2a_name = "Avoidance";
|
||||||
mod2b_name = "Combat Effects";
|
mod2b_name = "Combat Effects";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemAvoidanceCap));
|
mod2a_cap = RuleI(Character, ItemAvoidanceCap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemCombatEffectsCap));
|
mod2b_cap = RuleI(Character, ItemCombatEffectsCap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetAvoidance());
|
mod2a = CastToBot()->GetAvoidance();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2a = Strings::Commify(CastToClient()->GetAvoidance());
|
mod2a = CastToClient()->GetAvoidance();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2b = Strings::Commify(CastToBot()->GetCombatEffects());
|
mod2b = CastToBot()->GetCombatEffects();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2b = Strings::Commify(CastToClient()->GetCombatEffects());
|
mod2b = CastToClient()->GetCombatEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -2068,19 +2070,19 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
case 1: {
|
case 1: {
|
||||||
mod2a_name = "Accuracy";
|
mod2a_name = "Accuracy";
|
||||||
mod2b_name = "Strikethrough";
|
mod2b_name = "Strikethrough";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemAccuracyCap));
|
mod2a_cap = RuleI(Character, ItemAccuracyCap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemStrikethroughCap));
|
mod2b_cap = RuleI(Character, ItemStrikethroughCap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetAccuracy());
|
mod2a = CastToBot()->GetAccuracy();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2a = Strings::Commify(CastToClient()->GetAccuracy());
|
mod2a = CastToClient()->GetAccuracy();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2b = Strings::Commify(CastToBot()->GetStrikeThrough());
|
mod2b = CastToBot()->GetStrikeThrough();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2b = Strings::Commify(CastToClient()->GetStrikeThrough());
|
mod2b = CastToClient()->GetStrikeThrough();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -2088,20 +2090,20 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
case 2: {
|
case 2: {
|
||||||
mod2a_name = "Shielding";
|
mod2a_name = "Shielding";
|
||||||
mod2b_name = "Spell Shielding";
|
mod2b_name = "Spell Shielding";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemShieldingCap));
|
mod2a_cap = RuleI(Character, ItemShieldingCap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemSpellShieldingCap));
|
mod2b_cap = RuleI(Character, ItemSpellShieldingCap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetShielding());
|
mod2a = CastToBot()->GetShielding();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2a = Strings::Commify(CastToClient()->GetShielding());
|
mod2a = CastToClient()->GetShielding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2b = Strings::Commify(CastToBot()->GetSpellShield());
|
mod2b = CastToBot()->GetSpellShield();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2b = Strings::Commify(CastToClient()->GetSpellShield());
|
mod2b = CastToClient()->GetSpellShield();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -2109,19 +2111,19 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
|
|||||||
case 3: {
|
case 3: {
|
||||||
mod2a_name = "Stun Resist";
|
mod2a_name = "Stun Resist";
|
||||||
mod2b_name = "DOT Shielding";
|
mod2b_name = "DOT Shielding";
|
||||||
mod2a_cap = Strings::Commify(RuleI(Character, ItemStunResistCap));
|
mod2a_cap = RuleI(Character, ItemStunResistCap);
|
||||||
mod2b_cap = Strings::Commify(RuleI(Character, ItemDoTShieldingCap));
|
mod2b_cap = RuleI(Character, ItemDoTShieldingCap);
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2a = Strings::Commify(CastToBot()->GetStunResist());
|
mod2a = CastToBot()->GetStunResist();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2a = Strings::Commify(CastToClient()->GetStunResist());
|
mod2a = CastToClient()->GetStunResist();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsBot()) {
|
if (IsBot()) {
|
||||||
mod2b = Strings::Commify(CastToBot()->GetDoTShield());
|
mod2b = CastToBot()->GetDoTShield();
|
||||||
} else if (IsClient()) {
|
} else if (IsClient()) {
|
||||||
mod2b = Strings::Commify(CastToClient()->GetDoTShield());
|
mod2b = CastToClient()->GetDoTShield();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -5325,14 +5327,7 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance* inst, uint16 spell_id, Mob* on,
|
|||||||
//It should be safe as we don't have any truly const EQ::ItemInstance floating around anywhere.
|
//It should be safe as we don't have any truly const EQ::ItemInstance floating around anywhere.
|
||||||
//So we'll live with it for now
|
//So we'll live with it for now
|
||||||
if (parse->ItemHasQuestSub(const_cast<EQ::ItemInstance*>(inst), EVENT_WEAPON_PROC)) {
|
if (parse->ItemHasQuestSub(const_cast<EQ::ItemInstance*>(inst), EVENT_WEAPON_PROC)) {
|
||||||
int i = parse->EventItem(
|
int i = parse->EventItem(EVENT_WEAPON_PROC, CastToClient(), const_cast<EQ::ItemInstance*>(inst), on, "", spell_id);
|
||||||
EVENT_WEAPON_PROC,
|
|
||||||
CastToClient(),
|
|
||||||
const_cast<EQ::ItemInstance*>(inst),
|
|
||||||
on,
|
|
||||||
"",
|
|
||||||
spell_id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
return;
|
return;
|
||||||
@@ -8613,3 +8608,21 @@ std::unordered_map<uint16, Mob *> &Mob::GetCloseMobList(float distance)
|
|||||||
{
|
{
|
||||||
return entity_list.GetCloseMobList(this, distance);
|
return entity_list.GetCloseMobList(this, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mob::ClearDataBucketCache()
|
||||||
|
{
|
||||||
|
if (IsOfClientBot()) {
|
||||||
|
uint64 id = 0;
|
||||||
|
DataBucketLoadType::Type t{};
|
||||||
|
if (IsBot()) {
|
||||||
|
id = CastToBot()->GetBotID();
|
||||||
|
t = DataBucketLoadType::Bot;
|
||||||
|
}
|
||||||
|
else if (IsClient()) {
|
||||||
|
id = CastToClient()->CharacterID();
|
||||||
|
t = DataBucketLoadType::Client;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataBucket::DeleteFromCache(id, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1491,6 +1491,8 @@ public:
|
|||||||
std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f);
|
std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f);
|
||||||
void CheckScanCloseMobsMovingTimer();
|
void CheckScanCloseMobsMovingTimer();
|
||||||
|
|
||||||
|
void ClearDataBucketCache();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
||||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||||
|
|||||||
+11
-3
@@ -1815,12 +1815,18 @@ void Mob::AI_Event_NoLongerEngaged() {
|
|||||||
StopNavigation();
|
StopNavigation();
|
||||||
ClearRampage();
|
ClearRampage();
|
||||||
|
|
||||||
parse->EventBotMercNPC(EVENT_COMBAT, this, nullptr, [&]() { return "0"; });
|
|
||||||
|
|
||||||
if (IsNPC()) {
|
if (IsNPC()) {
|
||||||
SetPrimaryAggro(false);
|
SetPrimaryAggro(false);
|
||||||
SetAssistAggro(false);
|
SetAssistAggro(false);
|
||||||
if (CastToNPC()->GetCombatEvent() && GetHP() > 0) {
|
if (
|
||||||
|
CastToNPC()->GetCombatEvent() &&
|
||||||
|
GetHP() > 0 &&
|
||||||
|
entity_list.GetNPCByID(GetID())
|
||||||
|
) {
|
||||||
|
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_COMBAT)) {
|
||||||
|
parse->EventNPC(EVENT_COMBAT, CastToNPC(), nullptr, "0", 0);
|
||||||
|
}
|
||||||
|
|
||||||
const uint32 emote_id = CastToNPC()->GetEmoteID();
|
const uint32 emote_id = CastToNPC()->GetEmoteID();
|
||||||
if (emote_id) {
|
if (emote_id) {
|
||||||
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::LeaveCombat, emote_id);
|
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::LeaveCombat, emote_id);
|
||||||
@@ -1829,6 +1835,8 @@ void Mob::AI_Event_NoLongerEngaged() {
|
|||||||
m_combat_record.Stop();
|
m_combat_record.Stop();
|
||||||
CastToNPC()->SetCombatEvent(false);
|
CastToNPC()->SetCombatEvent(false);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
parse->EventBotMerc(EVENT_COMBAT, this, nullptr, [&]() { return "0"; });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-8
@@ -3297,16 +3297,28 @@ uint32 NPC::GetSpawnKillCount()
|
|||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::DoQuestPause(Mob *other) {
|
void NPC::DoQuestPause(Mob* m)
|
||||||
if(IsMoving() && !IsOnHatelist(other)) {
|
{
|
||||||
PauseWandering(RuleI(NPC, SayPauseTimeInSec));
|
if (!m) {
|
||||||
if (other && !other->sneaking)
|
return;
|
||||||
FaceTarget(other);
|
|
||||||
} else if(!IsMoving()) {
|
|
||||||
if (other && !other->sneaking && GetAppearance() != eaSitting && GetAppearance() != eaDead)
|
|
||||||
FaceTarget(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsMoving() && !IsOnHatelist(m)) {
|
||||||
|
PauseWandering(RuleI(NPC, SayPauseTimeInSec));
|
||||||
|
|
||||||
|
if (FacesTarget() && !m->sneaking) {
|
||||||
|
FaceTarget(m);
|
||||||
|
}
|
||||||
|
} else if (!IsMoving()) {
|
||||||
|
if (
|
||||||
|
FacesTarget() &&
|
||||||
|
!m->sneaking &&
|
||||||
|
GetAppearance() != eaSitting &&
|
||||||
|
GetAppearance() != eaDead
|
||||||
|
) {
|
||||||
|
FaceTarget(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::ChangeLastName(std::string last_name)
|
void NPC::ChangeLastName(std::string last_name)
|
||||||
@@ -4238,3 +4250,17 @@ void NPC::DoNpcToNpcAggroScan()
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NPC::FacesTarget()
|
||||||
|
{
|
||||||
|
const std::string& excluded_races_rule = RuleS(NPC, ExcludedFaceTargetRaces);
|
||||||
|
|
||||||
|
if (excluded_races_rule.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& v = Strings::Split(excluded_races_rule, ",");
|
||||||
|
|
||||||
|
return std::find(v.begin(), v.end(), std::to_string(GetBaseRace())) == v.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -482,7 +482,8 @@ public:
|
|||||||
NPC_Emote_Struct* GetNPCEmote(uint32 emote_id, uint8 event_);
|
NPC_Emote_Struct* GetNPCEmote(uint32 emote_id, uint8 event_);
|
||||||
void DoNPCEmote(uint8 event_, uint32 emote_id, Mob* t = nullptr);
|
void DoNPCEmote(uint8 event_, uint32 emote_id, Mob* t = nullptr);
|
||||||
bool CanTalk();
|
bool CanTalk();
|
||||||
void DoQuestPause(Mob *other);
|
void DoQuestPause(Mob* m);
|
||||||
|
bool FacesTarget();
|
||||||
|
|
||||||
inline void SetSpellScale(float amt) { spellscale = amt; }
|
inline void SetSpellScale(float amt) { spellscale = amt; }
|
||||||
inline float GetSpellScale() { return spellscale; }
|
inline float GetSpellScale() { return spellscale; }
|
||||||
|
|||||||
@@ -278,6 +278,19 @@ void Client::DoParcelSend(const Parcel_Struct *parcel_in)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parcel_in->money_flag && parcel_in->item_slot != INVALID_INDEX) {
|
||||||
|
Message(
|
||||||
|
Chat::Yellow,
|
||||||
|
fmt::format(
|
||||||
|
"{} tells you, 'I am confused! Do you want to send money or an item?'",
|
||||||
|
merchant->GetCleanName()
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
DoParcelCancel();
|
||||||
|
SendParcelAck();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto num_of_parcels = GetParcelCount();
|
auto num_of_parcels = GetParcelCount();
|
||||||
if (num_of_parcels >= RuleI(Parcel, ParcelMaxItems)) {
|
if (num_of_parcels >= RuleI(Parcel, ParcelMaxItems)) {
|
||||||
SendParcelIconStatus();
|
SendParcelIconStatus();
|
||||||
|
|||||||
+13
-52
@@ -91,13 +91,7 @@ void QuestManager::Process() {
|
|||||||
if (cur->Timer_.Enabled() && cur->Timer_.Check()) {
|
if (cur->Timer_.Enabled() && cur->Timer_.Check()) {
|
||||||
if (cur->mob) {
|
if (cur->mob) {
|
||||||
if (cur->mob->IsEncounter()) {
|
if (cur->mob->IsEncounter()) {
|
||||||
parse->EventEncounter(
|
parse->EventEncounter(EVENT_TIMER, cur->mob->CastToEncounter()->GetEncounterName(), cur->name, 0, nullptr);
|
||||||
EVENT_TIMER,
|
|
||||||
cur->mob->CastToEncounter()->GetEncounterName(),
|
|
||||||
cur->name,
|
|
||||||
0,
|
|
||||||
nullptr
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
parse->EventMob(EVENT_TIMER, cur->mob, nullptr, [&]() { return cur->name; }, 0);
|
parse->EventMob(EVENT_TIMER, cur->mob, nullptr, [&]() { return cur->name; }, 0);
|
||||||
}
|
}
|
||||||
@@ -661,14 +655,7 @@ void QuestManager::stoptimer(const std::string& timer_name)
|
|||||||
|
|
||||||
for (auto e = QTimerList.begin(); e != QTimerList.end(); ++e) {
|
for (auto e = QTimerList.begin(); e != QTimerList.end(); ++e) {
|
||||||
if (e->mob && e->mob == owner && e->name == timer_name) {
|
if (e->mob && e->mob == owner && e->name == timer_name) {
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_TIMER_STOP, owner, nullptr, [&]() { return timer_name; });
|
||||||
EVENT_TIMER_STOP,
|
|
||||||
owner,
|
|
||||||
nullptr,
|
|
||||||
[&]() {
|
|
||||||
return timer_name;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
QTimerList.erase(e);
|
QTimerList.erase(e);
|
||||||
break;
|
break;
|
||||||
@@ -695,14 +682,7 @@ void QuestManager::stoptimer(const std::string& timer_name, Mob* m)
|
|||||||
|
|
||||||
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
|
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
|
||||||
if (e->mob && e->mob == m) {
|
if (e->mob && e->mob == m) {
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_TIMER_STOP, m, nullptr, [&]() { return timer_name; });
|
||||||
EVENT_TIMER_STOP,
|
|
||||||
m,
|
|
||||||
nullptr,
|
|
||||||
[&]() {
|
|
||||||
return timer_name;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
QTimerList.erase(e);
|
QTimerList.erase(e);
|
||||||
break;
|
break;
|
||||||
@@ -743,14 +723,7 @@ void QuestManager::stopalltimers()
|
|||||||
|
|
||||||
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
|
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
|
||||||
if (e->mob && e->mob == owner) {
|
if (e->mob && e->mob == owner) {
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_TIMER_STOP, owner, nullptr, [&]() { return e->name; });
|
||||||
EVENT_TIMER_STOP,
|
|
||||||
owner,
|
|
||||||
nullptr,
|
|
||||||
[&]() {
|
|
||||||
return e->name;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
e = QTimerList.erase(e);
|
e = QTimerList.erase(e);
|
||||||
} else {
|
} else {
|
||||||
@@ -792,14 +765,7 @@ void QuestManager::stopalltimers(Mob* m)
|
|||||||
|
|
||||||
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
|
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
|
||||||
if (e->mob && e->mob == m) {
|
if (e->mob && e->mob == m) {
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_TIMER_STOP, m, nullptr, [&]() { return e->name; });
|
||||||
EVENT_TIMER_STOP,
|
|
||||||
m,
|
|
||||||
nullptr,
|
|
||||||
[&]() {
|
|
||||||
return e->name;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
e = QTimerList.erase(e);
|
e = QTimerList.erase(e);
|
||||||
} else {
|
} else {
|
||||||
@@ -853,18 +819,13 @@ void QuestManager::pausetimer(const std::string& timer_name, Mob* m)
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_TIMER_PAUSE, mob, nullptr, [&]() {
|
||||||
EVENT_TIMER_PAUSE,
|
return fmt::format(
|
||||||
mob,
|
"{} {}",
|
||||||
nullptr,
|
timer_name,
|
||||||
[&]() {
|
milliseconds
|
||||||
return fmt::format(
|
);
|
||||||
"{} {}",
|
});
|
||||||
timer_name,
|
|
||||||
milliseconds
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
LogQuests("Pausing timer [{}] for [{}] with [{}] ms remaining", timer_name, owner->GetName(), milliseconds);
|
LogQuests("Pausing timer [{}] for [{}] with [{}] ms remaining", timer_name, owner->GetName(), milliseconds);
|
||||||
}
|
}
|
||||||
@@ -1326,7 +1287,7 @@ std::string QuestManager::getskillname(int skill_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string QuestManager::getldonthemename(uint32 theme_id) {
|
std::string QuestManager::getldonthemename(uint32 theme_id) {
|
||||||
return EQ::constants::GetLDoNThemeName(theme_id);
|
return LDoNTheme::GetName(theme_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string QuestManager::getfactionname(int faction_id) {
|
std::string QuestManager::getfactionname(int faction_id) {
|
||||||
|
|||||||
+20
-38
@@ -256,22 +256,15 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
|||||||
|
|
||||||
Mob* spell_target = entity_list.GetMobID(target_id);
|
Mob* spell_target = entity_list.GetMobID(target_id);
|
||||||
std::vector<std::any> args = { spell_target };
|
std::vector<std::any> args = { spell_target };
|
||||||
int return_value = parse->EventMob(
|
int return_value = parse->EventMob(EVENT_CAST_BEGIN, this, nullptr, [&]() {
|
||||||
EVENT_CAST_BEGIN,
|
return fmt::format(
|
||||||
this,
|
"{} {} {} {}",
|
||||||
nullptr,
|
spell_id,
|
||||||
[&]() {
|
GetID(),
|
||||||
return fmt::format(
|
GetCasterLevel(spell_id),
|
||||||
"{} {} {} {}",
|
target_id
|
||||||
spell_id,
|
);
|
||||||
GetID(),
|
}, 0, &args);
|
||||||
GetCasterLevel(spell_id),
|
|
||||||
target_id
|
|
||||||
);
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
|
|
||||||
if (IsClient() && return_value != 0) {
|
if (IsClient() && return_value != 0) {
|
||||||
if (IsDiscipline(spell_id)) {
|
if (IsDiscipline(spell_id)) {
|
||||||
@@ -1804,22 +1797,15 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
|
|||||||
|
|
||||||
std::vector<std::any> args = { spell_target };
|
std::vector<std::any> args = { spell_target };
|
||||||
|
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_CAST, this, nullptr, [&]() {
|
||||||
EVENT_CAST,
|
return fmt::format(
|
||||||
this,
|
"{} {} {} {}",
|
||||||
nullptr,
|
spell_id,
|
||||||
[&]() {
|
GetID(),
|
||||||
return fmt::format(
|
GetCasterLevel(spell_id),
|
||||||
"{} {} {} {}",
|
target_id
|
||||||
spell_id,
|
);
|
||||||
GetID(),
|
}, 0, &args);
|
||||||
GetCasterLevel(spell_id),
|
|
||||||
target_id
|
|
||||||
);
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
&args
|
|
||||||
);
|
|
||||||
|
|
||||||
if(bard_song_mode)
|
if(bard_song_mode)
|
||||||
{
|
{
|
||||||
@@ -3965,10 +3951,7 @@ bool Mob::SpellOnTarget(
|
|||||||
|
|
||||||
std::vector<std::any> args = { spelltar };
|
std::vector<std::any> args = { spelltar };
|
||||||
|
|
||||||
parse->EventMob(
|
parse->EventMob(EVENT_CAST_ON, spelltar, this,
|
||||||
EVENT_CAST_ON,
|
|
||||||
spelltar,
|
|
||||||
this,
|
|
||||||
[&]() {
|
[&]() {
|
||||||
return fmt::format(
|
return fmt::format(
|
||||||
"{} {} {} {}",
|
"{} {} {} {}",
|
||||||
@@ -3978,8 +3961,7 @@ bool Mob::SpellOnTarget(
|
|||||||
target_id
|
target_id
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
0,
|
0, &args
|
||||||
&args
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!DoCastingChecksOnTarget(false, spell_id, spelltar)) {
|
if (!DoCastingChecksOnTarget(false, spell_id, spelltar)) {
|
||||||
|
|||||||
+34
-26
@@ -777,6 +777,8 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
tradingWith->SayString(TRADE_BACK, GetCleanName());
|
tradingWith->SayString(TRADE_BACK, GetCleanName());
|
||||||
PushItemOnCursor(*inst, true);
|
PushItemOnCursor(*inst, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items.clear();
|
||||||
}
|
}
|
||||||
// Only enforce trade rules if the NPC doesn't have an EVENT_TRADE
|
// Only enforce trade rules if the NPC doesn't have an EVENT_TRADE
|
||||||
// subroutine. That overrides all.
|
// subroutine. That overrides all.
|
||||||
@@ -1091,15 +1093,16 @@ void Client::TraderStartTrader(const EQApplicationPacket *app)
|
|||||||
inst->SetPrice(in->item_cost[i]);
|
inst->SetPrice(in->item_cost[i]);
|
||||||
TraderRepository::Trader trader_item{};
|
TraderRepository::Trader trader_item{};
|
||||||
|
|
||||||
trader_item.id = 0;
|
trader_item.id = 0;
|
||||||
trader_item.char_entity_id = GetID();
|
trader_item.char_entity_id = GetID();
|
||||||
trader_item.char_id = CharacterID();
|
trader_item.char_id = CharacterID();
|
||||||
trader_item.char_zone_id = GetZoneID();
|
trader_item.char_zone_id = GetZoneID();
|
||||||
trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges();
|
trader_item.char_zone_instance_id = GetInstanceID();
|
||||||
trader_item.item_cost = inst->GetPrice();
|
trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges();
|
||||||
trader_item.item_id = inst->GetID();
|
trader_item.item_cost = inst->GetPrice();
|
||||||
trader_item.item_sn = in->serial_number[i];
|
trader_item.item_id = inst->GetID();
|
||||||
trader_item.slot_id = i;
|
trader_item.item_sn = in->serial_number[i];
|
||||||
|
trader_item.slot_id = i;
|
||||||
if (inst->IsAugmented()) {
|
if (inst->IsAugmented()) {
|
||||||
auto augs = inst->GetAugmentIDs();
|
auto augs = inst->GetAugmentIDs();
|
||||||
trader_item.aug_slot_1 = augs.at(0);
|
trader_item.aug_slot_1 = augs.at(0);
|
||||||
@@ -1794,7 +1797,7 @@ void Client::SendBarterWelcome()
|
|||||||
|
|
||||||
void Client::DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria)
|
void Client::DoBazaarSearch(BazaarSearchCriteria_Struct search_criteria)
|
||||||
{
|
{
|
||||||
auto results = Bazaar::GetSearchResults(database, search_criteria, GetZoneID());
|
auto results = Bazaar::GetSearchResults(database, search_criteria, GetZoneID(), GetInstanceID());
|
||||||
if (results.empty()) {
|
if (results.empty()) {
|
||||||
SendBazaarDone(GetID());
|
SendBazaarDone(GetID());
|
||||||
return;
|
return;
|
||||||
@@ -2913,10 +2916,11 @@ void Client::SendBecomeTraderToWorld(Client *trader, BazaarTraderBarterActions a
|
|||||||
auto outapp = new ServerPacket(ServerOP_TraderMessaging, sizeof(TraderMessaging_Struct));
|
auto outapp = new ServerPacket(ServerOP_TraderMessaging, sizeof(TraderMessaging_Struct));
|
||||||
auto data = (TraderMessaging_Struct *) outapp->pBuffer;
|
auto data = (TraderMessaging_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
data->action = action;
|
data->action = action;
|
||||||
data->entity_id = trader->GetID();
|
data->entity_id = trader->GetID();
|
||||||
data->trader_id = trader->CharacterID();
|
data->trader_id = trader->CharacterID();
|
||||||
data->zone_id = trader->GetZoneID();
|
data->zone_id = trader->GetZoneID();
|
||||||
|
data->instance_id = trader->GetInstanceID();
|
||||||
strn0cpy(data->trader_name, trader->GetName(), sizeof(data->trader_name));
|
strn0cpy(data->trader_name, trader->GetName(), sizeof(data->trader_name));
|
||||||
|
|
||||||
worldserver.SendPacket(outapp);
|
worldserver.SendPacket(outapp);
|
||||||
@@ -2937,9 +2941,11 @@ void Client::SendBecomeTrader(BazaarTraderBarterActions action, uint32 entity_id
|
|||||||
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct));
|
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct));
|
||||||
auto data = (BecomeTrader_Struct *) outapp->pBuffer;
|
auto data = (BecomeTrader_Struct *) outapp->pBuffer;
|
||||||
|
|
||||||
data->action = action;
|
data->action = action;
|
||||||
data->entity_id = trader->GetID();
|
data->entity_id = trader->GetID();
|
||||||
data->trader_id = trader->CharacterID();
|
data->trader_id = trader->CharacterID();
|
||||||
|
data->zone_id = trader->GetZoneID();
|
||||||
|
data->zone_instance_id = trader->GetInstanceID();
|
||||||
strn0cpy(data->trader_name, trader->GetCleanName(), sizeof(data->trader_name));
|
strn0cpy(data->trader_name, trader->GetCleanName(), sizeof(data->trader_name));
|
||||||
|
|
||||||
QueuePacket(outapp);
|
QueuePacket(outapp);
|
||||||
@@ -3085,14 +3091,15 @@ void Client::TraderPriceUpdate(const EQApplicationPacket *app)
|
|||||||
auto item_detail = FindTraderItemBySerialNumber(newgis->serial_number[i]);
|
auto item_detail = FindTraderItemBySerialNumber(newgis->serial_number[i]);
|
||||||
|
|
||||||
TraderRepository::Trader trader_item{};
|
TraderRepository::Trader trader_item{};
|
||||||
trader_item.id = 0;
|
trader_item.id = 0;
|
||||||
trader_item.char_entity_id = GetID();
|
trader_item.char_entity_id = GetID();
|
||||||
trader_item.char_id = CharacterID();
|
trader_item.char_id = CharacterID();
|
||||||
trader_item.char_zone_id = GetZoneID();
|
trader_item.char_zone_id = GetZoneID();
|
||||||
trader_item.item_charges = newgis->charges[i];
|
trader_item.char_zone_instance_id = GetInstanceID();
|
||||||
trader_item.item_cost = tpus->NewPrice;
|
trader_item.item_charges = newgis->charges[i];
|
||||||
trader_item.item_id = newgis->items[i];
|
trader_item.item_cost = tpus->NewPrice;
|
||||||
trader_item.item_sn = newgis->serial_number[i];
|
trader_item.item_id = newgis->items[i];
|
||||||
|
trader_item.item_sn = newgis->serial_number[i];
|
||||||
if (item_detail->IsAugmented()) {
|
if (item_detail->IsAugmented()) {
|
||||||
auto augs = item_detail->GetAugmentIDs();
|
auto augs = item_detail->GetAugmentIDs();
|
||||||
trader_item.aug_slot_1 = augs.at(0);
|
trader_item.aug_slot_1 = augs.at(0);
|
||||||
@@ -3221,7 +3228,8 @@ void Client::SendBulkBazaarTraders()
|
|||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results.count);
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results.count);
|
||||||
|
|
||||||
for (auto t : results.traders) {
|
for (auto t : results.traders) {
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.zone_id);
|
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, t.zone_id);
|
||||||
|
VARSTRUCT_ENCODE_TYPE(uint16, bufptr, t.zone_instance_id);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.trader_id);
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.trader_id);
|
||||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.entity_id);
|
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, t.entity_id);
|
||||||
VARSTRUCT_ENCODE_STRING(bufptr, t.trader_name.c_str());
|
VARSTRUCT_ENCODE_STRING(bufptr, t.trader_name.c_str());
|
||||||
|
|||||||
+7
-10
@@ -3644,11 +3644,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
SharedTaskZoneMessaging::HandleWorldMessage(pack);
|
SharedTaskZoneMessaging::HandleWorldMessage(pack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_DataBucketCacheUpdate:
|
|
||||||
{
|
|
||||||
DataBucket::HandleWorldMessage(pack);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_GuildTributeUpdate: {
|
case ServerOP_GuildTributeUpdate: {
|
||||||
GuildTributeUpdate* in = (GuildTributeUpdate*)pack->pBuffer;
|
GuildTributeUpdate* in = (GuildTributeUpdate*)pack->pBuffer;
|
||||||
|
|
||||||
@@ -3934,15 +3929,17 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
out->action = 0;
|
out->action = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out->entity_id = in->entity_id;
|
|
||||||
out->zone_id = in->zone_id;
|
out->entity_id = in->entity_id;
|
||||||
out->trader_id = in->trader_id;
|
out->zone_id = in->zone_id;
|
||||||
|
out->zone_instance_id = in->instance_id;
|
||||||
|
out->trader_id = in->trader_id;
|
||||||
strn0cpy(out->trader_name, in->trader_name, sizeof(out->trader_name));
|
strn0cpy(out->trader_name, in->trader_name, sizeof(out->trader_name));
|
||||||
|
|
||||||
c.second->QueuePacket(outapp);
|
c.second->QueuePacket(outapp, true, Mob::CLIENT_CONNECTED);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
if (zone && zone->GetZoneID() == Zones::BAZAAR) {
|
if (zone && zone->GetZoneID() == Zones::BAZAAR && in->instance_id == zone->GetInstanceID()) {
|
||||||
if (in->action == TraderOn) {
|
if (in->action == TraderOn) {
|
||||||
c.second->SendBecomeTrader(TraderOn, in->entity_id);
|
c.second->SendBecomeTrader(TraderOn, in->entity_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1923,8 +1923,6 @@ const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DataBucket::BulkLoadEntities(DataBucketLoadType::NPC, npc_ids);
|
|
||||||
|
|
||||||
if (!npc_faction_ids.empty()) {
|
if (!npc_faction_ids.empty()) {
|
||||||
zone->LoadNPCFactions(npc_faction_ids);
|
zone->LoadNPCFactions(npc_faction_ids);
|
||||||
zone->LoadNPCFactionAssociations(npc_faction_ids);
|
zone->LoadNPCFactionAssociations(npc_faction_ids);
|
||||||
|
|||||||
Reference in New Issue
Block a user