mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-24 22:32:29 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fcb0a47280 | |||
| 1e50f19f7e | |||
| 33bb5aa8e5 | |||
| 6a668f8aa5 | |||
| df499b22ab | |||
| 7bc00cb466 | |||
| 51f6108aab | |||
| c13f9f80d9 | |||
| 443abf9199 | |||
| 1556e05b2f | |||
| 1d645aa5f6 | |||
| 9f42da5bad | |||
| 4a8222f243 | |||
| db4c515853 | |||
| 462656a201 | |||
| ddd98be383 |
@@ -1,3 +1,50 @@
|
||||
## [22.4.3] - 02/21/2023
|
||||
|
||||
### Bots
|
||||
|
||||
* Change HasBotItem(item_id) to return slot_id instead of bool. ([#2966](https://github.com/EQEmu/Server/pull/2966)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-19
|
||||
* Change SaveTimers to Replace instead of Insert. ([#2951](https://github.com/EQEmu/Server/pull/2951)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
|
||||
* Fix output of ^spells while ^Enforcespellsettings is enabled ([#2959](https://github.com/EQEmu/Server/pull/2959)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-18
|
||||
|
||||
### Crash
|
||||
|
||||
* Fix crash with EVENT_UNEQUIP_ITEM_BOT ([#2973](https://github.com/EQEmu/Server/pull/2973)) ([Aeadoin](https://github.com/Aeadoin)) 2023-02-20
|
||||
* Fix world crash in player event processing ([#2960](https://github.com/EQEmu/Server/pull/2960)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
|
||||
|
||||
### Database
|
||||
|
||||
* Address deadlock in player events ([#2974](https://github.com/EQEmu/Server/pull/2974)) ([Akkadius](https://github.com/Akkadius)) 2023-02-21
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fix MIR LDoN Theme Items on LDoN Merchants ([#2971](https://github.com/EQEmu/Server/pull/2971)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-20
|
||||
* Fix OOCMute not functioning ([#2970](https://github.com/EQEmu/Server/pull/2970)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-20
|
||||
|
||||
### Pathing
|
||||
|
||||
* Improvements to z-clipping, z-recovery and z-calculations ([#2975](https://github.com/EQEmu/Server/pull/2975)) ([Akkadius](https://github.com/Akkadius)) 2023-02-21
|
||||
|
||||
### Pets
|
||||
|
||||
* Client Pet summoned by NPC should not change guard location. ([#2967](https://github.com/EQEmu/Server/pull/2967)) ([noudess](https://github.com/noudess)) 2023-02-19
|
||||
|
||||
### Player Events
|
||||
|
||||
* Create new event ITEM_CREATION ([#2944](https://github.com/EQEmu/Server/pull/2944)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
|
||||
|
||||
### Quest API
|
||||
|
||||
* Add client->SignalClient() overload to Perl ([#2963](https://github.com/EQEmu/Server/pull/2963)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-19
|
||||
* Fix Perl SetSimpleRoamBox Overloads ([#2961](https://github.com/EQEmu/Server/pull/2961)) ([Kinglykrab](https://github.com/Kinglykrab)) 2023-02-19
|
||||
|
||||
### Reload API
|
||||
|
||||
* Add world handlers for certain opcodes ([#2958](https://github.com/EQEmu/Server/pull/2958)) ([Akkadius](https://github.com/Akkadius)) 2023-02-18
|
||||
|
||||
### SQL
|
||||
|
||||
* Add date to optional Drakkin Guktan Faction Update ([#2965](https://github.com/EQEmu/Server/pull/2965)) ([joligario](https://github.com/joligario)) 2023-02-19
|
||||
|
||||
## [22.4.2] - 02/18/2023
|
||||
|
||||
### Content
|
||||
|
||||
+15
-7
@@ -70,17 +70,20 @@ DBcore::~DBcore()
|
||||
// Sends the MySQL server a keepalive
|
||||
void DBcore::ping()
|
||||
{
|
||||
if (!MDatabase.trylock()) {
|
||||
if (!m_query_lock.try_lock()) {
|
||||
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
|
||||
return;
|
||||
}
|
||||
mysql_ping(&mysql);
|
||||
MDatabase.unlock();
|
||||
m_query_lock.unlock();
|
||||
}
|
||||
|
||||
MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce)
|
||||
{
|
||||
return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
|
||||
m_query_lock.lock();
|
||||
auto r = QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce);
|
||||
m_query_lock.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
bool DBcore::DoesTableExist(std::string table_name)
|
||||
@@ -95,15 +98,11 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
|
||||
LockMutex lock(&MDatabase);
|
||||
|
||||
// Reconnect if we are not connected before hand.
|
||||
if (pStatus != Connected) {
|
||||
Open();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// request query. != 0 indicates some kind of error.
|
||||
if (mysql_real_query(&mysql, query, querylen) != 0) {
|
||||
unsigned int errorNumber = mysql_errno(&mysql);
|
||||
@@ -299,3 +298,12 @@ void DBcore::SetOriginHost(const std::string &origin_host)
|
||||
{
|
||||
DBcore::origin_host = origin_host;
|
||||
}
|
||||
|
||||
std::string DBcore::Escape(const std::string& s)
|
||||
{
|
||||
const std::size_t s_len = s.length();
|
||||
std::vector<char> temp((s_len * 2) + 1, '\0');
|
||||
mysql_real_escape_string(&mysql, temp.data(), s.c_str(), s_len);
|
||||
|
||||
return temp.data();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <mysql.h>
|
||||
#include <string.h>
|
||||
#include <mutex>
|
||||
|
||||
class DBcore {
|
||||
public:
|
||||
@@ -27,6 +28,7 @@ public:
|
||||
void TransactionBegin();
|
||||
void TransactionCommit();
|
||||
void TransactionRollback();
|
||||
std::string Escape(const std::string& s);
|
||||
uint32 DoEscapeString(char *tobuf, const char *frombuf, uint32 fromlen);
|
||||
void ping();
|
||||
MYSQL *getMySQL() { return &mysql; }
|
||||
@@ -57,6 +59,8 @@ private:
|
||||
Mutex MDatabase;
|
||||
eStatus pStatus;
|
||||
|
||||
std::mutex m_query_lock{};
|
||||
|
||||
std::string origin_host;
|
||||
|
||||
char *pHost;
|
||||
|
||||
@@ -113,7 +113,9 @@ bool PlayerEventLogs::IsEventEnabled(PlayerEvent::EventType event)
|
||||
// this processes any current player events on the queue
|
||||
void PlayerEventLogs::ProcessBatchQueue()
|
||||
{
|
||||
m_batch_queue_lock.lock();
|
||||
if (m_record_batch_queue.empty()) {
|
||||
m_batch_queue_lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +130,6 @@ void PlayerEventLogs::ProcessBatchQueue()
|
||||
);
|
||||
|
||||
// empty
|
||||
m_batch_queue_lock.lock();
|
||||
m_record_batch_queue = {};
|
||||
m_batch_queue_lock.unlock();
|
||||
}
|
||||
@@ -139,6 +140,10 @@ void PlayerEventLogs::AddToQueue(const PlayerEventLogsRepository::PlayerEventLog
|
||||
m_batch_queue_lock.lock();
|
||||
m_record_batch_queue.emplace_back(log);
|
||||
m_batch_queue_lock.unlock();
|
||||
|
||||
if (m_record_batch_queue.size() >= RuleI(Logging, BatchPlayerEventProcessChunkSize)) {
|
||||
ProcessBatchQueue();
|
||||
}
|
||||
}
|
||||
|
||||
// fills common event data in the SendEvent function
|
||||
@@ -699,6 +704,7 @@ void PlayerEventLogs::SetSettingsDefaults()
|
||||
m_settings[PlayerEvent::KILLED_NPC].event_enabled = 0;
|
||||
m_settings[PlayerEvent::KILLED_NAMED_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::KILLED_RAID_NPC].event_enabled = 1;
|
||||
m_settings[PlayerEvent::ITEM_CREATION].event_enabled = 1;
|
||||
|
||||
for (int i = PlayerEvent::GM_COMMAND; i != PlayerEvent::MAX; i++) {
|
||||
m_settings[i].retention_days = RETENTION_DAYS_DEFAULT;
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace PlayerEvent {
|
||||
KILLED_NPC,
|
||||
KILLED_NAMED_NPC,
|
||||
KILLED_RAID_NPC,
|
||||
ITEM_CREATION,
|
||||
MAX // dont remove
|
||||
};
|
||||
|
||||
@@ -110,7 +111,8 @@ namespace PlayerEvent {
|
||||
"Possible Hack",
|
||||
"Killed NPC",
|
||||
"Killed Named NPC",
|
||||
"Killed Raid NPC"
|
||||
"Killed Raid NPC",
|
||||
"Item Creation"
|
||||
};
|
||||
|
||||
// Generic struct used by all events
|
||||
@@ -184,6 +186,40 @@ namespace PlayerEvent {
|
||||
}
|
||||
};
|
||||
|
||||
// used in Trade event
|
||||
struct ItemCreationEvent {
|
||||
int64 item_id;
|
||||
std::string item_name;
|
||||
uint16 to_slot;
|
||||
int16 charges;
|
||||
uint32 aug1;
|
||||
uint32 aug2;
|
||||
uint32 aug3;
|
||||
uint32 aug4;
|
||||
uint32 aug5;
|
||||
uint32 aug6;
|
||||
bool attuned;
|
||||
|
||||
// cereal
|
||||
template<class Archive>
|
||||
void serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
CEREAL_NVP(item_id),
|
||||
CEREAL_NVP(item_name),
|
||||
CEREAL_NVP(to_slot),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(aug1),
|
||||
CEREAL_NVP(aug2),
|
||||
CEREAL_NVP(aug3),
|
||||
CEREAL_NVP(aug4),
|
||||
CEREAL_NVP(aug5),
|
||||
CEREAL_NVP(aug6),
|
||||
CEREAL_NVP(attuned)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// used in Trade event
|
||||
struct TradeItem {
|
||||
int64 item_id;
|
||||
|
||||
@@ -240,8 +240,8 @@ public:
|
||||
v.push_back(columns[7] + " = " + std::to_string(e.z));
|
||||
v.push_back(columns[8] + " = " + std::to_string(e.heading));
|
||||
v.push_back(columns[9] + " = " + std::to_string(e.event_type_id));
|
||||
v.push_back(columns[10] + " = '" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back(columns[11] + " = '" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back(columns[10] + " = '" + db.Escape(e.event_type_name) + "'");
|
||||
v.push_back(columns[11] + " = '" + db.Escape(e.event_data) + "'");
|
||||
v.push_back(columns[12] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
@@ -274,8 +274,8 @@ public:
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.event_type_id));
|
||||
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back("'" + db.Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + db.Escape(e.event_data) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
auto results = db.QueryDatabase(
|
||||
@@ -316,8 +316,8 @@ public:
|
||||
v.push_back(std::to_string(e.z));
|
||||
v.push_back(std::to_string(e.heading));
|
||||
v.push_back(std::to_string(e.event_type_id));
|
||||
v.push_back("'" + Strings::Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + Strings::Escape(e.event_data) + "'");
|
||||
v.push_back("'" + db.Escape(e.event_type_name) + "'");
|
||||
v.push_back("'" + db.Escape(e.event_data) + "'");
|
||||
v.push_back("FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")");
|
||||
|
||||
insert_chunks.push_back("(" + Strings::Implode(",", v) + ")");
|
||||
|
||||
@@ -783,6 +783,7 @@ RULE_BOOL(Logging, PrintFileFunctionAndLine, false, "Ex: [World Server] [net.cpp
|
||||
RULE_BOOL(Logging, WorldGMSayLogging, true, "Relay worldserver logging to zone processes via GM say output")
|
||||
RULE_BOOL(Logging, PlayerEventsQSProcess, false, "Have query server process player events instead of world. Useful when wanting to use a dedicated server and database for processing player events on separate disk")
|
||||
RULE_INT(Logging, BatchPlayerEventProcessIntervalSeconds, 5, "This is the interval in which player events are processed in world or qs")
|
||||
RULE_INT(Logging, BatchPlayerEventProcessChunkSize, 10000, "This is the cap of events that can be inserted into the queue before a force flush. This is to keep from hitting MySQL max_allowed_packet and killing the connection")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(HotReload)
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
// Build variables
|
||||
// these get injected during the build pipeline
|
||||
#define CURRENT_VERSION "22.4.2-dev" // always append -dev to the current version for custom-builds
|
||||
#define CURRENT_VERSION "22.4.3-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__
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eqemu-server",
|
||||
"version": "22.4.2",
|
||||
"version": "22.4.3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/EQEmu/Server.git"
|
||||
|
||||
@@ -224,6 +224,13 @@ void EQEmuApiWorldDataService::reload(Json::Value &r, const std::vector<std::str
|
||||
else {
|
||||
pack = new ServerPacket(c.opcode, 0);
|
||||
message(r, fmt::format("Reloading [{}] globally", c.desc));
|
||||
|
||||
if (c.opcode == ServerOP_ReloadLogs) {
|
||||
LogSys.LoadLogDatabaseSettings();
|
||||
}
|
||||
else if (c.opcode == ServerOP_ReloadRules) {
|
||||
RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true);
|
||||
}
|
||||
}
|
||||
|
||||
found_command = true;
|
||||
|
||||
@@ -1332,6 +1332,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
||||
case ServerOP_ItemStatus:
|
||||
case ServerOP_KickPlayer:
|
||||
case ServerOP_KillPlayer:
|
||||
case ServerOP_OOCMute:
|
||||
case ServerOP_OOZGroupMessage:
|
||||
case ServerOP_Petition:
|
||||
case ServerOP_RaidGroupSay:
|
||||
|
||||
+14
-19
@@ -4478,23 +4478,19 @@ uint32 Bot::CountBotItem(uint32 item_id) {
|
||||
return item_count;
|
||||
}
|
||||
|
||||
bool Bot::HasBotItem(uint32 item_id) {
|
||||
bool has_item = false;
|
||||
EQ::ItemInstance *inst = nullptr;
|
||||
int16 Bot::HasBotItem(uint32 item_id) {
|
||||
EQ::ItemInstance const *inst = nullptr;
|
||||
|
||||
for (uint16 slot_id = EQ::invslot::EQUIPMENT_BEGIN; slot_id <= EQ::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
inst = GetBotItem(slot_id);
|
||||
if (!inst || !inst->GetItem()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst->GetID() == item_id) {
|
||||
has_item = true;
|
||||
break;
|
||||
return slot_id;
|
||||
}
|
||||
}
|
||||
|
||||
return has_item;
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
void Bot::RemoveBotItem(uint32 item_id) {
|
||||
@@ -4616,17 +4612,17 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client*
|
||||
struct ClientTrade {
|
||||
ItemInstance* trade_item_instance;
|
||||
int16 from_client_slot;
|
||||
int16 to_bot_slot;
|
||||
int16 to_bot_slot = invslot::SLOT_INVALID;
|
||||
|
||||
ClientTrade(ItemInstance* item, int16 from) : trade_item_instance(item), from_client_slot(from), to_bot_slot(invslot::SLOT_INVALID) { }
|
||||
ClientTrade(ItemInstance* item, int16 from) : trade_item_instance(item), from_client_slot(from) { }
|
||||
};
|
||||
|
||||
struct ClientReturn {
|
||||
const ItemInstance* return_item_instance;
|
||||
ItemInstance* return_item_instance;
|
||||
int16 from_bot_slot;
|
||||
int16 to_client_slot;
|
||||
int16 to_client_slot = invslot::SLOT_INVALID;
|
||||
|
||||
ClientReturn(const ItemInstance* item, int16 from) : return_item_instance(item), from_bot_slot(from), to_client_slot(invslot::SLOT_INVALID) { }
|
||||
ClientReturn(ItemInstance* item, int16 from) : return_item_instance(item), from_bot_slot(from) { }
|
||||
};
|
||||
|
||||
static const int16 bot_equip_order[invslot::EQUIPMENT_COUNT] = {
|
||||
@@ -4906,7 +4902,7 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client*
|
||||
if (trade_instance->GetItem()->IsType2HWeapon()) {
|
||||
if (!melee_secondary) {
|
||||
melee_2h_weapon = true;
|
||||
auto equipped_secondary_weapon = m_inv[invslot::slotSecondary];
|
||||
auto equipped_secondary_weapon = GetBotItem(invslot::slotSecondary);
|
||||
if (equipped_secondary_weapon) {
|
||||
client_return.push_back(ClientReturn(equipped_secondary_weapon, invslot::slotSecondary));
|
||||
}
|
||||
@@ -4922,7 +4918,7 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client*
|
||||
!trade_instance->IsWeapon()
|
||||
) {
|
||||
melee_secondary = true;
|
||||
auto equipped_primary_weapon = m_inv[invslot::slotPrimary];
|
||||
auto equipped_primary_weapon = GetBotItem(invslot::slotPrimary);
|
||||
if (equipped_primary_weapon && equipped_primary_weapon->GetItem()->IsType2HWeapon()) {
|
||||
client_return.push_back(ClientReturn(equipped_primary_weapon, invslot::slotPrimary));
|
||||
}
|
||||
@@ -4937,7 +4933,7 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client*
|
||||
trade_iterator.to_bot_slot = index;
|
||||
|
||||
if (m_inv[index]) {
|
||||
client_return.push_back(ClientReturn(m_inv[index], index));
|
||||
client_return.push_back(ClientReturn(GetBotItem(index), index));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -5071,9 +5067,8 @@ void Bot::PerformTradeWithClient(int16 begin_slot_id, int16 end_slot_id, Client*
|
||||
client->DeleteItemInInventory(return_iterator.from_bot_slot);
|
||||
} else { // successful trade returns
|
||||
auto return_instance = m_inv.PopItem(return_iterator.from_bot_slot);
|
||||
//if (*return_instance != *return_iterator.return_item_instance) {
|
||||
|
||||
// // TODO: add logging
|
||||
//}
|
||||
|
||||
if (!database.botdb.DeleteItemBySlot(GetBotID(), return_iterator.from_bot_slot)) {
|
||||
OwnerMessage(
|
||||
@@ -9490,7 +9485,7 @@ void Bot::ListBotSpells(uint8 min_level)
|
||||
auto spell_count = 0;
|
||||
auto spell_number = 1;
|
||||
|
||||
for (const auto& s : (AIBot_spells.size() > AIBot_spells_enforced.size()) ? AIBot_spells : AIBot_spells_enforced) {
|
||||
for (const auto& s : (GetBotEnforceSpellSetting()) ? AIBot_spells_enforced : AIBot_spells) {
|
||||
auto b = bot_spell_settings.find(s.spellid);
|
||||
if (b == bot_spell_settings.end() && s.minlevel >= min_level) {
|
||||
bot_owner->Message(
|
||||
|
||||
+1
-1
@@ -720,7 +720,7 @@ public:
|
||||
uint32 CountBotItem(uint32 item_id);
|
||||
std::map<uint16, uint32> GetBotItemSlots();
|
||||
uint32 GetBotItemBySlot(uint16 slot_id);
|
||||
bool HasBotItem(uint32 item_id);
|
||||
int16 HasBotItem(uint32 item_id);
|
||||
void RemoveBotItem(uint32 item_id);
|
||||
uint32 GetTotalPlayTime();
|
||||
|
||||
|
||||
@@ -9320,7 +9320,7 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* inst = my_bot->GetBotItem(slot_id);
|
||||
auto* inst = my_bot->GetBotItem(slot_id);
|
||||
if (!inst) {
|
||||
std::string slot_message = "is";
|
||||
switch (slot_id) {
|
||||
|
||||
@@ -962,7 +962,10 @@ bool BotDatabase::SaveTimers(Bot* bot_inst)
|
||||
if (bot_timers[timer_index] <= Timer::GetCurrentTime())
|
||||
continue;
|
||||
|
||||
query = StringFormat("INSERT INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) VALUES ('%u', '%u', '%u')", bot_inst->GetBotID(), (timer_index + 1), bot_timers[timer_index]);
|
||||
query = fmt::format(
|
||||
"REPLACE INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) VALUES ('{}', '{}', '{}')",
|
||||
bot_inst->GetBotID(), (timer_index + 1), bot_timers[timer_index]
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
DeleteTimers(bot_inst->GetBotID());
|
||||
|
||||
@@ -2144,7 +2144,7 @@ void Client::Handle_OP_AdventureMerchantRequest(const EQApplicationPacket *app)
|
||||
theme = LDoNThemes::RUJ;
|
||||
} else if (item->LDoNTheme & LDoNThemeBits::MMCBit) {
|
||||
theme = LDoNThemes::MMC;
|
||||
} else if (item->LDoNTheme & LDoNThemeBits::RUJBit) {
|
||||
} else if (item->LDoNTheme & LDoNThemeBits::MIRBit) {
|
||||
theme = LDoNThemes::MIR;
|
||||
} else if (item->LDoNTheme & LDoNThemeBits::GUKBit) {
|
||||
theme = LDoNThemes::GUK;
|
||||
|
||||
@@ -116,7 +116,7 @@ void command_gearup(Client *c, const Seperator *sep)
|
||||
if (t->IsClient()) {
|
||||
has_item = t->CastToClient()->GetInv().HasItem(item_id, 1, invWhereWorn) != INVALID_INDEX;
|
||||
} else if (t->IsBot()) {
|
||||
has_item = t->CastToBot()->HasBotItem(item_id);
|
||||
has_item = t->CastToBot()->HasBotItem(item_id) != INVALID_INDEX;
|
||||
}
|
||||
|
||||
bool can_wear_item = false;
|
||||
|
||||
+19
-2
@@ -794,6 +794,23 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
|
||||
}
|
||||
}
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::ITEM_CREATION)) {
|
||||
auto e = PlayerEvent::ItemCreationEvent{};
|
||||
e.item_id = item->ID;
|
||||
e.item_name = item->Name;
|
||||
e.to_slot = to_slot;
|
||||
e.charges = charges;
|
||||
e.aug1 = aug1;
|
||||
e.aug2 = aug2;
|
||||
e.aug3 = aug3;
|
||||
e.aug4 = aug4;
|
||||
e.aug5 = aug5;
|
||||
e.aug6 = aug6;
|
||||
e.attuned = attuned;
|
||||
|
||||
RecordPlayerEventLog(PlayerEvent::ITEM_CREATION, e);
|
||||
}
|
||||
|
||||
// put item into inventory
|
||||
if (to_slot == EQ::invslot::slotCursor) {
|
||||
PushItemOnCursor(*inst);
|
||||
@@ -848,13 +865,13 @@ void Client::DropItem(int16 slot_id, bool recurse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string message = fmt::format(
|
||||
"Tried to drop an item on the ground that was no-drop! item_name [{}] item_id ({})",
|
||||
invalid_drop->GetItem()->Name,
|
||||
invalid_drop->GetItem()->ID
|
||||
);
|
||||
|
||||
|
||||
invalid_drop = nullptr;
|
||||
RecordPlayerEventLog(PlayerEvent::POSSIBLE_HACK, PlayerEvent::PossibleHackEvent{.message = message});
|
||||
GetInv().DeleteItem(slot_id);
|
||||
|
||||
+3
-3
@@ -65,8 +65,8 @@ Lua_Mob Lua_Bot::GetOwner() {
|
||||
return Lua_Mob(self->GetOwner());
|
||||
}
|
||||
|
||||
bool Lua_Bot::HasBotItem(uint32 item_id) {
|
||||
Lua_Safe_Call_Bool();
|
||||
int16 Lua_Bot::HasBotItem(uint32 item_id) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->HasBotItem(item_id);
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ luabind::scope lua_register_bot() {
|
||||
.def("GetRawItemAC", (int(Lua_Bot::*)(void))&Lua_Bot::GetRawItemAC)
|
||||
.def("GetSpellDamage", (int(Lua_Bot::*)(void))&Lua_Bot::GetSpellDamage)
|
||||
.def("HasAugmentEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasAugmentEquippedByID)
|
||||
.def("HasBotItem", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem)
|
||||
.def("HasBotItem", (int16(Lua_Bot::*)(uint32))&Lua_Bot::HasBotItem)
|
||||
.def("HasBotSpellEntry", (bool(Lua_Bot::*)(uint16)) & Lua_Bot::HasBotSpellEntry)
|
||||
.def("HasItemEquippedByID", (bool(Lua_Bot::*)(uint32))&Lua_Bot::HasItemEquippedByID)
|
||||
.def("IsGrouped", (bool(Lua_Bot::*)(void))&Lua_Bot::IsGrouped)
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public:
|
||||
uint32 GetBotItemIDBySlot(uint16 slot_id);
|
||||
int GetExpansionBitmask();
|
||||
Lua_Mob GetOwner();
|
||||
bool HasBotItem(uint32 item_id);
|
||||
int16 HasBotItem(uint32 item_id);
|
||||
void OwnerMessage(std::string message);
|
||||
bool ReloadBotDataBuckets();
|
||||
bool ReloadBotOwnerDataBuckets();
|
||||
|
||||
+29
-6
@@ -103,6 +103,7 @@ Mob::Mob(
|
||||
attack_dw_timer(2000),
|
||||
ranged_timer(2000),
|
||||
hp_regen_per_second_timer(1000),
|
||||
m_z_clip_check_timer(1000),
|
||||
tic_timer(6000),
|
||||
mana_timer(2000),
|
||||
spellend_timer(0),
|
||||
@@ -2374,14 +2375,14 @@ void Mob::ShowBuffList(Client* client) {
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::GMMove(float x, float y, float z, float heading) {
|
||||
void Mob::GMMove(float x, float y, float z, float heading, bool save_guard_spot) {
|
||||
m_Position.x = x;
|
||||
m_Position.y = y;
|
||||
m_Position.z = z;
|
||||
SetHeading(heading);
|
||||
mMovementManager->SendCommandToClients(this, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
|
||||
|
||||
if (IsNPC()) {
|
||||
if (IsNPC() && save_guard_spot) {
|
||||
CastToNPC()->SaveGuardSpot(glm::vec4(x, y, z, heading));
|
||||
}
|
||||
}
|
||||
@@ -3714,10 +3715,32 @@ bool Mob::HateSummon() {
|
||||
// probably should be like half melee range, but we can't get melee range nicely because reasons :)
|
||||
new_pos = target->TryMoveAlong(new_pos, 5.0f, angle);
|
||||
|
||||
if (target->IsClient())
|
||||
target->CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), new_pos.x, new_pos.y, new_pos.z, new_pos.w, 0, SummonPC);
|
||||
else
|
||||
target->GMMove(new_pos.x, new_pos.y, new_pos.z, new_pos.w);
|
||||
if (target->IsClient()) {
|
||||
target->CastToClient()->MovePC(
|
||||
zone->GetZoneID(),
|
||||
zone->GetInstanceID(),
|
||||
new_pos.x,
|
||||
new_pos.y,
|
||||
new_pos.z,
|
||||
new_pos.w,
|
||||
0,
|
||||
SummonPC
|
||||
);
|
||||
} else {
|
||||
bool target_is_client_pet = (
|
||||
target->IsPet() &&
|
||||
target->IsPetOwnerClient()
|
||||
);
|
||||
bool set_new_guard_spot = !(IsNPC() && target_is_client_pet);
|
||||
|
||||
target->GMMove(
|
||||
new_pos.x,
|
||||
new_pos.y,
|
||||
new_pos.z,
|
||||
new_pos.w,
|
||||
set_new_guard_spot
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if(summon_level == 2) {
|
||||
|
||||
+3
-1
@@ -686,7 +686,7 @@ public:
|
||||
float GetMovespeed() const { return IsRunning() ? GetRunspeed() : GetWalkspeed(); }
|
||||
bool IsRunning() const { return m_is_running; }
|
||||
void SetRunning(bool val) { m_is_running = val; }
|
||||
virtual void GMMove(float x, float y, float z, float heading = 0.01);
|
||||
virtual void GMMove(float x, float y, float z, float heading = 0.01, bool save_guard_spot = true);
|
||||
virtual void GMMove(const glm::vec4 &position);
|
||||
void SetDelta(const glm::vec4& delta);
|
||||
void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu);
|
||||
@@ -1427,6 +1427,8 @@ protected:
|
||||
int _GetRunSpeed() const;
|
||||
int _GetFearSpeed() const;
|
||||
|
||||
Timer m_z_clip_check_timer;
|
||||
|
||||
virtual bool AI_EngagedCastCheck() { return(false); }
|
||||
virtual bool AI_PursueCastCheck() { return(false); }
|
||||
virtual bool AI_IdleCastCheck() { return(false); }
|
||||
|
||||
@@ -1071,6 +1071,14 @@ void Mob::AI_Process() {
|
||||
}
|
||||
|
||||
if (engaged) {
|
||||
if (IsNPC() && m_z_clip_check_timer.Check()) {
|
||||
auto t = GetTarget();
|
||||
if (t && DistanceNoZ(GetPosition(), t->GetPosition()) < 75 && std::abs(GetPosition().z - t->GetPosition().z) > 15 && !CheckLosFN(t)) {
|
||||
GMMove(t->GetPosition().x, t->GetPosition().y, t->GetPosition().z, t->GetPosition().w);
|
||||
FaceTarget(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(m_PlayerState & static_cast<uint32>(PlayerState::Aggressive)))
|
||||
SendAddPlayerState(PlayerState::Aggressive);
|
||||
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ uint32 Perl_Bot_CountBotItem(Bot* self, uint32 item_id)
|
||||
return self->CountBotItem(item_id);
|
||||
}
|
||||
|
||||
bool Perl_Bot_HasBotItem(Bot* self, uint32 item_id)
|
||||
int16 Perl_Bot_HasBotItem(Bot* self, uint32 item_id)
|
||||
{
|
||||
return self->HasBotItem(item_id);
|
||||
}
|
||||
|
||||
@@ -2755,6 +2755,11 @@ void Perl_Client_Signal(Client* self, int signal_id)
|
||||
self->Signal(signal_id);
|
||||
}
|
||||
|
||||
void Perl_Client_SignalClient(Client* self, int signal_id) // @categories Script Utility
|
||||
{
|
||||
self->Signal(signal_id);
|
||||
}
|
||||
|
||||
std::string Perl_Client_GetGuildPublicNote(Client* self)
|
||||
{
|
||||
return self->GetGuildPublicNote();
|
||||
@@ -3362,6 +3367,7 @@ void perl_register_client()
|
||||
package.add("SetTitleSuffix", (void(*)(Client*, std::string, bool))&Perl_Client_SetTitleSuffix);
|
||||
package.add("SetZoneFlag", &Perl_Client_SetZoneFlag);
|
||||
package.add("Signal", &Perl_Client_Signal);
|
||||
package.add("SignalClient", &Perl_Client_SignalClient);
|
||||
package.add("SilentMessage", &Perl_Client_SilentMessage);
|
||||
package.add("Sit", &Perl_Client_Sit);
|
||||
package.add("SlotConvert2", &Perl_Client_SlotConvert2);
|
||||
|
||||
@@ -584,6 +584,16 @@ bool Perl_NPC_GetCombatState(NPC* self) // @categories Script Utility
|
||||
return self->GetCombatEvent();
|
||||
}
|
||||
|
||||
void Perl_NPC_SetSimpleRoamBox(NPC* self, float box_size) // @categories Script Utility
|
||||
{
|
||||
self->SetSimpleRoamBox(box_size);
|
||||
}
|
||||
|
||||
void Perl_NPC_SetSimpleRoamBox(NPC* self, float box_size, float move_distance) // @categories Script Utility
|
||||
{
|
||||
self->SetSimpleRoamBox(box_size, move_distance);
|
||||
}
|
||||
|
||||
void Perl_NPC_SetSimpleRoamBox(NPC* self, float box_size, float move_distance, int move_delay) // @categories Script Utility
|
||||
{
|
||||
self->SetSimpleRoamBox(box_size, move_distance, move_delay);
|
||||
|
||||
+13
-15
@@ -781,7 +781,19 @@ float Mob::GetFixedZ(const glm::vec3 &destination, int32 z_find_offset) {
|
||||
return new_z;
|
||||
}
|
||||
|
||||
new_z = FindDestGroundZ(destination, (-GetZOffset() / 2));
|
||||
new_z = FindDestGroundZ(destination, ((-GetZOffset() / 2) + z_find_offset));
|
||||
|
||||
if (RuleB(Map, MobPathingVisualDebug)) {
|
||||
DrawDebugCoordinateNode(
|
||||
fmt::format("{} search z node", GetCleanName()),
|
||||
glm::vec4{
|
||||
m_Position.x,
|
||||
m_Position.y,
|
||||
((-GetZOffset() / 2) + z_find_offset),
|
||||
m_Position.w
|
||||
}
|
||||
);
|
||||
}
|
||||
if (new_z != BEST_Z_INVALID) {
|
||||
new_z += GetZOffset();
|
||||
|
||||
@@ -790,20 +802,6 @@ float Mob::GetFixedZ(const glm::vec3 &destination, int32 z_find_offset) {
|
||||
}
|
||||
}
|
||||
|
||||
// prevent ceiling clipping
|
||||
// if client is close in distance (not counting Z) and we clipped up into a ceiling
|
||||
// this helps us snap back down (or up) if it were to happen
|
||||
// other fixes were put in place to prevent clipping into the ceiling to begin with
|
||||
if (std::abs(new_z - m_Position.z) > 15) {
|
||||
LogFixZ("TRIGGER clipping detection");
|
||||
auto t = GetTarget();
|
||||
if (t && DistanceNoZ(GetPosition(), t->GetPosition()) < 20) {
|
||||
new_z = FindDestGroundZ(t->GetPosition(), -t->GetZOffset());
|
||||
new_z += GetZOffset();
|
||||
GMMove(t->GetPosition().x, t->GetPosition().y, new_z, t->GetPosition().w);
|
||||
}
|
||||
}
|
||||
|
||||
auto duration = timer.elapsed();
|
||||
|
||||
LogFixZ("[{}] returned [{}] at [{}] [{}] [{}] - Took [{}]",
|
||||
|
||||
Reference in New Issue
Block a user