mirror of
https://github.com/EQEmu/Server.git
synced 2026-01-08 23:53:52 +00:00
Added server handler for OP_CharInventory .. Added rule-based option to split BulkSendInventory into parent item packets
This commit is contained in:
parent
a26227f258
commit
7fb3146a77
@ -726,6 +726,7 @@ RULE_BOOL(Inventory, EnforceAugmentWear, true, "Forces augment wear slot validat
|
||||
RULE_BOOL(Inventory, DeleteTransformationMold, true, "False if you want mold to last forever")
|
||||
RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false, "Weapons can use any weapon transformation")
|
||||
RULE_BOOL(Inventory, TransformSummonedBags, false, "Transforms summoned bags into disenchanted ones instead of deleting")
|
||||
RULE_BOOL(Inventory, BulkSendEnMasse, false, "Sends player 'Enter World' inventory as one massive packet (true = normal behavior)")
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Client)
|
||||
|
||||
@ -340,6 +340,9 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
temp_pvp = false;
|
||||
is_client_moving = false;
|
||||
|
||||
m_op_charinventory_sent = 0;
|
||||
m_op_charinventory_received = 0;
|
||||
|
||||
/**
|
||||
* GM
|
||||
*/
|
||||
|
||||
@ -721,6 +721,11 @@ public:
|
||||
|
||||
void OnDisconnect(bool hard_disconnect);
|
||||
|
||||
void IncrementOPCharInventorySent(size_t count = 1) { m_op_charinventory_sent += count; }
|
||||
void IncrementOPCharInventoryReceived(size_t count = 1) { m_op_charinventory_received += count; }
|
||||
size_t GetOpCharInventorySentCount() { return m_op_charinventory_sent; }
|
||||
size_t GetOpCharInventoryReceivedCount() { return m_op_charinventory_received; }
|
||||
|
||||
uint16 GetSkillPoints() { return m_pp.points;}
|
||||
void SetSkillPoints(int inp) { m_pp.points = inp;}
|
||||
|
||||
@ -1626,6 +1631,9 @@ private:
|
||||
|
||||
int client_max_level;
|
||||
|
||||
size_t m_op_charinventory_sent;
|
||||
size_t m_op_charinventory_received;
|
||||
|
||||
#ifdef BOTS
|
||||
|
||||
public:
|
||||
|
||||
@ -89,6 +89,7 @@ void MapOpcodes()
|
||||
// connecting opcode handler assignments:
|
||||
ConnectingOpcodes[OP_ApproveZone] = &Client::Handle_Connect_OP_ApproveZone;
|
||||
ConnectingOpcodes[OP_BlockedBuffs] = &Client::Handle_OP_BlockedBuffs;
|
||||
ConnectingOpcodes[OP_CharInventory] = &Client::Handle_Connect_OP_CharInventory;
|
||||
ConnectingOpcodes[OP_ClientError] = &Client::Handle_Connect_OP_ClientError;
|
||||
ConnectingOpcodes[OP_ClientReady] = &Client::Handle_Connect_OP_ClientReady;
|
||||
ConnectingOpcodes[OP_ClientUpdate] = &Client::Handle_Connect_OP_ClientUpdate;
|
||||
@ -932,6 +933,41 @@ void Client::Handle_Connect_OP_ApproveZone(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_Connect_OP_CharInventory(const EQApplicationPacket* app)
|
||||
{
|
||||
if (ClientVersionBit() & EQEmu::versions::maskRoFAndLater) {
|
||||
|
||||
IncrementOPCharInventoryReceived();
|
||||
if (GetOpCharInventorySentCount() == GetOpCharInventoryReceivedCount()) {
|
||||
|
||||
/*
|
||||
Weather Packet
|
||||
This shouldent be moved, this seems to be what the client
|
||||
uses to advance to the next state (sending ReqNewZone)
|
||||
*/
|
||||
auto outapp = new EQApplicationPacket(OP_Weather, 12);
|
||||
Weather_Struct* ws = (Weather_Struct*)outapp->pBuffer;
|
||||
ws->val1 = 0x000000FF;
|
||||
if (zone->zone_weather == 1) {
|
||||
ws->type = 0x31; // Rain
|
||||
}
|
||||
if (zone->zone_weather == 2) {
|
||||
|
||||
outapp->pBuffer[8] = 0x01;
|
||||
ws->type = 0x02;
|
||||
}
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
Handle_Connect_OP_ReqNewZone(nullptr);
|
||||
SetAttackTimer();
|
||||
conn_state = ZoneInfoSent;
|
||||
zoneinpacket_timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Handle_Connect_OP_ClientError(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size != sizeof(ClientError_Struct)) {
|
||||
@ -1655,15 +1691,20 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
this is not quite where live sends inventory, they do it after tribute
|
||||
*/
|
||||
if (loaditems) { /* Dont load if a length error occurs */
|
||||
if (admin >= minStatusToBeGM)
|
||||
|
||||
if (admin >= minStatusToBeGM) {
|
||||
m_inv.SetGMInventory(true); // set to true to allow expansion-restricted packets through
|
||||
}
|
||||
|
||||
BulkSendInventoryItems();
|
||||
|
||||
/* Send stuff on the cursor which isnt sent in bulk */
|
||||
for (auto iter = m_inv.cursor_cbegin(); iter != m_inv.cursor_cend(); ++iter) {
|
||||
|
||||
/* First item cursor is sent in bulk inventory packet */
|
||||
if (iter == m_inv.cursor_cbegin())
|
||||
if (iter == m_inv.cursor_cbegin()) {
|
||||
continue;
|
||||
}
|
||||
const EQEmu::ItemInstance *inst = *iter;
|
||||
SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketLimbo);
|
||||
}
|
||||
@ -1692,31 +1733,31 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
/*
|
||||
Weather Packet
|
||||
This shouldent be moved, this seems to be what the client
|
||||
uses to advance to the next state (sending ReqNewZone)
|
||||
*/
|
||||
outapp = new EQApplicationPacket(OP_Weather, 12);
|
||||
Weather_Struct *ws = (Weather_Struct *)outapp->pBuffer;
|
||||
ws->val1 = 0x000000FF;
|
||||
if (zone->zone_weather == 1) { ws->type = 0x31; } // Rain
|
||||
if (zone->zone_weather == 2) {
|
||||
outapp->pBuffer[8] = 0x01;
|
||||
ws->type = 0x02;
|
||||
}
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
if (ClientVersionBit() & EQEmu::versions::maskUFAndEarlier) { // RoF+ moved to Client::Handle_Connect_OP_CharInventory(...)
|
||||
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) {
|
||||
Handle_Connect_OP_ReqNewZone(nullptr);
|
||||
}
|
||||
/*
|
||||
Weather Packet
|
||||
This shouldent be moved, this seems to be what the client
|
||||
uses to advance to the next state (sending ReqNewZone)
|
||||
*/
|
||||
outapp = new EQApplicationPacket(OP_Weather, 12);
|
||||
Weather_Struct* ws = (Weather_Struct*)outapp->pBuffer;
|
||||
ws->val1 = 0x000000FF;
|
||||
if (zone->zone_weather == 1) {
|
||||
ws->type = 0x31; // Rain
|
||||
}
|
||||
if (zone->zone_weather == 2) {
|
||||
outapp->pBuffer[8] = 0x01;
|
||||
ws->type = 0x02;
|
||||
}
|
||||
outapp->priority = 6;
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
SetAttackTimer();
|
||||
conn_state = ZoneInfoSent;
|
||||
zoneinpacket_timer.Start();
|
||||
return;
|
||||
SetAttackTimer();
|
||||
conn_state = ZoneInfoSent;
|
||||
zoneinpacket_timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
// connected opcode handlers
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/* Connecting OpCode Handlers */
|
||||
void Handle_Connect_0x3e33(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ApproveZone(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_CharInventory(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientError(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientReady(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientUpdate(const EQApplicationPacket *app);
|
||||
|
||||
@ -731,83 +731,185 @@ void Client::OnDisconnect(bool hard_disconnect) {
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
// Sends the client complete inventory used in character login
|
||||
// Sends the client complete inventory used in character login (enter world/zoning)
|
||||
void Client::BulkSendInventoryItems()
|
||||
{
|
||||
// LINKDEAD TRADE ITEMS
|
||||
// Move trade slot items back into normal inventory..need them there now for the proceeding validity checks
|
||||
for (int16 slot_id = EQEmu::invslot::TRADE_BEGIN; slot_id <= EQEmu::invslot::TRADE_END; slot_id++) {
|
||||
// Move any residual trade slot items back into normal inventory..need them there now for the proceeding validity checks
|
||||
for (int16 slot_id = EQEmu::invslot::TRADE_BEGIN; slot_id <= EQEmu::invslot::TRADE_END; ++slot_id) {
|
||||
|
||||
EQEmu::ItemInstance* inst = m_inv.PopItem(slot_id);
|
||||
if(inst) {
|
||||
bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false;
|
||||
|
||||
bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow);
|
||||
int16 free_slot_id = m_inv.FindFreeSlot(inst->IsClassBag(), true, inst->GetItem()->Size, is_arrow);
|
||||
LogInventory("Incomplete Trade Transaction: Moving [{}] from slot [{}] to [{}]", inst->GetItem()->Name, slot_id, free_slot_id);
|
||||
LogInventory(
|
||||
"Incomplete Trade Transaction: Moving [{}] from slot [{}] to [{}]",
|
||||
inst->GetItem()->Name,
|
||||
slot_id,
|
||||
free_slot_id
|
||||
);
|
||||
PutItemInInventory(free_slot_id, *inst, false);
|
||||
database.SaveInventory(character_id, nullptr, slot_id);
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
|
||||
bool deletenorent = database.NoRentExpired(GetName());
|
||||
if (deletenorent) { //client was offline for more than 30 minutes, delete no rent items
|
||||
if (RuleB(Inventory, TransformSummonedBags))
|
||||
// Client was offline for more than 30 minutes, delete no rent items
|
||||
bool delete_no_rent = database.NoRentExpired(GetName());
|
||||
if (delete_no_rent) {
|
||||
|
||||
if (RuleB(Inventory, TransformSummonedBags)) {
|
||||
DisenchantSummonedBags(false);
|
||||
}
|
||||
RemoveNoRent(false);
|
||||
}
|
||||
|
||||
RemoveDuplicateLore(false);
|
||||
MoveSlotNotAllowed(false);
|
||||
|
||||
EQEmu::OutBuffer ob;
|
||||
EQEmu::OutBuffer::pos_type last_pos = ob.tellp();
|
||||
if (RuleB(Inventory, BulkSendEnMasse)) { // Default behavior
|
||||
|
||||
// Possessions items
|
||||
for (int16 slot_id = EQEmu::invslot::POSSESSIONS_BEGIN; slot_id <= EQEmu::invslot::POSSESSIONS_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
EQEmu::OutBuffer ob;
|
||||
EQEmu::OutBuffer::pos_type last_pos = ob.tellp();
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
for (int16 slot_id = EQEmu::invslot::POSSESSIONS_BEGIN; slot_id <= EQEmu::invslot::POSSESSIONS_END; ++slot_id) {
|
||||
|
||||
if (ob.tellp() == last_pos)
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
if (ob.tellp() == last_pos) {
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
}
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
for (int16 slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
|
||||
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
if (ob.tellp() == last_pos) {
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
}
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
for (int16 slot_id = EQEmu::invslot::SHARED_BANK_BEGIN; slot_id <= EQEmu::invslot::SHARED_BANK_END; ++slot_id) {
|
||||
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
if (ob.tellp() == last_pos) {
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
}
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_CharInventory);
|
||||
outapp->size = ob.size();
|
||||
outapp->pBuffer = ob.detach();
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (ClientVersionBit() & EQEmu::versions::maskRoFAndLater) {
|
||||
IncrementOPCharInventorySent();
|
||||
}
|
||||
}
|
||||
else { // Specialized behavior
|
||||
|
||||
// Bank items
|
||||
for (int16 slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
for (int16 slot_id = EQEmu::invslot::POSSESSIONS_BEGIN; slot_id <= EQEmu::invslot::POSSESSIONS_END; ++slot_id) {
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ob.tellp() == last_pos)
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
EQEmu::OutBuffer ob;
|
||||
EQEmu::OutBuffer::pos_type last_pos = ob.tellp();
|
||||
|
||||
last_pos = ob.tellp();
|
||||
inst->Serialize(ob, slot_id);
|
||||
if (ob.tellp() == last_pos) {
|
||||
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_CharInventory);
|
||||
outapp->size = ob.size();
|
||||
outapp->pBuffer = ob.detach();
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (ClientVersionBit() & EQEmu::versions::maskRoFAndLater) {
|
||||
IncrementOPCharInventorySent();
|
||||
}
|
||||
}
|
||||
|
||||
for (int16 slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
|
||||
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EQEmu::OutBuffer ob;
|
||||
EQEmu::OutBuffer::pos_type last_pos = ob.tellp();
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
if (ob.tellp() == last_pos) {
|
||||
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_CharInventory);
|
||||
outapp->size = ob.size();
|
||||
outapp->pBuffer = ob.detach();
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (ClientVersionBit() & EQEmu::versions::maskRoFAndLater) {
|
||||
IncrementOPCharInventorySent();
|
||||
}
|
||||
}
|
||||
|
||||
for (int16 slot_id = EQEmu::invslot::SHARED_BANK_BEGIN; slot_id <= EQEmu::invslot::SHARED_BANK_END; ++slot_id) {
|
||||
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EQEmu::OutBuffer ob;
|
||||
EQEmu::OutBuffer::pos_type last_pos = ob.tellp();
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
if (ob.tellp() == last_pos) {
|
||||
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_CharInventory);
|
||||
outapp->size = ob.size();
|
||||
outapp->pBuffer = ob.detach();
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
if (ClientVersionBit() & EQEmu::versions::maskRoFAndLater) {
|
||||
IncrementOPCharInventorySent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SharedBank items
|
||||
for (int16 slot_id = EQEmu::invslot::SHARED_BANK_BEGIN; slot_id <= EQEmu::invslot::SHARED_BANK_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
inst->Serialize(ob, slot_id);
|
||||
|
||||
if (ob.tellp() == last_pos)
|
||||
LogInventory("Serialization failed on item slot [{}] during BulkSendInventoryItems. Item skipped", slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_CharInventory);
|
||||
outapp->size = ob.size();
|
||||
outapp->pBuffer = ob.detach();
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user