Compare commits

...

25 Commits

Author SHA1 Message Date
Chris Miles 490cffb5ea [Release] 22.61.0 (#4587) 2025-01-06 00:27:11 -06:00
Alex King d95b64e0b8 [Cleanup] Fix GM Flag Spell Restriction Bypasses (#4571)
* [Cleanup] Fix GM Flag Spell Restriction Bypasses

* Update spells.cpp
2025-01-06 00:18:25 -06:00
Alex King 1ed282f6ff [Inventory] Add GetInventorySlots() Method (#4566)
* [Inventory] Add GetInventorySlots() Method

* Update client.cpp

* Push
2025-01-05 23:48:39 -06:00
Chris Miles a3a498634f [Maps] Fix broken Map MMFS implementation (#4576) 2025-01-05 23:48:09 -06:00
Chris Miles c44596b38a [Network] Prune / disconnect TCP connections gracefully (#4574) 2025-01-05 23:48:00 -06:00
Mitch Freeman fe43d26dd6 [Fix] Guild creation to propagate across zones (#4575)
Fix guild creation to propagate across zones
2025-01-05 23:47:22 -06:00
Chris Miles 3155b82abb [Command] Fix #copycharacter (#4582)
* [Command] Fix #copycharacter

* Update copy_character.cpp
2025-01-05 23:46:59 -06:00
Chris Miles 4c6aaa6995 [Logs] Improve Crash log defaults (#4579) 2025-01-05 23:46:43 -06:00
Mitch Freeman c82dee575a [Fix] Guild Membership Update Fix (#4581)
When the guild membership was large (1k+) the client would studder for half a sec when a guild member would login or logout.  This was reproduceable with a guild size of 2k members though floor would be client dependent most likely.
2025-01-05 23:46:19 -06:00
Mitch Freeman 33db85f2ee [Fix] Repair a EQEMUConfig Memory Leak (#4584)
Co-authored-by: Mitch Freeman <neckkola@gmail.com>
2025-01-05 23:45:28 -06:00
Mitch Freeman b40e4ce7cd [Fix] Repair a memory leak in GuildsList (#4585)
There was a leak generated when sending the GuildsList

Co-authored-by: Mitch Freeman <neckkola@gmail.com>
2025-01-05 23:45:09 -06:00
Mitch Freeman 20ff325013 [Fix] Repair a LoadNPCEmote MemoryLeak (#4586) 2025-01-05 23:44:51 -06:00
Chris Miles 8a7d5e72cb [Filesystem] Path Manager Improvements (#4557)
* [Filesystem] Path Manager Improvements

* Update path_manager.cpp

* Use native fs path building syntax
2025-01-05 23:44:16 -06:00
Mitch Freeman 4493ebebab [Bug Fix] Resolve a client crash when logging in or zoning (#4572) 2024-12-14 14:27:43 -05:00
Alex King 77793f364e [Commands] Add #find bot Subcommand (#4563)
* [Commands] Add #find bot Subcommand

* Update find.cpp

* Update find.cpp
2024-12-12 16:55:33 -06:00
Alex King e258aaa068 [Bug Fix] Allow Items in ROF2 to Stack to 32,767 (#4556)
* [Bug Fix] Allow Items in ROF2 to Stack to 32,767

* Update rof2.cpp
2024-12-12 16:39:38 -06:00
Paul Johnson 3b779ef301 [Rules] Add rules for requiring custom files from client (#4561)
* rules for enabling requiring custom files

* shorten default

* variable name

* check account status for enforcing client key

* rule for custom files admin level

---------

Co-authored-by: Paul Johnson <Paul@pjohnsomac-6366.digi.box>
2024-12-12 01:47:50 -06:00
Alex King 3f3c0f2fda [Commands] Add #find ldon_theme Subcommand (#4564) 2024-12-12 01:27:25 -06:00
Alex King 0f164c456e [Cleanup] Remove Unused Group Methods (#4559) 2024-12-12 01:25:36 -06:00
Mitch Freeman 6172c49b08 [Feature] Enable bazaar window 'Find Trader' functionality (#4560)
* First pass to enable trader 'Find Trader' functionality

* Move SendBulkTraders out of zoning routines and send as part of the opening of the bazaar search window.
Add zone instance to SendBulkTraders to support multi-instanced bazaars.
2024-12-12 01:25:12 -06:00
Chris Miles 66a7dd0143 [Databuckets] Improved Reliability and Performance of Databuckets (#4562)
* [Databuckets] Don't broadcast client-scoped updates

* Remove temp feature flag

* Remove distributed caching, only cache for character scoped data, simplify

* Update bot.cpp

* Cleanup

* Update data_bucket.cpp

* Cleanup

* Cleanup

* Remove BulkLoadEntities from LoadNPCTypes

* Update data_bucket.cpp

* Cleanup

* More cleanup

* More cleanup

* BulkLoadEntities to BulkLoadEntitiesToCache

* Add CanCache in DeleteData to gate an unnecessary call
2024-12-12 01:17:08 -06:00
Alex King 5c6e7a8b09 [Cleanup] Convert Event Parses to Single Line (#4569)
* [Cleanup] Convert Event Parses to Single Line

* Push

* Update spells.cpp

* Update spells.cpp

---------

Co-authored-by: Akkadius <akkadius1@gmail.com>
2024-12-12 00:43:22 -06:00
dependabot[bot] bd85fc96a0 Bump golang.org/x/crypto in /utils/scripts/build/should-release (#4570)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.21.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 00:17:28 -06:00
nytmyr 8e40e5357c [Bots] Fix AA ranks to account for level (#4567)
Previously level requirement was only being checked on the initial rank of an AA. If passed, bots would gain all ranks for that AA regardless of level, this will now check for the level requirement for each rank before granting the AA
2024-12-06 23:58:11 -05:00
nytmyr 5f0b999ca9 [Groups] Fix AmIMainAssist incorrectly checking for MainTankName (#4565) 2024-12-04 16:04:34 -05:00
93 changed files with 1262 additions and 1310 deletions
+65
View File
@@ -1,3 +1,68 @@
## [22.61.0] 1/6/2025
### Bots
* Fix AA ranks to account for level ([#4567](https://github.com/EQEmu/Server/pull/4567)) @nytmyr 2024-12-07
### Code
* Convert Event Parses to Single Line ([#4569](https://github.com/EQEmu/Server/pull/4569)) @Kinglykrab 2024-12-12
* Fix GM Flag Spell Restriction Bypasses ([#4571](https://github.com/EQEmu/Server/pull/4571)) @Kinglykrab 2025-01-06
* Remove Unused Group Methods ([#4559](https://github.com/EQEmu/Server/pull/4559)) @Kinglykrab 2024-12-12
### Commands
* Add #find bot Subcommand ([#4563](https://github.com/EQEmu/Server/pull/4563)) @Kinglykrab 2024-12-12
* Add #find ldon_theme Subcommand ([#4564](https://github.com/EQEmu/Server/pull/4564)) @Kinglykrab 2024-12-12
* Fix #copycharacter ([#4582](https://github.com/EQEmu/Server/pull/4582)) @Akkadius 2025-01-06
### Databuckets
* Improved Reliability and Performance of Databuckets ([#4562](https://github.com/EQEmu/Server/pull/4562)) @Akkadius 2024-12-12
### Feature
* Enable bazaar window 'Find Trader' functionality ([#4560](https://github.com/EQEmu/Server/pull/4560)) @neckkola 2024-12-12
### Filesystem
* Path Manager Improvements ([#4557](https://github.com/EQEmu/Server/pull/4557)) @Akkadius 2025-01-06
### Fixes
* Allow Items in ROF2 to Stack to 32,767 ([#4556](https://github.com/EQEmu/Server/pull/4556)) @Kinglykrab 2024-12-12
* Fix EVENT_COMBAT on NPC Death ([#4558](https://github.com/EQEmu/Server/pull/4558)) @Kinglykrab 2024-11-28
* Guild Membership Update Fix ([#4581](https://github.com/EQEmu/Server/pull/4581)) @neckkola 2025-01-06
* Guild creation to propagate across zones ([#4575](https://github.com/EQEmu/Server/pull/4575)) @neckkola 2025-01-06
* Repair a EQEMUConfig Memory Leak ([#4584](https://github.com/EQEmu/Server/pull/4584)) @neckkola 2025-01-06
* Repair a LoadNPCEmote MemoryLeak ([#4586](https://github.com/EQEmu/Server/pull/4586)) @neckkola 2025-01-06
* Repair a memory leak in GuildsList ([#4585](https://github.com/EQEmu/Server/pull/4585)) @neckkola 2025-01-06
* Resolve a client crash when logging in or zoning ([#4572](https://github.com/EQEmu/Server/pull/4572)) @neckkola 2024-12-14
### Groups
* Fix AmIMainAssist incorrectly checking for MainTankName ([#4565](https://github.com/EQEmu/Server/pull/4565)) @nytmyr 2024-12-04
### Inventory
* Add GetInventorySlots() Method ([#4566](https://github.com/EQEmu/Server/pull/4566)) @Kinglykrab 2025-01-06
### Logs
* Improve Crash log defaults ([#4579](https://github.com/EQEmu/Server/pull/4579)) @Akkadius 2025-01-06
### Maps
* Fix broken Map MMFS implementation ([#4576](https://github.com/EQEmu/Server/pull/4576)) @Akkadius 2025-01-06
### Network
* Prune / disconnect TCP connections gracefully ([#4574](https://github.com/EQEmu/Server/pull/4574)) @Akkadius 2025-01-06
### Rules
* Add rules for requiring custom files from client ([#4561](https://github.com/EQEmu/Server/pull/4561)) @knervous 2024-12-12
## [22.60.0] 11/25/2024
### Bazaar
+3
View File
@@ -37,6 +37,9 @@ IF(EQEMU_ADD_PROFILER)
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-as-needed,-lprofiler,--as-needed")
ENDIF(EQEMU_ADD_PROFILER)
IF(USE_MAP_MMFS)
ADD_DEFINITIONS(-DUSE_MAP_MMFS)
ENDIF (USE_MAP_MMFS)
IF(MSVC)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
+28 -20
View File
@@ -8,13 +8,14 @@ std::vector<BazaarSearchResultsFromDB_Struct>
Bazaar::GetSearchResults(
SharedDatabase &db,
BazaarSearchCriteria_Struct search,
uint32 char_zone_id
uint32 char_zone_id,
int32 char_zone_instance_id
)
{
LogTrading(
"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 [{}] "
"search_scope [{}] char_zone_id [{}]",
"search_scope [{}] char_zone_id [{}], char_zone_instance_id [{}]",
search.item_name,
search.min_cost,
search.max_cost,
@@ -26,7 +27,8 @@ Bazaar::GetSearchResults(
search.trader_entity_id,
search.trader_id,
search.search_scope,
char_zone_id
char_zone_id,
char_zone_instance_id
);
std::string search_criteria_trader("TRUE ");
@@ -34,14 +36,19 @@ Bazaar::GetSearchResults(
if (search.search_scope == NonRoFBazaarSearchScope) {
search_criteria_trader.append(
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,
Zones::BAZAAR
Zones::BAZAAR,
char_zone_instance_id
)
);
}
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) {
search_criteria_trader.append(fmt::format(" AND trader.char_id = {}", search.trader_id));
@@ -62,7 +69,7 @@ Bazaar::GetSearchResults(
std::string query = fmt::format(
"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, "
"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 "
"WHERE {} AND trader.char_id = character_data.id "
"GROUP BY trader.item_sn, trader.item_charges, trader.char_id",
@@ -122,19 +129,20 @@ Bazaar::GetSearchResults(
continue;
}
r.count = Strings::ToInt(row[0]);
r.trader_id = Strings::ToInt(row[1]);
r.serial_number = Strings::ToInt(row[3]);
r.cost = Strings::ToInt(row[5]);
r.slot_id = Strings::ToInt(row[6]);
r.sum_charges = Strings::ToInt(row[7]);
r.stackable = item->Stackable;
r.icon_id = item->Icon;
r.trader_zone_id = Strings::ToInt(row[8]);
r.trader_entity_id = Strings::ToInt(row[9]);
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
r.item_name = fmt::format("{:.63}\0", item->Name);
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
r.count = Strings::ToInt(row[0]);
r.trader_id = Strings::ToInt(row[1]);
r.serial_number = Strings::ToInt(row[3]);
r.cost = Strings::ToInt(row[5]);
r.slot_id = Strings::ToInt(row[6]);
r.sum_charges = Strings::ToInt(row[7]);
r.stackable = item->Stackable;
r.icon_id = item->Icon;
r.trader_zone_id = Strings::ToInt(row[8]);
r.trader_zone_instance_id = Strings::ToInt(row[17]);
r.trader_entity_id = Strings::ToInt(row[9]);
r.serial_number_RoF = fmt::format("{:016}\0", Strings::ToInt(row[3]));
r.item_name = fmt::format("{:.63}\0", item->Name);
r.trader_name = fmt::format("{:.63}\0", std::string(row[10]).c_str());
LogTradingDetail(
"Searching against item [{}] ({}) for trader [{}]",
+1 -1
View File
@@ -7,7 +7,7 @@
class Bazaar {
public:
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);
};
+2
View File
@@ -294,6 +294,8 @@ void print_trace()
SendCrashReport(crash_report);
}
LogSys.CloseFileLogs();
exit(1);
}
+49 -1
View File
@@ -1860,7 +1860,35 @@ bool Database::CopyCharacter(
const int64 new_character_id = (CharacterDataRepository::GetMaxId(*this) + 1);
std::vector<std::string> tables_to_zero_id = { "keyring", "data_buckets", "character_instance_safereturns" };
// validate destination name doesn't exist already
const auto& destination_characters = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}' AND `deleted_at` IS NULL LIMIT 1",
Strings::Escape(destination_character_name)
)
);
if (!destination_characters.empty()) {
LogError("Character [{}] already exists", destination_character_name);
return false;
}
std::vector<std::string> tables_to_zero_id = {
"keyring",
"data_buckets",
"character_instance_safereturns",
"character_expedition_lockouts",
"character_instance_lockouts",
"character_parcels",
"character_tribute",
"player_titlesets",
};
std::vector<std::string> ignore_tables = {
"guilds",
};
size_t total_rows_copied = 0;
TransactionBegin();
@@ -1868,6 +1896,10 @@ bool Database::CopyCharacter(
const std::string& table_name = t.first;
const std::string& character_id_column_name = t.second;
if (Strings::Contains(ignore_tables, table_name)) {
continue;
}
auto results = QueryDatabase(
fmt::format(
"SHOW COLUMNS FROM {}",
@@ -1918,6 +1950,10 @@ bool Database::CopyCharacter(
value = std::to_string(destination_account_id);
}
if (!Strings::IsNumber(value)) {
value = Strings::Escape(value);
}
new_values.emplace_back(value);
}
@@ -1950,6 +1986,11 @@ bool Database::CopyCharacter(
)
);
size_t rows_copied = insert_rows.size(); // Rows copied for this table
total_rows_copied += rows_copied; // Increment grand total
LogInfo("Copying table [{}] rows [{}]", table_name, Strings::Commify(rows_copied));
if (!insert.ErrorMessage().empty()) {
TransactionRollback();
return false;
@@ -1959,6 +2000,13 @@ bool Database::CopyCharacter(
TransactionCommit();
LogInfo(
"Character [{}] copied to [{}] total rows [{}]",
source_character_name,
destination_character_name,
Strings::Commify(total_rows_copied)
);
return true;
}
@@ -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_npc_expires ON data_buckets (npc_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
+15 -23
View File
@@ -140,29 +140,6 @@ std::string EQ::constants::GetLanguageName(uint8 language_id)
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()
{
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();
}
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
View File
@@ -352,9 +352,6 @@ namespace EQ
extern const std::map<uint8, std::string>& GetLanguageMap();
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();
std::string GetFlyModeName(int8 flymode_id);
@@ -751,6 +748,35 @@ static std::map<uint32, std::string> stance_names = {
{ 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 {
constexpr int PC = 1;
constexpr int NPC = 2;
-18
View File
@@ -993,24 +993,6 @@ enum class DynamicZoneMemberStatus : uint8_t
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 {
Odus = 0,
Qeynos,
+5 -1
View File
@@ -3742,7 +3742,8 @@ struct GetItems_Struct{
struct BecomeTrader_Struct {
uint32 action;
uint32 zone_id;
uint16 zone_id;
uint16 zone_instance_id;
uint32 trader_id;
uint32 entity_id;
char trader_name[64];
@@ -6347,6 +6348,7 @@ enum BazaarTraderBarterActions {
TraderAck2 = 22,
AddTraderToBazaarWindow = 24,
RemoveTraderFromBazaarWindow = 25,
FirstOpenSearch = 26,
ClickTrader = 28,
DeliveryCostUpdate = 29
};
@@ -6386,6 +6388,7 @@ struct BazaarSearchResultsFromDB_Struct {
uint32 icon_id;
uint32 sum_charges;
uint32 trader_zone_id;
int32 trader_zone_instance_id;
uint32 trader_entity_id;
uint32 item_stat;
bool stackable;
@@ -6407,6 +6410,7 @@ struct BazaarSearchResultsFromDB_Struct {
CEREAL_NVP(icon_id),
CEREAL_NVP(sum_charges),
CEREAL_NVP(trader_zone_id),
CEREAL_NVP(trader_zone_instance_id),
CEREAL_NVP(trader_entity_id),
CEREAL_NVP(item_stat),
CEREAL_NVP(stackable),
+1 -1
View File
@@ -137,9 +137,9 @@ class EQEmuConfig
{
}
virtual ~EQEmuConfig() {}
public:
virtual ~EQEmuConfig() {}
// Produce a const singleton
static const EQEmuConfig *get()
+8
View File
@@ -25,6 +25,8 @@
#include "repositories/discord_webhooks_repository.h"
#include "repositories/logsys_categories_repository.h"
#include "termcolor/rang.hpp"
#include "path_manager.h"
#include "file.h"
#include <iostream>
#include <string>
@@ -85,6 +87,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
* Set Defaults
*/
log_settings[Logs::Crash].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::Crash].log_to_file = static_cast<uint8>(Logs::General);
log_settings[Logs::MySQLError].log_to_console = static_cast<uint8>(Logs::General);
log_settings[Logs::NPCScaling].log_to_gmsay = static_cast<uint8>(Logs::General);
log_settings[Logs::HotReload].log_to_gmsay = static_cast<uint8>(Logs::General);
@@ -532,6 +535,11 @@ void EQEmuLogSys::StartFileLogs(const std::string &log_name)
{
EQEmuLogSys::CloseFileLogs();
if (!File::Exists(path.GetLogPath())) {
LogInfo("Logs directory not found, creating [{}]", path.GetLogPath());
File::Makedir(path.GetLogPath());
}
/**
* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one...
*/
+5 -5
View File
@@ -612,9 +612,9 @@ bool EQ::InventoryProfile::HasAugmentEquippedByID(uint32 item_id)
return has_equipped;
}
int EQ::InventoryProfile::CountAugmentEquippedByID(uint32 item_id)
uint32 EQ::InventoryProfile::CountAugmentEquippedByID(uint32 item_id)
{
int quantity = 0;
uint32 quantity = 0;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
@@ -643,9 +643,9 @@ bool EQ::InventoryProfile::HasItemEquippedByID(uint32 item_id)
return has_equipped;
}
int EQ::InventoryProfile::CountItemEquippedByID(uint32 item_id)
uint32 EQ::InventoryProfile::CountItemEquippedByID(uint32 item_id)
{
int quantity = 0;
uint32 quantity = 0;
ItemInstance* item = nullptr;
for (int slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
@@ -1807,4 +1807,4 @@ int16 EQ::InventoryProfile::FindFirstFreeSlotThatFitsItem(const EQ::ItemData *it
}
}
return 0;
}
}
+2 -2
View File
@@ -147,13 +147,13 @@ namespace EQ
bool HasItemEquippedByID(uint32 item_id);
// Check how many of a specific item the player has equipped by Item ID
int CountItemEquippedByID(uint32 item_id);
uint32 CountItemEquippedByID(uint32 item_id);
// Check if player has a specific augment equipped by Item ID
bool HasAugmentEquippedByID(uint32 item_id);
// Check how many of a specific augment the player has equipped by Item ID
int CountAugmentEquippedByID(uint32 item_id);
uint32 CountAugmentEquippedByID(uint32 item_id);
// Get a list of augments from a specific slot ID
std::vector<uint32> GetAugmentIDsBySlotID(int16 slot_id);
+2
View File
@@ -80,6 +80,8 @@ void EQ::Net::TCPConnection::Start() {
}
}
else if (nread == UV_EOF) {
connection->Disconnect();
if (buf->base) {
delete[] buf->base;
}
+30 -14
View File
@@ -583,19 +583,21 @@ namespace RoF2
auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BecomeTrader_Struct));
auto eq = (BecomeTrader_Struct *) outapp->pBuffer;
eq->action = emu->action;
eq->entity_id = emu->entity_id;
eq->trader_id = emu->trader_id;
eq->zone_id = emu->zone_id;
eq->action = emu->action;
eq->entity_id = emu->entity_id;
eq->trader_id = emu->trader_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));
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->trader_id,
eq->entity_id,
eq->zone_id
);
eq->zone_id,
eq->zone_instance_id);
dest->FastQueuePacket(&outapp);
break;
}
@@ -1843,11 +1845,11 @@ namespace RoF2
}
}
auto outapp = new EQApplicationPacket(OP_GuildsList);
outapp->size = packet_size;
outapp->pBuffer = buffer;
safe_delete_array(in->pBuffer);
dest->FastQueuePacket(&outapp);
in->pBuffer = buffer;
in->size = packet_size;
dest->FastQueuePacket(&in);
}
ENCODE(OP_GuildTributeDonateItem)
@@ -6218,6 +6220,11 @@ namespace RoF2
FINISH_DIRECT_DECODE();
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: {
__packet->SetOpcode(OP_BazaarSearch);
LogTrading("(RoF2) WelcomeMessage action <green>[{}]", action);
@@ -6358,9 +6365,18 @@ namespace RoF2
//sprintf(hdr.unknown000, "06e0002Y1W00");
strn0cpy(hdr.unknown000, fmt::format("{:016}\0", inst->GetSerialNumber()).c_str(),sizeof(hdr.unknown000));
hdr.stacksize =
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
? 0xFFFFFFFF : inst->GetCharges()) : 1);
hdr.stacksize = 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;
structs::InventorySlot_Struct slot_id{};
+2 -1
View File
@@ -3119,7 +3119,8 @@ enum RoF2BazaarTraderBuyerActions {
BazaarInspect = 18,
ClickTrader = 28,
ItemMove = 19,
ReconcileItems = 20
ReconcileItems = 20,
FirstOpenSearch = 26
};
enum RoF2BuyerActions {
+52 -66
View File
@@ -5,31 +5,19 @@
#include "strings.h"
#include <filesystem>
namespace fs = std::filesystem;
inline std::string striptrailingslash(const std::string &file_path)
{
if (file_path.back() == '/' || file_path.back() == '\\') {
return file_path.substr(0, file_path.length() - 1);
}
return file_path;
}
void PathManager::LoadPaths()
{
m_server_path = File::FindEqemuConfigPath();
if (!m_server_path.empty()) {
std::filesystem::current_path(m_server_path);
}
if (m_server_path.empty()) {
LogInfo("Failed to load server path");
return;
}
LogInfo("server [{}]", m_server_path);
std::filesystem::current_path(m_server_path);
if (!EQEmuConfig::LoadConfig()) {
LogError("Failed to load eqemu config");
@@ -38,66 +26,64 @@ void PathManager::LoadPaths()
const auto c = EQEmuConfig::get();
// maps
if (File::Exists(fs::path{m_server_path + "/" + c->MapDir}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/" + c->MapDir}).string();
}
else if (File::Exists(fs::path{m_server_path + "/maps"}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/maps"}).string();
}
else if (File::Exists(fs::path{m_server_path + "/Maps"}.string())) {
m_maps_path = fs::relative(fs::path{m_server_path + "/Maps"}).string();
}
auto resolve_path = [&](const std::string& dir, const std::vector<std::string>& fallback_dirs = {}) -> std::string {
// relative
if (File::Exists((fs::path{m_server_path} / dir).string())) {
return fs::relative(fs::path{m_server_path} / dir).lexically_normal().string();
}
// quests
if (File::Exists(fs::path{m_server_path + "/" + c->QuestDir}.string())) {
m_quests_path = fs::relative(fs::path{m_server_path + "/" + c->QuestDir}).string();
}
// absolute
if (File::Exists(fs::path{dir}.string())) {
return fs::absolute(fs::path{dir}).string();
}
// plugins
if (File::Exists(fs::path{m_server_path + "/" + c->PluginDir}.string())) {
m_plugins_path = fs::relative(fs::path{m_server_path + "/" + c->PluginDir}).string();
}
// fallback search options if specified
for (const auto& fallback : fallback_dirs) {
if (File::Exists((fs::path{m_server_path} / fallback).string())) {
return fs::relative(fs::path{m_server_path} / fallback).lexically_normal().string();
}
}
// lua_modules
if (File::Exists(fs::path{m_server_path + "/" + c->LuaModuleDir}.string())) {
m_lua_modules_path = fs::relative(fs::path{m_server_path + "/" + c->LuaModuleDir}).string();
}
// if all else fails, just set it to the config value
return dir;
};
// lua mods
if (File::Exists(fs::path{ m_server_path + "/mods" }.string())) {
m_lua_mods_path = fs::relative(fs::path{ m_server_path + "/mods" }).string();
}
m_maps_path = resolve_path(c->MapDir, {"maps", "Maps"});
m_quests_path = resolve_path(c->QuestDir);
m_plugins_path = resolve_path(c->PluginDir);
m_lua_modules_path = resolve_path(c->LuaModuleDir);
m_lua_mods_path = resolve_path("mods");
m_patch_path = resolve_path(c->PatchDir);
m_opcode_path = resolve_path(c->OpcodeDir);
m_shared_memory_path = resolve_path(c->SharedMemDir);
m_log_path = resolve_path(c->LogDir, {"logs"});
// patches
if (File::Exists(fs::path{m_server_path + "/" + c->PatchDir}.string())) {
m_patch_path = fs::relative(fs::path{m_server_path + "/" + c->PatchDir}).string();
}
// Log all paths in a loop
std::vector<std::pair<std::string, std::string>> paths = {
{"server", m_server_path},
{"logs", m_log_path},
{"lua mods", m_lua_mods_path},
{"lua_modules", m_lua_modules_path},
{"maps", m_maps_path},
{"patches", m_patch_path},
{"opcode", m_opcode_path},
{"plugins", m_plugins_path},
{"quests", m_quests_path},
{"shared_memory", m_shared_memory_path}
};
// patches
if (File::Exists(fs::path{ m_server_path + "/" + c->OpcodeDir }.string())) {
m_opcode_path = fs::relative(fs::path{ m_server_path + "/" + c->OpcodeDir }).string();
}
constexpr int name_width = 15;
constexpr int path_width = 0;
constexpr int break_length = 70;
// shared_memory_path
if (File::Exists(fs::path{m_server_path + "/" + c->SharedMemDir}.string())) {
m_shared_memory_path = fs::relative(fs::path{ m_server_path + "/" + c->SharedMemDir }).string();
std::cout << std::endl;
LogInfo("{}", Strings::Repeat("-", break_length));
for (const auto& [name, in_path] : paths) {
if (!in_path.empty()) {
LogInfo("{:>{}} > [{:<{}}]", name, name_width, in_path, path_width);
}
}
// logging path
if (File::Exists(fs::path{m_server_path + "/" + c->LogDir}.string())) {
m_log_path = fs::relative(fs::path{m_server_path + "/" + c->LogDir}).string();
}
LogInfo("logs path [{}]", m_log_path);
LogInfo("lua mods path [{}]", m_lua_mods_path);
LogInfo("lua_modules path [{}]", m_lua_modules_path);
LogInfo("maps path [{}]", m_maps_path);
LogInfo("patches path [{}]", m_patch_path);
LogInfo("opcode path [{}]", m_opcode_path);
LogInfo("plugins path [{}]", m_plugins_path);
LogInfo("quests path [{}]", m_quests_path);
LogInfo("shared_memory path [{}]", m_shared_memory_path);
LogInfo("{}", Strings::Repeat("-", break_length));
}
const std::string &PathManager::GetServerPath() const
@@ -49,23 +49,23 @@ public:
std::string field;
switch (theme_id) {
case LDoNThemes::GUK: {
case LDoNTheme::GUK: {
field = "guk_";
break;
}
case LDoNThemes::MIR: {
case LDoNTheme::MIR: {
field = "mir_";
break;
}
case LDoNThemes::MMC: {
case LDoNTheme::MMC: {
field = "mmc_";
break;
}
case LDoNThemes::RUJ: {
case LDoNTheme::RUJ: {
field = "ruj_";
break;
}
case LDoNThemes::TAK: {
case LDoNTheme::TAK: {
field = "tak_";
break;
}
@@ -28,13 +28,14 @@ public:
uint32_t aug_slot_4;
uint32_t aug_slot_5;
uint32_t aug_slot_6;
int32_t item_sn;
uint32_t item_sn;
int32_t item_charges;
uint64_t item_cost;
uint32_t item_cost;
uint8_t slot_id;
uint32_t char_entity_id;
uint32_t char_zone_id;
int8_t active_transaction;
int32_t char_zone_instance_id;
uint8_t active_transaction;
};
static std::string PrimaryKey()
@@ -60,6 +61,7 @@ public:
"slot_id",
"char_entity_id",
"char_zone_id",
"char_zone_instance_id",
"active_transaction",
};
}
@@ -82,6 +84,7 @@ public:
"slot_id",
"char_entity_id",
"char_zone_id",
"char_zone_instance_id",
"active_transaction",
};
}
@@ -123,22 +126,23 @@ public:
{
Trader e{};
e.id = 0;
e.char_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.item_sn = 0;
e.item_charges = 0;
e.item_cost = 0;
e.slot_id = 0;
e.char_entity_id = 0;
e.char_zone_id = 0;
e.active_transaction = 0;
e.id = 0;
e.char_id = 0;
e.item_id = 0;
e.aug_slot_1 = 0;
e.aug_slot_2 = 0;
e.aug_slot_3 = 0;
e.aug_slot_4 = 0;
e.aug_slot_5 = 0;
e.aug_slot_6 = 0;
e.item_sn = 0;
e.item_charges = 0;
e.item_cost = 0;
e.slot_id = 0;
e.char_entity_id = 0;
e.char_zone_id = 0;
e.char_zone_instance_id = 0;
e.active_transaction = 0;
return e;
}
@@ -175,22 +179,23 @@ public:
if (results.RowCount() == 1) {
Trader e{};
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.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_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_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_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_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], 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_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.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.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_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_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_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 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_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.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_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;
}
@@ -238,7 +243,8 @@ public:
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[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(
fmt::format(
@@ -275,6 +281,7 @@ public:
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_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
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.char_entity_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));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
@@ -354,22 +362,23 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{};
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.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_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_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_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_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], 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_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.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.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_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_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_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 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_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.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_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);
}
@@ -394,22 +403,23 @@ public:
for (auto row = results.begin(); row != results.end(); ++row) {
Trader e{};
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.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_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_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_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_charges = row[10] ? static_cast<int32_t>(atoi(row[10])) : 0;
e.item_cost = row[11] ? strtoull(row[11], 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_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.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.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_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_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_6 = row[8] ? static_cast<uint32_t>(strtoul(row[8], nullptr, 10)) : 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_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.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_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);
}
@@ -499,6 +509,7 @@ public:
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_zone_id));
v.push_back(std::to_string(e.char_zone_instance_id));
v.push_back(std::to_string(e.active_transaction));
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.char_entity_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));
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
+9 -6
View File
@@ -16,6 +16,7 @@ public:
struct DistinctTraders_Struct {
uint32 trader_id;
uint32 zone_id;
uint32 zone_instance_id;
uint32 entity_id;
std::string trader_name;
};
@@ -35,7 +36,8 @@ public:
GetBazaarSearchResults(
SharedDatabase &db,
BazaarSearchCriteria_Struct search,
uint32 char_zone_id
uint32 char_zone_id,
int32 char_zone_instance_id
);
static BulkTraders_Struct GetDistinctTraders(Database &db)
@@ -44,7 +46,7 @@ public:
std::vector<DistinctTraders_Struct> distinct_traders;
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 "
"JOIN character_data AS c ON t.char_id = c.id;"
);
@@ -54,10 +56,11 @@ public:
for (auto row: results) {
DistinctTraders_Struct e{};
e.trader_id = Strings::ToInt(row[0]);
e.zone_id = Strings::ToInt(row[1]);
e.entity_id = Strings::ToInt(row[2]);
e.trader_name = row[3] ? row[3] : "";
e.trader_id = Strings::ToInt(row[0]);
e.zone_id = Strings::ToInt(row[1]);
e.zone_instance_id = Strings::ToInt(row[2]);
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.traders.push_back(e);
+3
View File
@@ -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, 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, 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(Zone)
-2
View File
@@ -319,8 +319,6 @@
// player events
#define ServerOP_PlayerEvent 0x5100
#define ServerOP_DataBucketCacheUpdate 0x5200
enum {
CZUpdateType_Character,
CZUpdateType_Group,
+2 -2
View File
@@ -25,7 +25,7 @@
// Build variables
// these get injected during the build pipeline
#define CURRENT_VERSION "22.60.0-dev" // always append -dev to the current version for custom-builds
#define CURRENT_VERSION "22.61.0-dev" // always append -dev to the current version for custom-builds
#define LOGIN_VERSION "0.8.0"
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
@@ -42,7 +42,7 @@
* 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
#endif
-12
View File
@@ -51,12 +51,6 @@ WorldServer::WorldServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> wo
ServerOP_LSAccountUpdate,
std::bind(&WorldServer::ProcessLSAccountUpdate, this, std::placeholders::_1, std::placeholders::_2)
);
m_keepalive = std::make_unique<EQ::Timer>(
1000,
true,
std::bind(&WorldServer::OnKeepAlive, this, std::placeholders::_1)
);
}
WorldServer::~WorldServer() = default;
@@ -1307,12 +1301,6 @@ const std::string &WorldServer::GetVersion() const
return m_version;
}
void WorldServer::OnKeepAlive(EQ::Timer *t)
{
ServerPacket pack(ServerOP_KeepAlive, 0);
m_connection->SendPacket(&pack);
}
void WorldServer::FormatWorldServerName(char *name, int8 server_list_type)
{
std::string server_long_name = name;
-7
View File
@@ -187,13 +187,6 @@ private:
bool m_is_server_logged_in;
bool m_is_server_trusted;
/**
* Keepalive
* @param t
*/
void OnKeepAlive(EQ::Timer *t);
std::unique_ptr<EQ::Timer> m_keepalive;
static void FormatWorldServerName(char *name, int8 server_list_type);
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "eqemu-server",
"version": "22.60.0",
"version": "22.61.0",
"repository": {
"type": "git",
"url": "https://github.com/EQEmu/Server.git"
+1 -1
View File
@@ -10,7 +10,7 @@ require (
require (
github.com/golang/protobuf v1.3.2 // 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
google.golang.org/appengine v1.6.7 // indirect
)
+2 -2
View File
@@ -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=
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.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+2 -2
View File
@@ -12,12 +12,12 @@ void WorldserverCLI::CopyCharacter(int argc, char **argv, argh::parser &cmd, std
};
std::vector<std::string> options = {};
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
if (cmd[{"-h", "--help"}]) {
return;
}
EQEmuCommand::ValidateCmdInput(arguments, options, cmd, argc, argv);
std::string source_character_name = cmd(2).str();
std::string destination_character_name = cmd(3).str();
std::string destination_account_name = cmd(4).str();
+11
View File
@@ -541,6 +541,17 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app)
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) {
SendExpansionInfo();
-10
View File
@@ -595,11 +595,6 @@ bool LoginServer::Connect()
);
}
m_keepalive = std::make_unique<EQ::Timer>(
1000,
true,
std::bind(&LoginServer::OnKeepAlive, this, std::placeholders::_1));
return true;
}
@@ -716,8 +711,3 @@ void LoginServer::SendAccountUpdate(ServerPacket *pack)
}
}
void LoginServer::OnKeepAlive(EQ::Timer *t)
{
ServerPacket pack(ServerOP_KeepAlive, 0);
SendPacket(&pack);
}
-1
View File
@@ -50,7 +50,6 @@ private:
void ProcessLSRemoteAddr(uint16_t opcode, EQ::Net::Packet &p);
void ProcessLSAccountUpdate(uint16_t opcode, EQ::Net::Packet &p);
void OnKeepAlive(EQ::Timer *t);
std::unique_ptr<EQ::Timer> m_keepalive;
std::unique_ptr<EQ::Net::ServertalkClient> m_client;
-6
View File
@@ -22,7 +22,6 @@ void QueryServConnection::AddConnection(std::shared_ptr<EQ::Net::ServertalkServe
connection->OnMessage(ServerOP_QueryServGeneric, std::bind(&QueryServConnection::HandleGenericMessage, this, std::placeholders::_1, std::placeholders::_2));
connection->OnMessage(ServerOP_LFGuildUpdate, std::bind(&QueryServConnection::HandleLFGuildUpdateMessage, this, std::placeholders::_1, std::placeholders::_2));
m_streams.emplace(std::make_pair(connection->GetUUID(), connection));
m_keepalive = std::make_unique<EQ::Timer>(1000, true, std::bind(&QueryServConnection::OnKeepAlive, this, std::placeholders::_1));
}
void QueryServConnection::RemoveConnection(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection)
@@ -54,8 +53,3 @@ bool QueryServConnection::SendPacket(ServerPacket* pack)
return true;
}
void QueryServConnection::OnKeepAlive(EQ::Timer *t)
{
ServerPacket pack(ServerOP_KeepAlive, 0);
SendPacket(&pack);
}
-1
View File
@@ -15,7 +15,6 @@ public:
void HandleGenericMessage(uint16_t opcode, EQ::Net::Packet &p);
void HandleLFGuildUpdateMessage(uint16_t opcode, EQ::Net::Packet &p);
bool SendPacket(ServerPacket* pack);
void OnKeepAlive(EQ::Timer *t);
private:
std::map<std::string, std::shared_ptr<EQ::Net::ServertalkServerConnection>> m_streams;
std::unique_ptr<EQ::Timer> m_keepalive;
-12
View File
@@ -31,8 +31,6 @@ void UCSConnection::SetConnection(std::shared_ptr<EQ::Net::ServertalkServerConne
)
);
}
m_keepalive = std::make_unique<EQ::Timer>(1000, true, std::bind(&UCSConnection::OnKeepAlive, this, std::placeholders::_1));
}
const std::shared_ptr<EQ::Net::ServertalkServerConnection> &UCSConnection::GetConnection() const
@@ -92,13 +90,3 @@ void UCSConnection::SendMessage(const char *From, const char *Message)
SendPacket(pack);
safe_delete(pack);
}
void UCSConnection::OnKeepAlive(EQ::Timer *t)
{
if (!connection) {
return;
}
ServerPacket pack(ServerOP_KeepAlive, 0);
connection->SendPacket(&pack);
}
-5
View File
@@ -23,11 +23,6 @@ private:
inline std::string GetIP() const { return (connection && connection->Handle()) ? connection->Handle()->RemoteIP() : 0; }
std::shared_ptr<EQ::Net::ServertalkServerConnection> connection;
/**
* Keepalive
*/
std::unique_ptr<EQ::Timer> m_keepalive;
void OnKeepAlive(EQ::Timer *t);
};
#endif /*UCS_H_*/
-8
View File
@@ -42,7 +42,6 @@ ZSList::ZSList()
memset(pLockedZones, 0, sizeof(pLockedZones));
m_tick = std::make_unique<EQ::Timer>(5000, true, std::bind(&ZSList::OnTick, this, std::placeholders::_1));
m_keepalive = std::make_unique<EQ::Timer>(1000, true, std::bind(&ZSList::OnKeepAlive, this, std::placeholders::_1));
}
ZSList::~ZSList() {
@@ -846,13 +845,6 @@ void ZSList::OnTick(EQ::Timer *t)
web_interface.SendEvent(out);
}
void ZSList::OnKeepAlive(EQ::Timer *t)
{
for (auto &zone : zone_server_list) {
zone->SendKeepAlive();
}
}
const std::list<std::unique_ptr<ZoneServer>> &ZSList::getZoneServerList() const
{
return zone_server_list;
-1
View File
@@ -72,7 +72,6 @@ public:
private:
void OnTick(EQ::Timer *t);
void OnKeepAlive(EQ::Timer *t);
uint32 NextID;
uint16 pLockedZones[MaxLockedZones];
uint32 CurGroupID;
-5
View File
@@ -1564,11 +1564,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
DynamicZone::HandleZoneMessage(pack);
break;
}
case ServerOP_DataBucketCacheUpdate: {
zoneserver_list.SendPacket(pack);
break;
}
case ServerOP_GuildTributeUpdate: {
auto data = (GuildTributeUpdate *)pack->pBuffer;
auto guild = guild_mgr.GetGuildByGuildID(data->guild_id);
+7 -22
View File
@@ -1550,10 +1550,7 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, boo
hit.damage_done = 0;
}
parse->EventBotMerc(
EVENT_USE_SKILL,
this,
nullptr,
parse->EventBotMerc(EVENT_USE_SKILL, this, nullptr,
[&]() {
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 };
parse->EventMercNPC(
EVENT_DEATH_COMPLETE,
this,
owner_or_self,
parse->EventMercNPC(EVENT_DEATH_COMPLETE, this, owner_or_self,
[&]() {
return fmt::format(
"{} {} {} {} {} {} {} {} {}",
@@ -3096,8 +3090,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
m_combat_record.GetHealingReceived()
);
},
0,
&args
0, &args
);
// 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) {
args = { this };
parse->EventMob(
EVENT_DAMAGE_GIVEN,
attacker,
this,
parse->EventMob(EVENT_DAMAGE_GIVEN, attacker, this,
[&]() {
return fmt::format(
"{} {} {} {} {} {} {} {} {}",
@@ -4284,17 +4274,13 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
static_cast<int>(special)
);
},
0,
&args
0, &args
);
}
args = { attacker };
damage_override = parse->EventMob(
EVENT_DAMAGE_TAKEN,
this,
attacker,
damage_override = parse->EventMob(EVENT_DAMAGE_TAKEN, this, attacker,
[&]() {
return fmt::format(
"{} {} {} {} {} {} {} {} {}",
@@ -4309,8 +4295,7 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons
static_cast<int>(special)
);
},
0,
&args
0, &args
);
if (damage_override > 0) {
+4 -17
View File
@@ -1265,7 +1265,7 @@ void Bot::LoadAAs() {
}
while(current) {
if (!CanUseAlternateAdvancementRank(current)) {
if (current->level_req > GetLevel() || !CanUseAlternateAdvancementRank(current)) {
current = nullptr;
} else {
current = current->next;
@@ -3089,6 +3089,7 @@ bool Bot::Spawn(Client* botCharacterOwner) {
m_targetable = true;
entity_list.AddBot(this, true, true);
ClearDataBucketCache();
DataBucket::GetDataBuckets(this);
LoadBotSpellSettings();
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 };
parse->EventBot(
EVENT_UNEQUIP_ITEM_BOT,
this,
nullptr,
export_string,
return_iterator.return_item_instance->GetID(),
&args
);
parse->EventBot(EVENT_UNEQUIP_ITEM_BOT, this, nullptr, export_string, return_iterator.return_item_instance->GetID(), &args);
}
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 };
parse->EventBot(
EVENT_EQUIP_ITEM_BOT,
this,
nullptr,
export_string,
trade_iterator.trade_item_instance->GetID(),
&args
);
parse->EventBot(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
+136 -153
View File
@@ -329,7 +329,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
adventure_stats_timer = nullptr;
adventure_leaderboard_timer = nullptr;
adv_data = nullptr;
adv_requested_theme = LDoNThemes::Unused;
adv_requested_theme = LDoNTheme::Unused;
adv_requested_id = 0;
adv_requested_member_count = 0;
@@ -1469,7 +1469,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
bool is_loss = false;
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 guk_points = (split_points + (points % 5));
@@ -1522,12 +1522,12 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
points -= split_points;
if (split_points != 0) { // if anything left, recursively loop thru again
UpdateLDoNPoints(LDoNThemes::Unused, split_points);
UpdateLDoNPoints(LDoNTheme::Unused, split_points);
}
break;
}
case LDoNThemes::GUK: {
case LDoNTheme::GUK: {
if (points < 0) {
if (m_pp.ldon_points_guk < (0 - points)) {
return false;
@@ -1539,7 +1539,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
m_pp.ldon_points_guk += points;
break;
}
case LDoNThemes::MIR: {
case LDoNTheme::MIR: {
if (points < 0) {
if (m_pp.ldon_points_mir < (0 - points)) {
return false;
@@ -1551,7 +1551,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
m_pp.ldon_points_mir += points;
break;
}
case LDoNThemes::MMC: {
case LDoNTheme::MMC: {
if (points < 0) {
if (m_pp.ldon_points_mmc < (0 - points)) {
return false;
@@ -1563,7 +1563,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
m_pp.ldon_points_mmc += points;
break;
}
case LDoNThemes::RUJ: {
case LDoNTheme::RUJ: {
if (points < 0) {
if (m_pp.ldon_points_ruj < (0 - points)) {
return false;
@@ -1575,7 +1575,7 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
m_pp.ldon_points_ruj += points;
break;
}
case LDoNThemes::TAK: {
case LDoNTheme::TAK: {
if (points < 0) {
if (m_pp.ldon_points_tak < (0 - points)) {
return false;
@@ -1623,23 +1623,23 @@ bool Client::UpdateLDoNPoints(uint32 theme_id, int points)
void Client::SetLDoNPoints(uint32 theme_id, uint32 points)
{
switch (theme_id) {
case LDoNThemes::GUK: {
case LDoNTheme::GUK: {
m_pp.ldon_points_guk = points;
break;
}
case LDoNThemes::MIR: {
case LDoNTheme::MIR: {
m_pp.ldon_points_mir = points;
break;
}
case LDoNThemes::MMC: {
case LDoNTheme::MMC: {
m_pp.ldon_points_mmc = points;
break;
}
case LDoNThemes::RUJ: {
case LDoNTheme::RUJ: {
m_pp.ldon_points_ruj = points;
break;
}
case LDoNThemes::TAK: {
case LDoNTheme::TAK: {
m_pp.ldon_points_tak = points;
break;
}
@@ -5676,15 +5676,15 @@ uint32 Client::GetLDoNPointsTheme(uint32 t)
{
switch(t)
{
case LDoNThemes::GUK:
case LDoNTheme::GUK:
return m_pp.ldon_points_guk;
case LDoNThemes::MIR:
case LDoNTheme::MIR:
return m_pp.ldon_points_mir;
case LDoNThemes::MMC:
case LDoNTheme::MMC:
return m_pp.ldon_points_mmc;
case LDoNThemes::RUJ:
case LDoNTheme::RUJ:
return m_pp.ldon_points_ruj;
case LDoNThemes::TAK:
case LDoNTheme::TAK:
return m_pp.ldon_points_tak;
default:
return 0;
@@ -5695,15 +5695,15 @@ uint32 Client::GetLDoNWinsTheme(uint32 t)
{
switch(t)
{
case LDoNThemes::GUK:
case LDoNTheme::GUK:
return m_pp.ldon_wins_guk;
case LDoNThemes::MIR:
case LDoNTheme::MIR:
return m_pp.ldon_wins_mir;
case LDoNThemes::MMC:
case LDoNTheme::MMC:
return m_pp.ldon_wins_mmc;
case LDoNThemes::RUJ:
case LDoNTheme::RUJ:
return m_pp.ldon_wins_ruj;
case LDoNThemes::TAK:
case LDoNTheme::TAK:
return m_pp.ldon_wins_tak;
default:
return 0;
@@ -5714,15 +5714,15 @@ uint32 Client::GetLDoNLossesTheme(uint32 t)
{
switch(t)
{
case LDoNThemes::GUK:
case LDoNTheme::GUK:
return m_pp.ldon_losses_guk;
case LDoNThemes::MIR:
case LDoNTheme::MIR:
return m_pp.ldon_losses_mir;
case LDoNThemes::MMC:
case LDoNTheme::MMC:
return m_pp.ldon_losses_mmc;
case LDoNThemes::RUJ:
case LDoNTheme::RUJ:
return m_pp.ldon_losses_ruj;
case LDoNThemes::TAK:
case LDoNTheme::TAK:
return m_pp.ldon_losses_tak;
default:
return 0;
@@ -5731,35 +5731,35 @@ uint32 Client::GetLDoNLossesTheme(uint32 t)
void Client::UpdateLDoNWinLoss(uint32 theme_id, bool win, bool remove) {
switch (theme_id) {
case LDoNThemes::GUK:
case LDoNTheme::GUK:
if (win) {
m_pp.ldon_wins_guk += (remove ? -1 : 1);
} else {
m_pp.ldon_losses_guk += (remove ? -1 : 1);
}
break;
case LDoNThemes::MIR:
case LDoNTheme::MIR:
if (win) {
m_pp.ldon_wins_mir += (remove ? -1 : 1);
} else {
m_pp.ldon_losses_mir += (remove ? -1 : 1);
}
break;
case LDoNThemes::MMC:
case LDoNTheme::MMC:
if (win) {
m_pp.ldon_wins_mmc += (remove ? -1 : 1);
} else {
m_pp.ldon_losses_mmc += (remove ? -1 : 1);
}
break;
case LDoNThemes::RUJ:
case LDoNTheme::RUJ:
if (win) {
m_pp.ldon_wins_ruj += (remove ? -1 : 1);
} else {
m_pp.ldon_losses_ruj += (remove ? -1 : 1);
}
break;
case LDoNThemes::TAK:
case LDoNTheme::TAK:
if (win) {
m_pp.ldon_wins_tak += (remove ? -1 : 1);
} else {
@@ -6227,7 +6227,7 @@ void Client::NewAdventure(int id, int theme, const char *text, int member_count,
void Client::ClearPendingAdventureData()
{
adv_requested_id = 0;
adv_requested_theme = LDoNThemes::Unused;
adv_requested_theme = LDoNTheme::Unused;
safe_delete_array(adv_requested_data);
adv_requested_member_count = 0;
}
@@ -10461,27 +10461,15 @@ void Client::SendToInstance(std::string instance_type, std::string zone_short_na
MovePC(zone_id, instance_id, x, y, z, heading);
}
int Client::CountItem(uint32 item_id)
uint32 Client::CountItem(uint32 item_id)
{
int quantity = 0;
uint32 quantity = 0;
EQ::ItemInstance *item = nullptr;
static const int16 slots[][2] = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
{ EQ::invslot::GUILD_TRIBUTE_BEGIN, EQ::invslot::GUILD_TRIBUTE_END },
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
item = GetInv().GetItem(slot_id);
if (item && item->GetID() == item_id) {
quantity += (item->IsStackable() ? item->GetCharges() : 1);
}
for (const int16& slot_id : GetInventorySlots()) {
item = GetInv().GetItem(slot_id);
if (item && item->GetID() == item_id) {
quantity += (item->IsStackable() ? item->GetCharges() : 1);
}
}
@@ -10498,30 +10486,26 @@ void Client::ResetItemCooldown(uint32 item_id)
int recast_type = item_d->RecastType;
bool found_item = false;
static const int16 slots[][2] = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
item = GetInv().GetItem(slot_id);
if (item) {
item_d = item->GetItem();
if (item_d && item->GetID() == item_id || (item_d->RecastType != RECAST_TYPE_UNLINKED_ITEM && item_d->RecastType == recast_type)) {
item->SetRecastTimestamp(0);
DeleteItemRecastTimer(item_d->ID);
SendItemPacket(slot_id, item, ItemPacketCharmUpdate);
found_item = true;
}
for (const int16& slot_id : GetInventorySlots()) {
item = GetInv().GetItem(slot_id);
if (item) {
item_d = item->GetItem();
if (
item_d &&
item->GetID() == item_id ||
(
item_d->RecastType != RECAST_TYPE_UNLINKED_ITEM &&
item_d->RecastType == recast_type
)
) {
item->SetRecastTimestamp(0);
DeleteItemRecastTimer(item_d->ID);
SendItemPacket(slot_id, item, ItemPacketCharmUpdate);
found_item = true;
}
}
}
if (!found_item) {
DeleteItemRecastTimer(item_id); //We didn't find the item but we still want to remove the timer
}
@@ -10556,25 +10540,20 @@ void Client::SetItemCooldown(uint32 item_id, bool use_saved_timer, uint32 in_sec
final_time = total_time - current_time;
}
static const int16 slots[][2] = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
item = GetInv().GetItem(slot_id);
if (item) {
item_d = item->GetItem();
if (item_d && item->GetID() == item_id || (item_d->RecastType != RECAST_TYPE_UNLINKED_ITEM && item_d->RecastType == recast_type)) {
item->SetRecastTimestamp(total_time);
SendItemPacket(slot_id, item, ItemPacketCharmUpdate);
}
for (const int16& slot_id : GetInventorySlots()) {
item = GetInv().GetItem(slot_id);
if (item) {
item_d = item->GetItem();
if (
item_d &&
item->GetID() == item_id ||
(
item_d->RecastType != RECAST_TYPE_UNLINKED_ITEM &&
item_d->RecastType == recast_type
)
) {
item->SetRecastTimestamp(total_time);
SendItemPacket(slot_id, item, ItemPacketCharmUpdate);
}
}
}
@@ -10617,38 +10596,26 @@ uint32 Client::GetItemCooldown(uint32 item_id)
void Client::RemoveItem(uint32 item_id, uint32 quantity)
{
uint32 removed_count = 0;
EQ::ItemInstance *item = nullptr;
static const int16 slots[][2] = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
{ EQ::invslot::GUILD_TRIBUTE_BEGIN, EQ::invslot::GUILD_TRIBUTE_END },
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
int16 removed_count = 0;
const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
if (removed_count == quantity) {
break;
}
item = GetInv().GetItem(slot_id);
if (item && item->GetID() == item_id) {
int16 charges = item->IsStackable() ? item->GetCharges() : 0;
int16 stack_size = std::max(charges, static_cast<int16>(1));
if ((removed_count + stack_size) <= quantity) {
removed_count += stack_size;
DeleteItemInInventory(slot_id, charges, true);
} else {
int16 amount_left = (quantity - removed_count);
if (amount_left > 0 && stack_size >= amount_left) {
removed_count += amount_left;
DeleteItemInInventory(slot_id, amount_left, true);
}
for (const int16& slot_id : GetInventorySlots()) {
if (removed_count == quantity) {
break;
}
item = GetInv().GetItem(slot_id);
if (item && item->GetID() == item_id) {
uint32 charges = item->IsStackable() ? item->GetCharges() : 0;
uint32 stack_size = std::max(charges, static_cast<uint32>(1));
if ((removed_count + stack_size) <= quantity) {
removed_count += stack_size;
DeleteItemInInventory(slot_id, charges, true);
} else {
uint32 amount_left = (quantity - removed_count);
if (amount_left > 0 && stack_size >= amount_left) {
removed_count += amount_left;
DeleteItemInInventory(slot_id, amount_left, true);
}
}
}
@@ -12820,37 +12787,28 @@ uint16 Client::GetSkill(EQ::skills::SkillType skill_id) const
void Client::RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity)
{
EQ::ItemInstance *item = nullptr;
static const int16 slots[][2] = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
{ EQ::invslot::GUILD_TRIBUTE_BEGIN, EQ::invslot::GUILD_TRIBUTE_END },
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
int16 removed_count = 0;
const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
if (removed_count == quantity) {
break;
}
item = GetInv().GetItem(slot_id);
if (item && item->GetSerialNumber() == serial_number) {
int16 charges = item->IsStackable() ? item->GetCharges() : 0;
int16 stack_size = std::max(charges, static_cast<int16>(1));
if ((removed_count + stack_size) <= quantity) {
removed_count += stack_size;
DeleteItemInInventory(slot_id, charges, true);
} else {
int16 amount_left = (quantity - removed_count);
if (amount_left > 0 && stack_size >= amount_left) {
removed_count += amount_left;
DeleteItemInInventory(slot_id, amount_left, true);
}
uint32 removed_count = 0;
const auto& slot_ids = GetInventorySlots();
for (const int16& slot_id : slot_ids) {
if (removed_count == quantity) {
break;
}
item = GetInv().GetItem(slot_id);
if (item && item->GetSerialNumber() == serial_number) {
uint32 charges = item->IsStackable() ? item->GetCharges() : 0;
uint32 stack_size = std::max(charges, static_cast<uint32>(1));
if ((removed_count + stack_size) <= quantity) {
removed_count += stack_size;
DeleteItemInInventory(slot_id, charges, true);
} else {
uint32 amount_left = (quantity - removed_count);
if (amount_left > 0 && stack_size >= amount_left) {
removed_count += amount_left;
DeleteItemInInventory(slot_id, amount_left, true);
}
}
}
@@ -13075,3 +13033,28 @@ void Client::ClientToNpcAggroProcess()
LogAggro("Checking Reverse Aggro (client->npc) scanned_npcs ([{}])", npc_scan_count);
}
}
const std::vector<int16>& Client::GetInventorySlots()
{
static const std::vector<std::pair<int16, int16>> slots = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END },
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
static std::vector<int16> slot_ids;
if (slot_ids.empty()) {
for (const auto& [begin, end] : slots) {
for (int16 slot_id = begin; slot_id <= end; ++slot_id) {
slot_ids.emplace_back(slot_id);
}
}
}
return slot_ids;
}
+2 -1
View File
@@ -467,6 +467,7 @@ public:
inline ExtendedProfile_Struct& GetEPP() { return m_epp; }
inline EQ::InventoryProfile& GetInv() { return m_inv; }
inline const EQ::InventoryProfile& GetInv() const { return m_inv; }
const std::vector<int16>& GetInventorySlots();
inline PetInfo* GetPetInfo(int pet_info_type) { return pet_info_type == PetInfoType::Suspended ? &m_suspendedminion : &m_petinfo; }
inline InspectMessage_Struct& GetInspectMessage() { return m_inspect_message; }
inline const InspectMessage_Struct& GetInspectMessage() const { return m_inspect_message; }
@@ -1093,7 +1094,7 @@ public:
bool PushItemOnCursor(const EQ::ItemInstance& inst, bool client_update = false);
void SendCursorBuffer();
void DeleteItemInInventory(int16 slot_id, int16 quantity = 0, bool client_update = false, bool update_db = true);
int CountItem(uint32 item_id);
uint32 CountItem(uint32 item_id);
void ResetItemCooldown(uint32 item_id);
void SetItemCooldown(uint32 item_id, bool use_saved_timer = false, uint32 in_seconds = 1);
uint32 GetItemCooldown(uint32 item_id);
+44 -135
View File
@@ -524,7 +524,6 @@ int Client::HandlePacket(const EQApplicationPacket *app)
// Finish client connecting state
void Client::CompleteConnect()
{
UpdateWho();
client_state = CLIENT_CONNECTED;
SendAllPackets();
@@ -861,7 +860,7 @@ void Client::CompleteConnect()
if (IsInAGuild()) {
if (firstlogon == 1) {
guild_mgr.UpdateDbMemberOnline(CharacterID(), true);
guild_mgr.SendToWorldSendGuildMembersList(GuildID());
SendGuildMembersList();
}
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), zone->GetZoneID(), time(nullptr));
@@ -913,10 +912,6 @@ void Client::CompleteConnect()
CastToClient()->FastQueuePacket(&outapp);
}
if (ClientVersion() >= EQ::versions::ClientVersion::RoF) {
SendBulkBazaarTraders();
}
// TODO: load these states
// We at least will set them to the correct state for now
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;
// Load Data Buckets
ClearDataBucketCache();
DataBucket::GetDataBuckets(this);
// Max Level for Character:PerCharacterQglobalMaxLevel and Character:PerCharacterBucketMaxLevel
@@ -2023,38 +2019,38 @@ void Client::Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app)
return;
}
if (item->LDoNTheme <= LDoNThemeBits::TAKBit) {
if (item->LDoNTheme <= LDoNTheme::TAKBit) {
uint32 ldon_theme;
if (item->LDoNTheme & LDoNThemeBits::TAKBit) {
if (item->LDoNTheme & LDoNTheme::TAKBit) {
if (m_pp.ldon_points_tak < item_cost) {
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) {
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) {
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) {
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) {
cannot_afford = true;
ldon_theme = LDoNThemes::GUK;
ldon_theme = LDoNTheme::GUK;
}
}
merchant_type = fmt::format(
"{} Point{}",
EQ::constants::GetLDoNThemeName(ldon_theme),
LDoNTheme::GetName(ldon_theme),
item_cost != 1 ? "s" : ""
);
}
@@ -2198,19 +2194,19 @@ void Client::Handle_OP_AdventureMerchantRequest(const EQApplicationPacket *app)
item = database.GetItem(ml.item);
if (item) {
uint32 theme = LDoNThemes::Unused;
if (item->LDoNTheme > LDoNThemeBits::TAKBit) {
theme = LDoNThemes::Unused;
} else if (item->LDoNTheme & LDoNThemeBits::TAKBit) {
theme = LDoNThemes::TAK;
} else if (item->LDoNTheme & LDoNThemeBits::RUJBit) {
theme = LDoNThemes::RUJ;
} else if (item->LDoNTheme & LDoNThemeBits::MMCBit) {
theme = LDoNThemes::MMC;
} else if (item->LDoNTheme & LDoNThemeBits::MIRBit) {
theme = LDoNThemes::MIR;
} else if (item->LDoNTheme & LDoNThemeBits::GUKBit) {
theme = LDoNThemes::GUK;
uint32 theme = LDoNTheme::Unused;
if (item->LDoNTheme > LDoNTheme::TAKBit) {
theme = LDoNTheme::Unused;
} else if (item->LDoNTheme & LDoNTheme::TAKBit) {
theme = LDoNTheme::TAK;
} else if (item->LDoNTheme & LDoNTheme::RUJBit) {
theme = LDoNTheme::RUJ;
} else if (item->LDoNTheme & LDoNTheme::MMCBit) {
theme = LDoNTheme::MMC;
} else if (item->LDoNTheme & LDoNTheme::MIRBit) {
theme = LDoNTheme::MIR;
} else if (item->LDoNTheme & LDoNTheme::GUKBit) {
theme = LDoNTheme::GUK;
}
ss << "^" << item->Name << "|";
ss << item->ID << "|";
@@ -3251,30 +3247,14 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
args.push_back(old_aug);
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
parse->EventItem(
EVENT_UNAUGMENT_ITEM,
this,
tobe_auged,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
}
args.assign(1, tobe_auged);
args.push_back(false);
if (parse->ItemHasQuestSub(old_aug, EVENT_AUGMENT_REMOVE)) {
parse->EventItem(
EVENT_AUGMENT_REMOVE,
this,
old_aug,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args);
}
if (parse->PlayerHasQuestSub(EVENT_AUGMENT_REMOVE_CLIENT)) {
@@ -3306,29 +3286,13 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
args.push_back(aug);
if (parse->ItemHasQuestSub(tobe_auged, EVENT_AUGMENT_ITEM)) {
parse->EventItem(
EVENT_AUGMENT_ITEM,
this,
tobe_auged,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
}
args.assign(1, tobe_auged);
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_INSERT)) {
parse->EventItem(
EVENT_AUGMENT_INSERT,
this,
aug,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args);
}
args.push_back(aug);
@@ -3398,30 +3362,14 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
args.push_back(aug);
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
parse->EventItem(
EVENT_UNAUGMENT_ITEM,
this,
tobe_auged,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
}
args.assign(1, tobe_auged);
args.push_back(false);
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_REMOVE)) {
parse->EventItem(
EVENT_AUGMENT_REMOVE,
this,
aug,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
}
args.push_back(aug);
@@ -3486,30 +3434,14 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
args.push_back(aug);
if (parse->ItemHasQuestSub(tobe_auged, EVENT_UNAUGMENT_ITEM)) {
parse->EventItem(
EVENT_UNAUGMENT_ITEM,
this,
tobe_auged,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
}
args.assign(1, tobe_auged);
args.push_back(true);
if (parse->ItemHasQuestSub(aug, EVENT_AUGMENT_REMOVE)) {
parse->EventItem(
EVENT_AUGMENT_REMOVE,
this,
aug,
nullptr,
"",
in_augment->augment_index,
&args
);
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
}
args.push_back(aug);
@@ -3985,6 +3917,10 @@ void Client::Handle_OP_BazaarSearch(const EQApplicationPacket *app)
SendBazaarWelcome();
break;
}
case FirstOpenSearch: {
SendBulkBazaarTraders();
break;
}
default: {
LogError("Malformed BazaarSearch_Struct packet received, ignoring\n");
}
@@ -4479,14 +4415,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
int i = 0;
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
i = parse->EventItem(
EVENT_ITEM_CLICK_CAST,
this,
p_inst,
nullptr,
"",
castspell->inventoryslot
);
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
}
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
@@ -4518,14 +4447,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
int i = 0;
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
i = parse->EventItem(
EVENT_ITEM_CLICK_CAST,
this,
p_inst,
nullptr,
"",
castspell->inventoryslot
);
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
}
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
@@ -8015,6 +7937,7 @@ void Client::Handle_OP_GuildCreate(const EQApplicationPacket *app)
SetGuildID(new_guild_id);
SendGuildList();
guild_mgr.MemberAdd(new_guild_id, CharacterID(), GetLevel(), GetClass(), GUILD_LEADER, GetZoneID(), GetName());
guild_mgr.SendGuildRefresh(new_guild_id, true, true, true, true);
guild_mgr.SendToWorldSendGuildList();
SendGuildSpawnAppearance();
@@ -9591,14 +9514,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
int i = 0;
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
i = parse->EventItem(
EVENT_ITEM_CLICK_CAST,
this,
p_inst,
nullptr,
"",
slot_id
);
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", slot_id);
}
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
@@ -9662,14 +9578,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
int i = 0;
if (parse->ItemHasQuestSub(p_inst, EVENT_ITEM_CLICK_CAST)) {
i = parse->EventItem(
EVENT_ITEM_CLICK_CAST,
this,
clickaug,
nullptr,
"",
slot_id
);
i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, clickaug, nullptr, "", slot_id);
}
if (parse->PlayerHasQuestSub(EVENT_ITEM_CLICK_CAST_CLIENT)) {
+3 -3
View File
@@ -179,7 +179,7 @@ bool Client::Process() {
}
if (IsInAGuild()) {
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
guild_mgr.SendToWorldSendGuildMembersList(GuildID());
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
}
SetDynamicZoneMemberStatus(DynamicZoneMemberStatus::Offline);
@@ -202,7 +202,7 @@ bool Client::Process() {
Save();
if (IsInAGuild()) {
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
guild_mgr.SendToWorldSendGuildMembersList(GuildID());
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
}
if (GetMerc())
@@ -578,7 +578,7 @@ bool Client::Process() {
}
if (IsInAGuild()) {
guild_mgr.UpdateDbMemberOnline(CharacterID(), false);
guild_mgr.SendToWorldSendGuildMembersList(GuildID());
guild_mgr.SendGuildMemberUpdateToWorld(GetName(), GuildID(), 0, time(nullptr));
}
return false;
+4 -2
View File
@@ -1871,9 +1871,10 @@ bool Corpse::HasItem(uint32 item_id)
return false;
}
uint16 Corpse::CountItem(uint32 item_id)
uint32 Corpse::CountItem(uint32 item_id)
{
uint16 item_count = 0;
uint32 item_count = 0;
if (!database.GetItem(item_id)) {
return item_count;
}
@@ -1893,6 +1894,7 @@ uint16 Corpse::CountItem(uint32 item_id)
item_count += i->charges > 0 ? i->charges : 1;
}
}
return item_count;
}
+1 -1
View File
@@ -196,7 +196,7 @@ public:
/* Corpse: Loot */
void QueryLoot(Client *to);
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 CountItem(uint32 item_id);
uint32 GetItemIDBySlot(uint16 loot_slot);
uint16 GetFirstLootSlotByItemID(uint32 item_id);
std::vector<int> GetLootList();
+152 -274
View File
@@ -8,7 +8,7 @@
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)
{
@@ -58,14 +58,14 @@ void DataBucket::SetData(const DataBucketKey &k)
b.value = k.value;
if (bucket_id) {
// loop cache and update cache value and timestamp
for (auto &ce: g_data_bucket_cache) {
if (CheckBucketMatch(ce.e, k)) {
ce.e = b;
ce.updated_time = GetCurrentTimeUNIX();
ce.update_action = DataBucketCacheUpdateAction::Upsert;
SendDataBucketCacheUpdate(ce);
break;
// update the cache if it exists
if (CanCache(k)) {
for (auto &e: g_data_bucket_cache) {
if (CheckBucketMatch(e, k)) {
e = b;
break;
}
}
}
@@ -74,28 +74,18 @@ void DataBucket::SetData(const DataBucketKey &k)
else {
b.key_ = k.key;
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);
g_data_bucket_cache.emplace_back(b);
}
}
}
std::string DataBucket::GetData(const std::string &bucket_key)
{
DataBucketKey k = {};
k.key = bucket_key;
return GetData(k).value;
return GetData(DataBucketKey{.key = bucket_key}).value;
}
// 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
);
for (const auto &ce: g_data_bucket_cache) {
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();
}
bool can_cache = CanCache(k);
// this is a bucket miss, return empty entity
// we still cache bucket misses, so we don't have to hit the database
if (ce.e.id == 0) {
return DataBucketsRepository::NewEntity();
}
// check the cache first if we can cache
if (can_cache) {
for (const auto &e: g_data_bucket_cache) {
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);
return ce.e;
// this is a bucket miss, return empty entity
// 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
// 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();
// cache bucket misses, so we don't have to hit the database
// when scripts try to read a bucket that doesn't exist
g_data_bucket_cache.emplace_back(
DataBucketCacheEntry{
.e = DataBucketsRepository::DataBuckets{
.id = 0,
.key_ = k.key,
.value = "",
.expires = 0,
.character_id = k.character_id,
.npc_id = k.npc_id,
.bot_id = k.bot_id
},
.updated_time = DataBucket::GetCurrentTimeUNIX()
DataBucketsRepository::DataBuckets{
.id = 0,
.key_ = k.key,
.value = "",
.expires = 0,
.character_id = k.character_id,
.npc_id = k.npc_id,
.bot_id = k.bot_id
}
);
@@ -178,60 +171,54 @@ DataBucketsRepository::DataBuckets DataBucket::GetData(const DataBucketKey &k, b
return {};
}
auto bucket = r.front();
// 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);
return {};
}
bool has_cache = false;
for (auto &ce: g_data_bucket_cache) {
if (ce.e.id == r[0].id) {
has_cache = true;
break;
// add to cache if it doesn't exist
if (can_cache) {
bool has_cache = false;
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) {
// add data bucket and timestamp to cache
g_data_bucket_cache.emplace_back(
DataBucketCacheEntry{
.e = r[0],
.updated_time = DataBucket::GetCurrentTimeUNIX()
}
);
}
return r[0];
return bucket;
}
std::string DataBucket::GetDataExpires(const std::string &bucket_key)
{
DataBucketKey k = {};
k.key = bucket_key;
return GetDataExpires(k);
return GetDataExpires(DataBucketKey{.key = bucket_key});
}
std::string DataBucket::GetDataRemaining(const std::string &bucket_key)
{
DataBucketKey k = {};
k.key = bucket_key;
return GetDataRemaining(k);
return GetDataRemaining(DataBucketKey{.key = bucket_key});
}
bool DataBucket::DeleteData(const std::string &bucket_key)
{
DataBucketKey k = {};
k.key = bucket_key;
return DeleteData(k);
return DeleteData(DataBucketKey{.key = bucket_key});
}
// GetDataBuckets bulk loads all data buckets for a mob
bool DataBucket::GetDataBuckets(Mob *mob)
{
DataBucketLoadType::Type t;
const uint32 id = mob->GetMobTypeIdentifier();
DataBucketLoadType::Type t{};
const uint32 id = mob->GetMobTypeIdentifier();
if (!id) {
return false;
@@ -243,46 +230,39 @@ bool DataBucket::GetDataBuckets(Mob *mob)
else if (mob->IsClient()) {
t = DataBucketLoadType::Client;
}
else if (mob->IsNPC()) {
t = DataBucketLoadType::NPC;
}
BulkLoadEntities(t, {id});
BulkLoadEntitiesToCache(t, {id});
return true;
}
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
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketCacheEntry &ce) {
bool match = CheckBucketMatch(ce.e, k);
if (match) {
ce.update_action = DataBucketCacheUpdateAction::Delete;
SendDataBucketCacheUpdate(ce);
// delete from cache where contents match
g_data_bucket_cache.erase(
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketsRepository::DataBuckets &e) {
return CheckBucketMatch(e, k);
}
),
g_data_bucket_cache.end()
);
return match;
}
),
g_data_bucket_cache.end()
);
LogDataBuckets(
"Deleting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
k.key,
k.bot_id,
k.character_id,
k.npc_id,
size_before,
g_data_bucket_cache.size()
);
LogDataBuckets(
"Deleting bucket key [{}] bot_id [{}] character_id [{}] npc_id [{}] cache size before [{}] after [{}]",
k.key,
k.bot_id,
k.character_id,
k.npc_id,
size_before,
g_data_bucket_cache.size()
);
}
return DataBucketsRepository::DeleteWhere(
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()) {
return;
}
if (ids.size() == 1) {
bool has_cache = false;
for (const auto &ce: g_data_bucket_cache) {
bool has_cache = false;
for (const auto &e: g_data_bucket_cache) {
if (t == DataBucketLoadType::Bot) {
has_cache = ce.e.bot_id == ids[0];
has_cache = e.bot_id == ids[0];
}
else if (t == DataBucketLoadType::Client) {
has_cache = ce.e.character_id == ids[0];
}
else if (t == DataBucketLoadType::NPC) {
has_cache = ce.e.npc_id == ids[0];
has_cache = e.character_id == ids[0];
}
}
@@ -406,9 +384,6 @@ void DataBucket::BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32
case DataBucketLoadType::Client:
column = "character_id";
break;
case DataBucketLoadType::NPC:
column = "npc_id";
break;
default:
LogError("Incorrect LoadType [{}]", static_cast<int>(t));
break;
@@ -442,12 +417,7 @@ void DataBucket::BulkLoadEntities(DataBucketLoadType::Type t, std::vector<uint32
if (!ExistsInCache(e)) {
LogDataBucketsDetail("bucket id [{}] bucket key [{}] bucket value [{}]", e.id, e.key_, e.value);
g_data_bucket_cache.emplace_back(
DataBucketCacheEntry{
.e = e,
.updated_time = GetCurrentTimeUNIX()
}
);
g_data_bucket_cache.emplace_back(e);
}
}
@@ -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();
@@ -469,11 +439,10 @@ void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id)
std::remove_if(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketCacheEntry &ce) {
[&](DataBucketsRepository::DataBuckets &e) {
return (
(t == DataBucketLoadType::Bot && ce.e.bot_id == id) ||
(t == DataBucketLoadType::Client && ce.e.character_id == id) ||
(t == DataBucketLoadType::NPC && ce.e.npc_id == id)
(type == DataBucketLoadType::Bot && e.bot_id == id) ||
(type == DataBucketLoadType::Client && e.character_id == id)
);
}
),
@@ -482,24 +451,17 @@ void DataBucket::DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id)
LogDataBuckets(
"LoadType [{}] id [{}] cache size before [{}] after [{}]",
DataBucketLoadType::Name[t],
DataBucketLoadType::Name[type],
id,
size_before,
g_data_bucket_cache.size()
);
}
int64_t DataBucket::GetCurrentTimeUNIX()
bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &entry)
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count();
}
bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &e)
{
for (const auto &ce: g_data_bucket_cache) {
if (ce.e.id == e.id) {
for (const auto &e: g_data_bucket_cache) {
if (e.id == entry.id) {
return true;
}
}
@@ -507,134 +469,6 @@ bool DataBucket::ExistsInCache(const DataBucketsRepository::DataBuckets &e)
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)
{
// 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(
g_data_bucket_cache.begin(),
g_data_bucket_cache.end(),
[&](DataBucketCacheEntry &ce) {
return ce.e.id == 0 && ce.e.key_ == e.key_ &&
ce.e.character_id == e.character_id &&
ce.e.npc_id == e.npc_id &&
ce.e.bot_id == e.bot_id;
[&](DataBucketsRepository::DataBuckets &ce) {
return ce.id == 0 && ce.key_ == e.key_ &&
ce.character_id == e.character_id &&
ce.npc_id == e.npc_id &&
ce.bot_id == e.bot_id;
}
),
g_data_bucket_cache.end()
@@ -667,3 +501,47 @@ void DataBucket::ClearCache()
g_data_bucket_cache.clear();
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
View File
@@ -1,7 +1,3 @@
//
// Created by Akkadius on 7/7/18.
//
#ifndef EQEMU_DATABUCKET_H
#define EQEMU_DATABUCKET_H
@@ -12,27 +8,6 @@
#include "../common/json/json_archive_single_line.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 {
std::string key;
std::string value;
@@ -46,14 +21,12 @@ namespace DataBucketLoadType {
enum Type : uint8 {
Bot,
Client,
NPC,
MaxType
};
static const std::string Name[Type::MaxType] = {
"Bot",
"Client",
"NPC",
};
}
@@ -68,8 +41,6 @@ public:
static bool GetDataBuckets(Mob *mob);
static int64_t GetCurrentTimeUNIX();
// scoped bucket methods
static void SetData(const DataBucketKey &k);
static bool DeleteData(const DataBucketKey &k);
@@ -80,15 +51,15 @@ public:
// bucket repository versus key matching
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 DeleteCachedBuckets(DataBucketLoadType::Type t, uint32 id);
static void BulkLoadEntitiesToCache(DataBucketLoadType::Type t, std::vector<uint32> ids);
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 ClearCache();
static void DeleteFromCache(uint64 id, DataBucketLoadType::Type type);
static bool CanCache(const DataBucketKey &key);
};
#endif //EQEMU_DATABUCKET_H
+1 -1
View File
@@ -1446,7 +1446,7 @@ int Perl__collectitems(uint32_t item_id, bool remove_item)
return quest_manager.collectitems(item_id, remove_item);
}
int Perl__countitem(uint32_t item_id)
uint32 Perl__countitem(uint32_t item_id)
{
return quest_manager.countitem(item_id);
}
+2 -14
View File
@@ -1817,25 +1817,13 @@ void EntityList::DuelMessage(Mob *winner, Mob *loser, bool flee)
if (parse->PlayerHasQuestSub(EVENT_DUEL_WIN)) {
std::vector<std::any> args = { winner, loser };
parse->EventPlayer(
EVENT_DUEL_WIN,
winner->CastToClient(),
loser->GetName(),
loser->CastToClient()->CharacterID(),
&args
);
parse->EventPlayer(EVENT_DUEL_WIN, winner->CastToClient(), loser->GetName(), loser->CastToClient()->CharacterID(), &args);
}
if (parse->PlayerHasQuestSub(EVENT_DUEL_LOSE)) {
std::vector<std::any> args = { winner, loser };
parse->EventPlayer(
EVENT_DUEL_LOSE,
loser->CastToClient(),
winner->GetName(),
winner->CastToClient()->CharacterID(),
&args
);
parse->EventPlayer(EVENT_DUEL_LOSE, loser->CastToClient(), winner->GetName(), winner->CastToClient()->CharacterID(), &args);
}
}
+15 -25
View File
@@ -2,31 +2,21 @@
void command_emptyinventory(Client *c, const Seperator *sep)
{
auto target = c;
Client* t = c;
if (c->GetGM() && c->GetTarget() && c->GetTarget()->IsClient()) {
target = c->GetTarget()->CastToClient();
t = c->GetTarget()->CastToClient();
}
EQ::ItemInstance *item = nullptr;
static const int16 slots[][2] = {
{ EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END },
{ EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END },
{ EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END},
{ EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END },
{ EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END },
{ EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END },
{ EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END },
};
int removed_count = 0;
const size_t size = sizeof(slots) / sizeof(slots[0]);
for (int slot_index = 0; slot_index < size; ++slot_index) {
for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) {
item = target->GetInv().GetItem(slot_id);
if (item) {
int stack_size = std::max(static_cast<int>(item->GetCharges()), 1);
removed_count += stack_size;
target->DeleteItemInInventory(slot_id, 0, true);
}
uint32 removed_count = 0;
for (const int16& slot_id : t->GetInventorySlots()) {
item = t->GetInv().GetItem(slot_id);
if (item) {
uint32 stack_size = std::max(static_cast<uint32>(item->GetCharges()), static_cast<uint32>(1));
removed_count += stack_size;
t->DeleteItemInInventory(slot_id, 0, true);
}
}
@@ -35,8 +25,8 @@ void command_emptyinventory(Client *c, const Seperator *sep)
Chat::White,
fmt::format(
"{} {} no items to delete.",
c->GetTargetDescription(target, TargetDescriptionType::UCYou),
c == target ? "have" : "has"
c->GetTargetDescription(t, TargetDescriptionType::UCYou),
c == t ? "have" : "has"
).c_str()
);
return;
@@ -46,9 +36,9 @@ void command_emptyinventory(Client *c, const Seperator *sep)
Chat::White,
fmt::format(
"Inventory cleared for {}, {} item{} deleted.",
c->GetTargetDescription(target),
c->GetTargetDescription(t),
removed_count,
removed_count != 1 ? "s" : ""
).c_str()
);
}
}
+13
View File
@@ -1,6 +1,7 @@
#include "../client.h"
#include "find/aa.cpp"
#include "find/body_type.cpp"
#include "find/bot.cpp"
#include "find/bug_category.cpp"
#include "find/character.cpp"
#include "find/class.cpp"
@@ -11,6 +12,7 @@
#include "find/faction.cpp"
#include "find/item.cpp"
#include "find/language.cpp"
#include "find/ldon_theme.cpp"
#include "find/npctype.cpp"
#include "find/object_type.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 = "item", .u = "item [Search Criteria]", .fn = FindItem, .a = {"#fi", "#finditem"}},
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 = "npctype", .u = "npctype [Search Criteria]", .fn = FindNPCType, .a = {
"#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"}},
};
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
const auto arguments = sep->argnum;
if (!arguments) {
+95
View File
@@ -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()
);
}
+1 -1
View File
@@ -36,7 +36,7 @@ void FindCharacter(Client *c, const Seperator *sep)
const auto& l = CharacterDataRepository::GetWhere(
content_db,
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
)
);
+1 -1
View File
@@ -57,7 +57,7 @@ void FindClass(Client *c, const Seperator *sep)
(
IsPlayerClass(class_id) ?
fmt::format(
" | ({})",
" ({})",
Strings::Commify(GetPlayerClassBit(class_id))
) :
""
+65
View File
@@ -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()
);
}
+15 -13
View File
@@ -3,20 +3,21 @@
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)) {
c->Message(Chat::White, "Usage: #set adventure_points [Theme] [Points]");
c->Message(Chat::White, "Valid themes are as follows:");
for (const auto& e : EQ::constants::GetLDoNThemeMap()) {
if (e.first != LDoNThemes::Unused) {
for (const auto& e : ldon_theme_names) {
if (e.first != LDoNTheme::Unused) {
c->Message(
Chat::White,
fmt::format(
"Theme {} | {}",
"Theme {} | {} ({})",
e.first,
e.second
e.second.first,
e.second.second
).c_str()
);
}
@@ -25,25 +26,26 @@ void SetAdventurePoints(Client *c, const Seperator *sep)
return;
}
auto t = c;
Client* t = c;
if (c->GetTarget() && c->GetTarget()->IsClient()) {
t = c->GetTarget()->CastToClient();
}
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:");
for (const auto& e : EQ::constants::GetLDoNThemeMap()) {
if (e.first != LDoNThemes::Unused) {
for (const auto& e : ldon_theme_names) {
if (e.first != LDoNTheme::Unused) {
c->Message(
Chat::White,
fmt::format(
"Theme {} | {}",
"Theme {} | {} ({})",
e.first,
e.second
e.second.first,
e.second.second
).c_str()
);
}
@@ -56,7 +58,7 @@ void SetAdventurePoints(Client *c, const Seperator *sep)
Chat::White,
fmt::format(
"Set {} Points to {} for {}.",
EQ::constants::GetLDoNThemeName(theme_id),
LDoNTheme::GetName(theme_id),
Strings::Commify(points),
c->GetTargetDescription(t)
).c_str()
+2 -2
View File
@@ -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);
if (ldon_currency_value) {
currency_table += DialogueWindow::TableRow(
DialogueWindow::TableCell(l.second) +
DialogueWindow::TableCell(l.second.first) +
DialogueWindow::TableCell(Strings::Commify(ldon_currency_value))
);
+1 -1
View File
@@ -2419,7 +2419,7 @@ bool Group::AmIMainAssist(const char *mob_name)
if (!mob_name)
return false;
return !((bool)MainTankName.compare(mob_name));
return !((bool)MainAssistName.compare(mob_name));
}
bool Group::AmIPuller(const char *mob_name)
-2
View File
@@ -63,7 +63,6 @@ public:
void AddMember(const std::string& new_member_name);
void SendUpdate(uint32 type,Mob* member);
void SendLeadershipAAUpdate();
void SendWorldGroup(uint32 zone_id,Mob* zoningmember);
bool DelMemberOOZ(const char *Name);
bool DelMember(Mob* oldmember,bool ignoresender = false);
void DisbandGroup(bool joinraid = false);
@@ -73,7 +72,6 @@ public:
bool IsGroupMember(Mob* c);
bool IsGroupMember(const char* name);
bool Process();
bool IsGroup() { return true; }
void SendGroupJoinOOZ(Mob* NewMember);
void CastGroupSpell(Mob* caster,uint16 spellid);
void SplitExp(ExpSource exp_source, const uint64 exp, Mob* other);
+1 -1
View File
@@ -83,9 +83,9 @@ public:
void SendRankName(uint32 guild_id, uint32 rank, std::string rank_name);
void SendAllRankNames(uint32 guild_id, uint32 char_id);
BaseGuildManager::GuildInfo* GetGuildByGuildID(uint32 guild_id);
virtual void SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation);
protected:
virtual void SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation);
virtual void SendCharRefresh(uint32 old_guild_id, uint32 guild_id, uint32 charid);
virtual void SendRankUpdate(uint32 CharID);
virtual void SendGuildDelete(uint32 guild_id);
+2 -2
View File
@@ -859,9 +859,9 @@ bool NPC::HasItem(uint32 item_id)
return false;
}
uint16 NPC::CountItem(uint32 item_id)
uint32 NPC::CountItem(uint32 item_id)
{
uint16 item_count = 0;
uint32 item_count = 0;
if (!database.GetItem(item_id)) {
return item_count;
}
+4 -3
View File
@@ -274,7 +274,7 @@ void Lua_Bot::SetSpellDurationRaid(int spell_id, int duration, int level, bool a
self->SetSpellDuration(spell_id, duration, level, ApplySpellType::Raid, allow_pets, is_raid_group_only);
}
int Lua_Bot::CountAugmentEquippedByID(uint32 item_id) {
uint32 Lua_Bot::CountAugmentEquippedByID(uint32 item_id) {
Lua_Safe_Call_Int();
return self->GetInv().CountAugmentEquippedByID(item_id);
}
@@ -284,7 +284,7 @@ bool Lua_Bot::HasAugmentEquippedByID(uint32 item_id) {
return self->GetInv().HasAugmentEquippedByID(item_id);
}
int Lua_Bot::CountItemEquippedByID(uint32 item_id) {
uint32 Lua_Bot::CountItemEquippedByID(uint32 item_id) {
Lua_Safe_Call_Int();
return self->GetInv().CountItemEquippedByID(item_id);
}
@@ -701,8 +701,9 @@ luabind::scope lua_register_bot() {
.def("ClearItemReuseTimer", (void(Lua_Bot::*)(uint32))&Lua_Bot::ClearItemReuseTimer)
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)())&Lua_Bot::ClearSpellRecastTimer)
.def("ClearSpellRecastTimer", (void(Lua_Bot::*)(uint16))&Lua_Bot::ClearSpellRecastTimer)
.def("CountAugmentEquippedByID", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountAugmentEquippedByID)
.def("CountBotItem", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountBotItem)
.def("CountItemEquippedByID", (int(Lua_Bot::*)(uint32))&Lua_Bot::CountItemEquippedByID)
.def("CountItemEquippedByID", (uint32(Lua_Bot::*)(uint32))&Lua_Bot::CountItemEquippedByID)
.def("DeleteBot", (void(Lua_Bot::*)(void))&Lua_Bot::DeleteBot)
.def("DeleteBucket", (void(Lua_Bot::*)(std::string))&Lua_Bot::DeleteBucket)
.def("Escape", (void(Lua_Bot::*)(void))&Lua_Bot::Escape)
+2 -2
View File
@@ -127,8 +127,8 @@ public:
void SetSpellRecastTimer(uint16 spell_id);
void SetSpellRecastTimer(uint16 spell_id, uint32 reuse_timer);
int CountAugmentEquippedByID(uint32 item_id);
int CountItemEquippedByID(uint32 item_id);
uint32 CountAugmentEquippedByID(uint32 item_id);
uint32 CountItemEquippedByID(uint32 item_id);
bool HasAugmentEquippedByID(uint32 item_id);
bool HasItemEquippedByID(uint32 item_id);
int GetHealAmount();
+22 -6
View File
@@ -2287,7 +2287,7 @@ void Lua_Client::SendToInstance(std::string instance_type, std::string zone_shor
self->SendToInstance(instance_type, zone_short_name, instance_version, x, y, z, heading, instance_identifier, duration);
}
int Lua_Client::CountItem(uint32 item_id) {
uint32 Lua_Client::CountItem(uint32 item_id) {
Lua_Safe_Call_Int();
return self->CountItem(item_id);
}
@@ -2480,7 +2480,7 @@ void Lua_Client::AddItem(luabind::object item_table) {
);
}
int Lua_Client::CountAugmentEquippedByID(uint32 item_id) {
uint32 Lua_Client::CountAugmentEquippedByID(uint32 item_id) {
Lua_Safe_Call_Int();
return self->GetInv().CountAugmentEquippedByID(item_id);
}
@@ -2490,7 +2490,7 @@ bool Lua_Client::HasAugmentEquippedByID(uint32 item_id) {
return self->GetInv().HasAugmentEquippedByID(item_id);
}
int Lua_Client::CountItemEquippedByID(uint32 item_id) {
uint32 Lua_Client::CountItemEquippedByID(uint32 item_id) {
Lua_Safe_Call_Int();
return self->GetInv().CountItemEquippedByID(item_id);
}
@@ -3436,6 +3436,21 @@ void Lua_Client::AreaTaunt(float range, int bonus_hate)
entity_list.AETaunt(self, range, bonus_hate);
}
luabind::object Lua_Client::GetInventorySlots(lua_State* L) {
auto lua_table = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
int index = 1;
for (const int16& slot_id : self->GetInventorySlots()) {
lua_table[index] = slot_id;
index++;
}
}
return lua_table;
}
luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>())
@@ -3514,9 +3529,9 @@ luabind::scope lua_register_client() {
.def("ClearXTargets", (void(Lua_Client::*)(void))&Lua_Client::ClearXTargets)
.def("ClearZoneFlag", (void(Lua_Client::*)(uint32))&Lua_Client::ClearZoneFlag)
.def("Connected", (bool(Lua_Client::*)(void))&Lua_Client::Connected)
.def("CountAugmentEquippedByID", (int(Lua_Client::*)(uint32))&Lua_Client::CountAugmentEquippedByID)
.def("CountItem", (int(Lua_Client::*)(uint32))&Lua_Client::CountItem)
.def("CountItemEquippedByID", (int(Lua_Client::*)(uint32))&Lua_Client::CountItemEquippedByID)
.def("CountAugmentEquippedByID", (uint32(Lua_Client::*)(uint32))&Lua_Client::CountAugmentEquippedByID)
.def("CountItem", (uint32(Lua_Client::*)(uint32))&Lua_Client::CountItem)
.def("CountItemEquippedByID", (uint32(Lua_Client::*)(uint32))&Lua_Client::CountItemEquippedByID)
.def("CreateExpedition", (Lua_Expedition(Lua_Client::*)(luabind::object))&Lua_Client::CreateExpedition)
.def("CreateExpedition", (Lua_Expedition(Lua_Client::*)(std::string, uint32, uint32, std::string, uint32, uint32))&Lua_Client::CreateExpedition)
.def("CreateExpedition", (Lua_Expedition(Lua_Client::*)(std::string, uint32, uint32, std::string, uint32, uint32, bool))&Lua_Client::CreateExpedition)
@@ -3650,6 +3665,7 @@ luabind::scope lua_register_client() {
.def("GetInstrumentMod", (int(Lua_Client::*)(int))&Lua_Client::GetInstrumentMod)
.def("GetIntoxication", (int(Lua_Client::*)(void))&Lua_Client::GetIntoxication)
.def("GetInventory", (Lua_Inventory(Lua_Client::*)(void))&Lua_Client::GetInventory)
.def("GetInventorySlots", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetInventorySlots)
.def("GetInvulnerableEnvironmentDamage", (bool(Lua_Client::*)(void))&Lua_Client::GetInvulnerableEnvironmentDamage)
.def("GetItemIDAt", (int(Lua_Client::*)(int))&Lua_Client::GetItemIDAt)
.def("GetItemCooldown", (uint32(Lua_Client::*)(uint32))&Lua_Client::GetItemCooldown)
+4 -3
View File
@@ -441,14 +441,14 @@ public:
void Popup(const char* title, const char* text, uint32 popup_id, uint32 negative_id, uint32 button_type, uint32 duration);
void Popup(const char* title, const char* text, uint32 popup_id, uint32 negative_id, uint32 button_type, uint32 duration, const char* button_name_one, const char* button_name_two);
void Popup(const char* title, const char* text, uint32 popup_id, uint32 negative_id, uint32 button_type, uint32 duration, const char* button_name_one, const char* button_name_two, uint32 sound_controls);
int CountItem(uint32 item_id);
uint32 CountItem(uint32 item_id);
void RemoveItem(uint32 item_id);
void RemoveItem(uint32 item_id, uint32 quantity);
void SetGMStatus(int new_status);
int16 GetGMStatus();
void AddItem(luabind::object item_table);
int CountAugmentEquippedByID(uint32 item_id);
int CountItemEquippedByID(uint32 item_id);
uint32 CountAugmentEquippedByID(uint32 item_id);
uint32 CountItemEquippedByID(uint32 item_id);
bool HasAugmentEquippedByID(uint32 item_id);
bool HasItemEquippedByID(uint32 item_id);
int GetHealAmount();
@@ -509,6 +509,7 @@ public:
void AreaTaunt();
void AreaTaunt(float range);
void AreaTaunt(float range, int bonus_hate);
luabind::object GetInventorySlots(lua_State* L);
void ApplySpell(int spell_id);
void ApplySpell(int spell_id, int duration);
+2 -2
View File
@@ -177,7 +177,7 @@ bool Lua_Corpse::HasItem(uint32 item_id) {
return self->HasItem(item_id);
}
uint16 Lua_Corpse::CountItem(uint32 item_id) {
uint32 Lua_Corpse::CountItem(uint32 item_id) {
Lua_Safe_Call_Int();
return self->CountItem(item_id);
}
@@ -226,7 +226,7 @@ luabind::scope lua_register_corpse() {
.def("AllowMobLoot", (void(Lua_Corpse::*)(Lua_Mob, uint8))&Lua_Corpse::AllowMobLoot)
.def("Bury", (void(Lua_Corpse::*)(void))&Lua_Corpse::Bury)
.def("CanMobLoot", (bool(Lua_Corpse::*)(int))&Lua_Corpse::CanMobLoot)
.def("CountItem", (uint16(Lua_Corpse::*)(uint32))&Lua_Corpse::CountItem)
.def("CountItem", (uint32(Lua_Corpse::*)(uint32))&Lua_Corpse::CountItem)
.def("CountItems", (uint32(Lua_Corpse::*)(void))&Lua_Corpse::CountItems)
.def("Delete", (void(Lua_Corpse::*)(void))&Lua_Corpse::Delete)
.def("Depop", (void(Lua_Corpse::*)(void))&Lua_Corpse::Depop)
+1 -1
View File
@@ -62,7 +62,7 @@ public:
uint32 GetPlatinum();
void AddLooter(Lua_Mob who);
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 CountItem(uint32 item_id);
uint32 GetItemIDBySlot(uint16 loot_slot);
uint16 GetFirstLootSlotByItemID(uint32 item_id);
Lua_Corpse_Loot_List GetLootList(lua_State* L);
+4 -4
View File
@@ -164,7 +164,7 @@ int Lua_Inventory::GetSlotByItemInst(Lua_ItemInst inst) {
return self->GetSlotByItemInst(inst);
}
int Lua_Inventory::CountAugmentEquippedByID(uint32 item_id) {
uint32 Lua_Inventory::CountAugmentEquippedByID(uint32 item_id) {
Lua_Safe_Call_Int();
return self->CountAugmentEquippedByID(item_id);
}
@@ -174,7 +174,7 @@ bool Lua_Inventory::HasAugmentEquippedByID(uint32 item_id) {
return self->HasAugmentEquippedByID(item_id);
}
int Lua_Inventory::CountItemEquippedByID(uint32 item_id) {
uint32 Lua_Inventory::CountItemEquippedByID(uint32 item_id) {
Lua_Safe_Call_Int();
return self->CountItemEquippedByID(item_id);
}
@@ -208,8 +208,8 @@ luabind::scope lua_register_inventory() {
.def("CalcSlotId", (int(Lua_Inventory::*)(int,int))&Lua_Inventory::CalcSlotId)
.def("CanItemFitInContainer", (bool(Lua_Inventory::*)(Lua_Item,Lua_Item))&Lua_Inventory::CanItemFitInContainer)
.def("CheckNoDrop", (bool(Lua_Inventory::*)(int))&Lua_Inventory::CheckNoDrop)
.def("CountAugmentEquippedByID", (int(Lua_Inventory::*)(uint32))&Lua_Inventory::CountAugmentEquippedByID)
.def("CountItemEquippedByID", (int(Lua_Inventory::*)(uint32))&Lua_Inventory::CountItemEquippedByID)
.def("CountAugmentEquippedByID", (uint32(Lua_Inventory::*)(uint32))&Lua_Inventory::CountAugmentEquippedByID)
.def("CountItemEquippedByID", (uint32(Lua_Inventory::*)(uint32))&Lua_Inventory::CountItemEquippedByID)
.def("DeleteItem", (bool(Lua_Inventory::*)(int))&Lua_Inventory::DeleteItem)
.def("DeleteItem", (bool(Lua_Inventory::*)(int,int))&Lua_Inventory::DeleteItem)
.def("FindFreeSlot", (int(Lua_Inventory::*)(bool,bool))&Lua_Inventory::FindFreeSlot)
+2 -2
View File
@@ -43,8 +43,8 @@ public:
bool DeleteItem(int slot_id);
bool DeleteItem(int slot_id, int quantity);
bool CheckNoDrop(int slot_id);
int CountAugmentEquippedByID(uint32 item_id);
int CountItemEquippedByID(uint32 item_id);
uint32 CountAugmentEquippedByID(uint32 item_id);
uint32 CountItemEquippedByID(uint32 item_id);
Lua_ItemInst PopItem(int slot_id);
bool HasAugmentEquippedByID(uint32 item_id);
bool HasItemEquippedByID(uint32 item_id);
+2 -2
View File
@@ -597,7 +597,7 @@ bool Lua_NPC::HasItem(uint32 item_id)
return self->HasItem(item_id);
}
uint16 Lua_NPC::CountItem(uint32 item_id)
uint32 Lua_NPC::CountItem(uint32 item_id)
{
Lua_Safe_Call_Int();
return self->CountItem(item_id);
@@ -862,7 +862,7 @@ luabind::scope lua_register_npc() {
.def("CheckNPCFactionAlly", (int(Lua_NPC::*)(int))&Lua_NPC::CheckNPCFactionAlly)
.def("ClearItemList", (void(Lua_NPC::*)(void))&Lua_NPC::ClearLootItems)
.def("ClearLastName", (void(Lua_NPC::*)(void))&Lua_NPC::ClearLastName)
.def("CountItem", (uint16(Lua_NPC::*)(uint32))&Lua_NPC::CountItem)
.def("CountItem", (uint32(Lua_NPC::*)(uint32))&Lua_NPC::CountItem)
.def("CountLoot", (int(Lua_NPC::*)(void))&Lua_NPC::CountLoot)
.def("DeleteBucket", (void(Lua_NPC::*)(std::string))&Lua_NPC::DeleteBucket)
.def("DescribeSpecialAbilities", (void(Lua_NPC::*)(Lua_Client))&Lua_NPC::DescribeSpecialAbilities)
+1 -1
View File
@@ -146,7 +146,7 @@ public:
void ChangeLastName(std::string last_name);
void ClearLastName();
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 CountItem(uint32 item_id);
uint32 GetLootItemIDBySlot(uint16 loot_slot);
uint16 GetFirstLootSlotByItemID(uint32 item_id);
float GetHealScale();
+5 -5
View File
@@ -320,7 +320,7 @@ bool Map::Load(const std::string &filename)
}
#ifdef USE_MAP_MMFS
if (v)
if (loaded_map_file)
return SaveMMF(filename, force_mmf_overwrite);
#endif /*USE_MAP_MMFS*/
@@ -338,7 +338,7 @@ bool Map::Load(const std::string &filename)
}
#ifdef USE_MAP_MMFS
if (v)
if (loaded_map_file)
return SaveMMF(filename, force_mmf_overwrite);
#endif /*USE_MAP_MMFS*/
@@ -1064,7 +1064,7 @@ bool Map::LoadMMF(const std::string& map_file_name, bool force_mmf_overwrite)
fclose(f);
std::vector<char> rm_buffer(rm_buffer_size);
uint32 v = InflateData(mmf_buffer.data(), mmf_buffer_size, rm_buffer.data(), rm_buffer_size);
uint32 v = EQ::InflateData(mmf_buffer.data(), mmf_buffer_size, rm_buffer.data(), rm_buffer_size);
if (imp) {
imp->rm->release();
@@ -1120,11 +1120,11 @@ bool Map::SaveMMF(const std::string& map_file_name, bool force_mmf_overwrite)
}
uint32 rm_buffer_size = rm_buffer.size();
uint32 mmf_buffer_size = EstimateDeflateBuffer(rm_buffer.size());
uint32 mmf_buffer_size = EQ::EstimateDeflateBuffer(rm_buffer.size());
std::vector<char> mmf_buffer(mmf_buffer_size);
mmf_buffer_size = DeflateData(rm_buffer.data(), rm_buffer.size(), mmf_buffer.data(), mmf_buffer.size());
mmf_buffer_size = EQ::DeflateData(rm_buffer.data(), rm_buffer.size(), mmf_buffer.data(), mmf_buffer.size());
if (!mmf_buffer_size) {
LogInfo("Failed to save Map MMF file: [{}] - null MMF buffer size", mmf_file_name.c_str());
return false;
+21 -8
View File
@@ -572,6 +572,8 @@ Mob::~Mob()
m_close_mobs.clear();
ClearDataBucketCache();
LeaveHealRotationTargetPool();
}
@@ -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.
//So we'll live with it for now
if (parse->ItemHasQuestSub(const_cast<EQ::ItemInstance*>(inst), EVENT_WEAPON_PROC)) {
int i = parse->EventItem(
EVENT_WEAPON_PROC,
CastToClient(),
const_cast<EQ::ItemInstance*>(inst),
on,
"",
spell_id
);
int i = parse->EventItem(EVENT_WEAPON_PROC, CastToClient(), const_cast<EQ::ItemInstance*>(inst), on, "", spell_id);
if (i != 0) {
return;
@@ -8613,3 +8608,21 @@ std::unordered_map<uint16, Mob *> &Mob::GetCloseMobList(float 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);
}
}
+2
View File
@@ -1491,6 +1491,8 @@ public:
std::unordered_map<uint16, Mob *> &GetCloseMobList(float distance = 0.0f);
void CheckScanCloseMobsMovingTimer();
void ClearDataBucketCache();
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);
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
+1 -1
View File
@@ -222,7 +222,7 @@ public:
void RemoveLootCash();
void QueryLoot(Client *to, bool is_pet_query = false);
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 CountItem(uint32 item_id);
uint32 GetLootItemIDBySlot(uint16 loot_slot);
uint16 GetFirstLootSlotByItemID(uint32 item_id);
std::vector<int> GetLootList();
+3 -3
View File
@@ -145,7 +145,7 @@ EQ::ItemInstance* Perl_Bot_GetAugmentAt(Bot* self, int16 slot_id, uint8 augment_
return nullptr;
}
int Perl_Bot_CountAugmentEquippedByID(Bot* self, uint32 item_id)
uint32 Perl_Bot_CountAugmentEquippedByID(Bot* self, uint32 item_id)
{
return self->GetInv().CountAugmentEquippedByID(item_id);
}
@@ -155,7 +155,7 @@ bool Perl_Bot_HasAugmentEquippedByID(Bot* self, uint32 item_id)
return self->GetInv().HasAugmentEquippedByID(item_id);
}
int Perl_Bot_CountItemEquippedByID(Bot* self, uint32 item_id)
uint32 Perl_Bot_CountItemEquippedByID(Bot* self, uint32 item_id)
{
return self->GetInv().CountItemEquippedByID(item_id);
}
@@ -650,7 +650,7 @@ void perl_register_bot()
package.add("ApplySpellRaid", (void(*)(Bot*, int, int, int, bool))&Perl_Bot_ApplySpellRaid);
package.add("ApplySpellRaid", (void(*)(Bot*, int, int, int, bool, bool))&Perl_Bot_ApplySpellRaid);
package.add("Camp", (void(*)(Bot*))&Perl_Bot_Camp);
package.add("Camp", (void(*)(Bot*, bool))&Perl_Bot_Camp);
package.add("Camp", (void(*)(Bot*, bool))&Perl_Bot_Camp);
package.add("ClearDisciplineReuseTimer", (void(*)(Bot*))&Perl_Bot_ClearDisciplineReuseTimer);
package.add("ClearDisciplineReuseTimer", (void(*)(Bot*, uint16))&Perl_Bot_ClearDisciplineReuseTimer);
package.add("ClearItemReuseTimer", (void(*)(Bot*))&Perl_Bot_ClearItemReuseTimer);
+16 -3
View File
@@ -2209,7 +2209,7 @@ void Perl_Client_SendToInstance(Client* self, std::string instance_type, std::st
self->SendToInstance(instance_type, zone_short_name, instance_version, x, y, z, heading, instance_identifier, duration);
}
int Perl_Client_CountItem(Client* self, uint32 item_id)
uint32 Perl_Client_CountItem(Client* self, uint32 item_id)
{
return self->CountItem(item_id);
}
@@ -2388,7 +2388,7 @@ void Perl_Client_AddItem(Client* self, perl::reference table_ref)
augment_four, augment_five, augment_six, attuned, slot_id);
}
int Perl_Client_CountAugmentEquippedByID(Client* self, uint32 item_id)
uint32 Perl_Client_CountAugmentEquippedByID(Client* self, uint32 item_id)
{
return self->GetInv().CountAugmentEquippedByID(item_id);
}
@@ -2398,7 +2398,7 @@ bool Perl_Client_HasAugmentEquippedByID(Client* self, uint32 item_id)
return self->GetInv().HasAugmentEquippedByID(item_id);
}
int Perl_Client_CountItemEquippedByID(Client* self, uint32 item_id)
uint32 Perl_Client_CountItemEquippedByID(Client* self, uint32 item_id)
{
return self->GetInv().CountItemEquippedByID(item_id);
}
@@ -3212,6 +3212,18 @@ Merc* Perl_Client_GetMerc(Client* self)
return self->GetMerc();
}
perl::array Perl_Client_GetInventorySlots(Client* self)
{
perl::array result;
const auto& v = self->GetInventorySlots();
for (int i = 0; i < v.size(); ++i) {
result.push_back(v[i]);
}
return result;
}
void perl_register_client()
{
perl::interpreter perl(PERL_GET_THX);
@@ -3426,6 +3438,7 @@ void perl_register_client()
package.add("GetInstanceID", &Perl_Client_GetInstanceID);
package.add("GetInstrumentMod", &Perl_Client_GetInstrumentMod);
package.add("GetInventory", &Perl_Client_GetInventory);
package.add("GetInventorySlots", &Perl_Client_GetInventorySlots);
package.add("GetInvulnerableEnvironmentDamage", &Perl_Client_GetInvulnerableEnvironmentDamage);
package.add("GetItemAt", &Perl_Client_GetItemAt);
package.add("GetItemCooldown", &Perl_Client_GetItemCooldown);
+2 -2
View File
@@ -150,7 +150,7 @@ bool Perl_Inventory_HasAugmentEquippedByID(EQ::InventoryProfile* self, uint32_t
return self->HasAugmentEquippedByID(item_id);
}
int Perl_Inventory_CountAugmentEquippedByID(EQ::InventoryProfile* self, uint32_t item_id)
uint32 Perl_Inventory_CountAugmentEquippedByID(EQ::InventoryProfile* self, uint32_t item_id)
{
return self->CountAugmentEquippedByID(item_id);
}
@@ -160,7 +160,7 @@ bool Perl_Inventory_HasItemEquippedByID(EQ::InventoryProfile* self, uint32_t ite
return self->HasItemEquippedByID(item_id);
}
int Perl_Inventory_CountItemEquippedByID(EQ::InventoryProfile* self, uint32_t item_id)
uint32 Perl_Inventory_CountItemEquippedByID(EQ::InventoryProfile* self, uint32_t item_id)
{
return self->CountItemEquippedByID(item_id);
}
+1 -1
View File
@@ -615,7 +615,7 @@ bool Perl_NPC_HasItem(NPC* self, uint32 item_id) // @categories Script Utility
return self->HasItem(item_id);
}
int Perl_NPC_CountItem(NPC* self, uint32 item_id)
uint32 Perl_NPC_CountItem(NPC* self, uint32 item_id)
{
return self->CountItem(item_id);
}
+1 -1
View File
@@ -161,7 +161,7 @@ bool Perl_Corpse_HasItem(Corpse* self, uint32_t item_id) // @categories Script U
return self->HasItem(item_id);
}
int Perl_Corpse_CountItem(Corpse* self, uint32_t item_id) // @categories Script Utility
uint32 Perl_Corpse_CountItem(Corpse* self, uint32_t item_id) // @categories Script Utility
{
return self->CountItem(item_id);
}
+14 -53
View File
@@ -91,13 +91,7 @@ void QuestManager::Process() {
if (cur->Timer_.Enabled() && cur->Timer_.Check()) {
if (cur->mob) {
if (cur->mob->IsEncounter()) {
parse->EventEncounter(
EVENT_TIMER,
cur->mob->CastToEncounter()->GetEncounterName(),
cur->name,
0,
nullptr
);
parse->EventEncounter(EVENT_TIMER, cur->mob->CastToEncounter()->GetEncounterName(), cur->name, 0, nullptr);
} else {
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) {
if (e->mob && e->mob == owner && e->name == timer_name) {
parse->EventMob(
EVENT_TIMER_STOP,
owner,
nullptr,
[&]() {
return timer_name;
}
);
parse->EventMob(EVENT_TIMER_STOP, owner, nullptr, [&]() { return timer_name; });
QTimerList.erase(e);
break;
@@ -695,14 +682,7 @@ void QuestManager::stoptimer(const std::string& timer_name, Mob* m)
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
if (e->mob && e->mob == m) {
parse->EventMob(
EVENT_TIMER_STOP,
m,
nullptr,
[&]() {
return timer_name;
}
);
parse->EventMob(EVENT_TIMER_STOP, m, nullptr, [&]() { return timer_name; });
QTimerList.erase(e);
break;
@@ -743,14 +723,7 @@ void QuestManager::stopalltimers()
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
if (e->mob && e->mob == owner) {
parse->EventMob(
EVENT_TIMER_STOP,
owner,
nullptr,
[&]() {
return e->name;
}
);
parse->EventMob(EVENT_TIMER_STOP, owner, nullptr, [&]() { return e->name; });
e = QTimerList.erase(e);
} else {
@@ -792,14 +765,7 @@ void QuestManager::stopalltimers(Mob* m)
for (auto e = QTimerList.begin(); e != QTimerList.end();) {
if (e->mob && e->mob == m) {
parse->EventMob(
EVENT_TIMER_STOP,
m,
nullptr,
[&]() {
return e->name;
}
);
parse->EventMob(EVENT_TIMER_STOP, m, nullptr, [&]() { return e->name; });
e = QTimerList.erase(e);
} else {
@@ -853,18 +819,13 @@ void QuestManager::pausetimer(const std::string& timer_name, Mob* m)
}
);
parse->EventMob(
EVENT_TIMER_PAUSE,
mob,
nullptr,
[&]() {
return fmt::format(
"{} {}",
timer_name,
milliseconds
);
}
);
parse->EventMob(EVENT_TIMER_PAUSE, mob, nullptr, [&]() {
return fmt::format(
"{} {}",
timer_name,
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) {
return EQ::constants::GetLDoNThemeName(theme_id);
return LDoNTheme::GetName(theme_id);
}
std::string QuestManager::getfactionname(int faction_id) {
@@ -3343,7 +3304,7 @@ int QuestManager::collectitems(uint32 item_id, bool remove)
return quantity;
}
int QuestManager::countitem(uint32 item_id) {
uint32 QuestManager::countitem(uint32 item_id) {
QuestManagerCurrentQuestVars();
if (!initiator) {
+1 -1
View File
@@ -249,7 +249,7 @@ public:
int getlevel(uint8 type);
int collectitems(uint32 item_id, bool remove);
int collectitems_processSlot(int16 slot_id, uint32 item_id, bool remove);
int countitem(uint32 item_id);
uint32 countitem(uint32 item_id);
void removeitem(uint32 item_id, uint32 quantity = 1);
std::string getitemcomment(uint32 item_id);
std::string getitemlore(uint32 item_id);
+104 -139
View File
@@ -256,22 +256,15 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
Mob* spell_target = entity_list.GetMobID(target_id);
std::vector<std::any> args = { spell_target };
int return_value = parse->EventMob(
EVENT_CAST_BEGIN,
this,
nullptr,
[&]() {
return fmt::format(
"{} {} {} {}",
spell_id,
GetID(),
GetCasterLevel(spell_id),
target_id
);
},
0,
&args
);
int return_value = parse->EventMob(EVENT_CAST_BEGIN, this, nullptr, [&]() {
return fmt::format(
"{} {} {} {}",
spell_id,
GetID(),
GetCasterLevel(spell_id),
target_id
);
}, 0, &args);
if (IsClient() && return_value != 0) {
if (IsDiscipline(spell_id)) {
@@ -652,6 +645,11 @@ bool Mob::DoCastingChecksOnCaster(int32 spell_id, CastingSlot slot) {
return true;
}
struct SpellCheck {
std::function<bool()> condition; // The condition to check
std::function<bool()> action; // The action if the condition fails
};
bool Mob::DoCastingChecksZoneRestrictions(bool check_on_casting, int32 spell_id) {
/*
@@ -659,114 +657,92 @@ bool Mob::DoCastingChecksZoneRestrictions(bool check_on_casting, int32 spell_id)
- levitate zone restriction (client blocks) [cancel before begin cast message]
- can not cast outdoor [cancels after spell finishes channeling]
If the spell is a casted spell, check on CastSpell and ignore on SpellFinished.
If the spell is a initiated from SpellFinished, then check at start of SpellFinished.
If the spell is a cast spell, check on CastSpell and ignore on SpellFinished.
If the spell is initiated from SpellFinished, then check at start of SpellFinished.
*/
bool bypass_casting_restrictions = false;
bool bypass_casting_restrictions = !IsClient();
glm::vec3 position = glm::vec3(GetPosition());
if (!IsClient()) {
bypass_casting_restrictions = true;
}
if (IsClient() && CastToClient()->GetGM()) {
bypass_casting_restrictions = true;
Message(
Chat::White,
fmt::format(
"Your GM flag allows you to bypass zone casting restrictions and cast {} in this zone.",
Saylink::Silent(
fmt::format(
"#castspell {}",
spell_id
),
GetSpellName(spell_id)
)
).c_str()
);
}
/*
Zone ares that prevent blocked spells from being cast.
If on cast iniated then check any mob casting, if on spellfinished only check if is from client.
*/
if ((check_on_casting && !bypass_casting_restrictions) || (!check_on_casting && IsClient())) {
if (zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) {
if (IsClient()) {
if (!CastToClient()->GetGM()) {
const char *msg = zone->GetSpellBlockedMessage(spell_id, glm::vec3(GetPosition()));
if (msg) {
Message(Chat::Red, msg);
return false;
}
else {
Message(Chat::Red, "You can't cast this spell here.");
return false;
}
LogSpells("Spell casting canceled [{}] : can not cast in this zone location blocked spell.", spell_id);
}
else {
Message(
Chat::White,
fmt::format(
"Your GM flag allows you to bypass zone blocked spells and cast {} in this zone.",
Saylink::Silent(
fmt::format(
"#castspell {}",
spell_id
),
GetSpellName(spell_id)
)
).c_str()
);
LogSpells("GM Cast Blocked Spell: [{}] (ID [{}])", GetSpellName(spell_id), spell_id);
}
}
return false;
auto gm_bypass_message = [&](const std::string& restriction) {
if (CastToClient()->GetGM()) {
Message(
Chat::White,
fmt::format(
"Your GM flag allows you to bypass {} and cast {}.",
restriction,
Saylink::Silent(
fmt::format("#castspell {}", spell_id),
GetSpellName(spell_id)
)
).c_str()
);
return true;
}
}
/*
Zones where you can not use levitate spells.
*/
if (!bypass_casting_restrictions && !zone->CanLevitate() && IsEffectInSpell(spell_id, SE_Levitate)) { //check on spellfinished.
Message(Chat::Red, "You have entered an area where levitation effects do not function.");
LogSpells("Spell casting canceled [{}] : can not cast levitation in this zone.", spell_id);
return false;
}
/*
Zones where you can not use detrimental spells.
*/
if (IsDetrimentalSpell(spell_id) && !zone->CanDoCombat()) {
Message(Chat::Red, "You cannot cast detrimental spells here.");
return false;
}
/*
Zones where you can not cast a spell that is for daytime or nighttime only
*/
if (spells[spell_id].time_of_day == SpellTimeRestrictions::Day && !zone->zone_time.IsDayTime()) {
MessageString(Chat::Red, CAST_DAYTIME);
return false;
}
};
if (spells[spell_id].time_of_day == SpellTimeRestrictions::Night && !zone->zone_time.IsNightTime()) {
MessageString(Chat::Red, CAST_NIGHTTIME);
return false;
}
if (check_on_casting) {
/*
Zones where you can not cast out door only spells. This is only checked when casting is completed.
*/
if (!bypass_casting_restrictions && spells[spell_id].zone_type == 1 && !zone->CanCastOutdoor()) {
if (IsClient()) {
if (!CastToClient()->GetGM()) {
MessageString(Chat::Red, CAST_OUTDOORS);
LogSpells("Spell casting canceled [{}] : can not cast outdoors.", spell_id);
return false;
} else {
Message(Chat::White, "Your GM flag allows you to cast outdoor spells when indoors.");
}
std::vector<SpellCheck> spell_checks = {
// Blocked spells
{
[&]() { return !bypass_casting_restrictions && zone->IsSpellBlocked(spell_id, position); },
[&]() {
if (gm_bypass_message("zone blocked spells")) { return true; }
const char* msg = zone->GetSpellBlockedMessage(spell_id, position);
Message(Chat::Red, msg ? msg : "You can't cast this spell here.");
return false;
}
},
// Levitation restriction
{
[&]() { return !bypass_casting_restrictions && !zone->CanLevitate() && IsEffectInSpell(spell_id, SE_Levitate); },
[&]() {
if (gm_bypass_message("zone levitation restrictions")) { return true; }
Message(Chat::Red, "You have entered an area where levitation effects do not function.");
return false;
}
},
// Detrimental spells restriction
{
[&]() { return !bypass_casting_restrictions && IsDetrimentalSpell(spell_id) && !zone->CanDoCombat(); },
[&]() {
if (gm_bypass_message("no combat zone restrictions")) { return true; }
Message(Chat::Red, "You cannot cast detrimental spells here.");
return false;
}
},
// Daytime-only spells
{
[&]() { return !bypass_casting_restrictions && spells[spell_id].time_of_day == SpellTimeRestrictions::Day && !zone->zone_time.IsDayTime(); },
[&]() {
if (gm_bypass_message("spell daytime restrictions")) { return true; }
MessageString(Chat::Red, CAST_DAYTIME);
return false;
}
},
// Nighttime-only spells
{
[&]() { return !bypass_casting_restrictions && spells[spell_id].time_of_day == SpellTimeRestrictions::Night && !zone->zone_time.IsNightTime(); },
[&]() {
if (gm_bypass_message("spell nighttime restrictions")) return true;
MessageString(Chat::Red, CAST_NIGHTTIME);
return false;
}
},
// Outdoor-only spells
{
[&]() { return check_on_casting && !bypass_casting_restrictions && spells[spell_id].zone_type == 1 && !zone->CanCastOutdoor(); },
[&]() {
if (gm_bypass_message("zone outdoor restrictions")) return true;
MessageString(Chat::Red, CAST_OUTDOORS);
return false;
}
}
};
for (const auto& check : spell_checks) {
if (check.condition() && !check.action()) {
return false;
}
}
@@ -1804,22 +1780,15 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
std::vector<std::any> args = { spell_target };
parse->EventMob(
EVENT_CAST,
this,
nullptr,
[&]() {
return fmt::format(
"{} {} {} {}",
spell_id,
GetID(),
GetCasterLevel(spell_id),
target_id
);
},
0,
&args
);
parse->EventMob(EVENT_CAST, this, nullptr, [&]() {
return fmt::format(
"{} {} {} {}",
spell_id,
GetID(),
GetCasterLevel(spell_id),
target_id
);
}, 0, &args);
if(bard_song_mode)
{
@@ -3965,10 +3934,7 @@ bool Mob::SpellOnTarget(
std::vector<std::any> args = { spelltar };
parse->EventMob(
EVENT_CAST_ON,
spelltar,
this,
parse->EventMob(EVENT_CAST_ON, spelltar, this,
[&]() {
return fmt::format(
"{} {} {} {}",
@@ -3978,8 +3944,7 @@ bool Mob::SpellOnTarget(
target_id
);
},
0,
&args
0, &args
);
if (!DoCastingChecksOnTarget(false, spell_id, spelltar)) {
+27 -22
View File
@@ -1093,15 +1093,16 @@ void Client::TraderStartTrader(const EQApplicationPacket *app)
inst->SetPrice(in->item_cost[i]);
TraderRepository::Trader trader_item{};
trader_item.id = 0;
trader_item.char_entity_id = GetID();
trader_item.char_id = CharacterID();
trader_item.char_zone_id = GetZoneID();
trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges();
trader_item.item_cost = inst->GetPrice();
trader_item.item_id = inst->GetID();
trader_item.item_sn = in->serial_number[i];
trader_item.slot_id = i;
trader_item.id = 0;
trader_item.char_entity_id = GetID();
trader_item.char_id = CharacterID();
trader_item.char_zone_id = GetZoneID();
trader_item.char_zone_instance_id = GetInstanceID();
trader_item.item_charges = inst->GetCharges() == 0 ? 1 : inst->GetCharges();
trader_item.item_cost = inst->GetPrice();
trader_item.item_id = inst->GetID();
trader_item.item_sn = in->serial_number[i];
trader_item.slot_id = i;
if (inst->IsAugmented()) {
auto augs = inst->GetAugmentIDs();
trader_item.aug_slot_1 = augs.at(0);
@@ -1796,7 +1797,7 @@ void Client::SendBarterWelcome()
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()) {
SendBazaarDone(GetID());
return;
@@ -2940,9 +2941,11 @@ void Client::SendBecomeTrader(BazaarTraderBarterActions action, uint32 entity_id
auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct));
auto data = (BecomeTrader_Struct *) outapp->pBuffer;
data->action = action;
data->entity_id = trader->GetID();
data->trader_id = trader->CharacterID();
data->action = action;
data->entity_id = trader->GetID();
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));
QueuePacket(outapp);
@@ -3088,14 +3091,15 @@ void Client::TraderPriceUpdate(const EQApplicationPacket *app)
auto item_detail = FindTraderItemBySerialNumber(newgis->serial_number[i]);
TraderRepository::Trader trader_item{};
trader_item.id = 0;
trader_item.char_entity_id = GetID();
trader_item.char_id = CharacterID();
trader_item.char_zone_id = GetZoneID();
trader_item.item_charges = newgis->charges[i];
trader_item.item_cost = tpus->NewPrice;
trader_item.item_id = newgis->items[i];
trader_item.item_sn = newgis->serial_number[i];
trader_item.id = 0;
trader_item.char_entity_id = GetID();
trader_item.char_id = CharacterID();
trader_item.char_zone_id = GetZoneID();
trader_item.char_zone_instance_id = GetInstanceID();
trader_item.item_charges = newgis->charges[i];
trader_item.item_cost = tpus->NewPrice;
trader_item.item_id = newgis->items[i];
trader_item.item_sn = newgis->serial_number[i];
if (item_detail->IsAugmented()) {
auto augs = item_detail->GetAugmentIDs();
trader_item.aug_slot_1 = augs.at(0);
@@ -3224,7 +3228,8 @@ void Client::SendBulkBazaarTraders()
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, results.count);
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.entity_id);
VARSTRUCT_ENCODE_STRING(bufptr, t.trader_name.c_str());
+6 -17
View File
@@ -91,8 +91,6 @@ void WorldServer::Connect()
});
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
m_keepalive = std::make_unique<EQ::Timer>(1000, true, std::bind(&WorldServer::OnKeepAlive, this, std::placeholders::_1));
}
bool WorldServer::SendPacket(ServerPacket *pack)
@@ -3644,11 +3642,6 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
SharedTaskZoneMessaging::HandleWorldMessage(pack);
break;
}
case ServerOP_DataBucketCacheUpdate:
{
DataBucket::HandleWorldMessage(pack);
break;
}
case ServerOP_GuildTributeUpdate: {
GuildTributeUpdate* in = (GuildTributeUpdate*)pack->pBuffer;
@@ -3934,12 +3927,14 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
out->action = 0;
}
}
out->entity_id = in->entity_id;
out->zone_id = in->zone_id;
out->trader_id = in->trader_id;
out->entity_id = in->entity_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));
c.second->QueuePacket(outapp);
c.second->QueuePacket(outapp, true, Mob::CLIENT_CONNECTED);
safe_delete(outapp);
}
if (zone && zone->GetZoneID() == Zones::BAZAAR && in->instance_id == zone->GetInstanceID()) {
@@ -4693,12 +4688,6 @@ void WorldServer::RequestTellQueue(const char *who)
return;
}
void WorldServer::OnKeepAlive(EQ::Timer *t)
{
ServerPacket pack(ServerOP_KeepAlive, 0);
SendPacket(&pack);
}
ZoneEventScheduler *WorldServer::GetScheduler() const
{
return m_zone_scheduler;
-2
View File
@@ -73,8 +73,6 @@ private:
uint32 cur_groupid;
uint32 last_groupid;
void OnKeepAlive(EQ::Timer *t);
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
std::unique_ptr<EQ::Timer> m_keepalive;
+9 -1
View File
@@ -1100,7 +1100,12 @@ Zone::~Zone() {
if (worldserver.Connected()) {
worldserver.SetZoneData(0);
}
for (auto &e: npc_emote_list) {
safe_delete(e);
}
npc_emote_list.clear();
zone_point_list.Clear();
entity_list.Clear();
parse->ReloadQuests();
@@ -1257,7 +1262,6 @@ void Zone::ReloadStaticData() {
LoadVeteranRewards();
LoadAlternateCurrencies();
npc_emote_list.clear();
LoadNPCEmotes(&npc_emote_list);
//load the zone config file.
@@ -2575,6 +2579,10 @@ void Zone::DoAdventureActions()
void Zone::LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* v)
{
for (auto &e: *v) {
safe_delete(e);
}
v->clear();
const auto& l = NpcEmotesRepository::All(content_db);
+7 -5
View File
@@ -43,11 +43,13 @@ class ZoneConfig : public EQEmuConfig {
}
// Load the config
static bool LoadConfig(const std::string& path = "") {
if (_zone_config != nullptr)
delete _zone_config;
_zone_config=new ZoneConfig;
_config=_zone_config;
static bool LoadConfig(const std::string &path = "")
{
safe_delete(_zone_config);
safe_delete(_config);
_zone_config = new ZoneConfig;
_config = _zone_config;
return _config->parseFile(path);
}
-2
View File
@@ -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()) {
zone->LoadNPCFactions(npc_faction_ids);
zone->LoadNPCFactionAssociations(npc_faction_ids);