Uleat |
10-28-2012 03:26 PM |
THIS IS A PROTOTYPE PATCH. DO NOT USE FOR LIVE SERVERS!
Ok..this is an evolving piece of work and is probably in the ALPHA PATCH state..but don't expect any miracles until it's posted as a BETA PATCH.
(' Why does he keep posting this crap, especially when it runs like #@!%??' - Well, if I, or my computer, were to die permanently, someone would have a
place to pick up, should they wish to. Plus, it let's me get feedback on concepts and implementations.)
I was having issues consistently clearing the cursor when it had more than one or two items. So, I wound up implementing a timer-based callback to ensure
that the client had enough time to 'pop' the next item in its cursor list. (I tried a 'for' loop, but the count value got to 100k with no effect..probably because the
thread was busy counting and couldn't process the SendItemPacket requests...)
'ResyncInvCallBackDelay' is critical to clearing the client cursor properly. This may need some tweaking on public servers.
This iteration does update bank items for occupied slots, but does not delete unoccupied ones due to reasons discussed on the CSD thread. (I'm trying to
avoid 'spamming' the client, so this behavior will remain in effect until I find another solution or give up searching.)
As it stands, it does not trigger any messages that are not intentional.
Callbacks are limited to 3 at the moment and the next concurrent one will Kick() the player. (Currently, once the process is beyond the callback phase, the
requests back up and no warning messages are given. This needs tweaking.)
Due to client update restrictions and untested behavior, these slot ranges are not currently activated: Tribute, Trader, Trader Bag Slots, and World Container.
I've modified some of my pre-existing changes, as well as other procedures that were causing issues when a swapitem occurred with a pre-existing CSD.
If someone could verify these for me:
-Titanium Bank Slots: (Bank: 2000 - 2015, Bank Bags: 2031 - 2190)
-SoF+ Bank Slots: (Bank: 2000 - 2015, Bank Bags: 2031 - 2270)
I'm not asking for anyone to critic the actual ResyncInv() procedures, but if someone could look at the way that I implemented the timer to check for issues
I'm ignorant to, I'd appreciate it. (It does work as it is coded.)
Thanks!
[ResyncInv.patch] (9 files affected, 506 lines)
Code:
Index: common/Item.cpp
===================================================================
--- common/Item.cpp (revision 2241)
+++ common/Item.cpp (working copy)
@@ -668,22 +668,20 @@
}
// Swap items in inventory
-void Inventory::SwapItem(sint16 slot_a, sint16 slot_b)
-{
- // Temp holding area for a
+bool Inventory::SwapItem(sint16 slot_a, sint16 slot_b)
+{ // Modified to fail all item swaps into illegal slots..failure will trigger a resyncinv -U
+
+ // Temp holding areas for a & b
ItemInst* inst_a = GetItem(slot_a);
+ ItemInst* inst_b = GetItem(slot_b);
- if(inst_a)
- {
- if(!inst_a->IsSlotAllowed(slot_b))
- return;
- }
+ if(inst_a) { if(!inst_a->IsSlotAllowed(slot_b)) { return false; } }
+ if(inst_b) { if(!inst_b->IsSlotAllowed(slot_a)) { return false; } }
- // Copy b->a
- _PutItem(slot_a, GetItem(slot_b));
-
- // Copy a->b
- _PutItem(slot_b, inst_a);
+ _PutItem(slot_a, inst_b); // Copy b->a
+ _PutItem(slot_b, inst_a); // Copy a->b
+
+ return true;
}
// Checks that user has at least 'quantity' number of items in a given inventory slot
Index: common/Item.h
===================================================================
--- common/Item.h (revision 2241)
+++ common/Item.h (working copy)
@@ -144,7 +144,8 @@
inline iter_queue cursor_begin() { return m_cursor.begin(); }
inline iter_queue cursor_end() { return m_cursor.end(); }
inline bool CursorEmpty() { return (m_cursor.size() == 0); }
-
+ inline int CursorSize() { return m_cursor.size(); }
+
// Retrieve a read-only item from inventory
inline const ItemInst* operator[](sint16 slot_id) const { return GetItem(slot_id); }
@@ -155,7 +156,7 @@
sint16 PushCursor(const ItemInst& inst);
// Swap items in inventory
- void SwapItem(sint16 slot_a, sint16 slot_b);
+ bool SwapItem(sint16 slot_a, sint16 slot_b);
// Remove item from inventory
bool DeleteItem(sint16 slot_id, uint8 quantity=0);
Index: zone/client.cpp
===================================================================
--- zone/client.cpp (revision 2241)
+++ zone/client.cpp (working copy)
@@ -324,6 +324,11 @@
}
MaxXTargets = 5;
XTargetAutoAddHaters = true;
+
+ /* ResyncInv Stuff - Constructor */
+ ResyncInvCallBackTimer = new Timer(0);
+ ResyncInvCount = 0;
+ ResyncInvCursorCount = 0;
}
Client::~Client() {
@@ -406,6 +411,8 @@
safe_delete(taskstate);
safe_delete(KarmaUpdateTimer);
safe_delete(GlobalChatLimiterTimer);
+ /* ResyncInv Stuff - Deconstructor */
+ safe_delete(ResyncInvCallBackTimer);
safe_delete(qGlobals);
safe_delete(adventure_request_timer);
safe_delete(adventure_create_timer);
Index: zone/client.h
===================================================================
--- zone/client.h (revision 2241)
+++ zone/client.h (working copy)
@@ -760,6 +760,8 @@
bool PushItemOnCursor(const ItemInst& inst, bool client_update = false);
void DeleteItemInInventory(sint16 slot_id, sint8 quantity = 0, bool client_update = false, bool update_db = true);
bool SwapItem(MoveItem_Struct* move_in);
+ /* ResyncInv Stuff - Delegates (Public:) */
+ void ResyncInventory(bool server_call = true, bool timer_callback = false);
void PutLootInInventory(sint16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data = 0);
bool AutoPutLootInInventory(ItemInst& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
void SummonItem(uint32 item_id, sint16 charges = 0, uint32 aug1=0, uint32 aug2=0, uint32 aug3=0, uint32 aug4=0, uint32 aug5=0, bool attuned=false, uint16 to_slot=SLOT_CURSOR);
@@ -1396,6 +1398,16 @@
struct XTarget_Struct XTargets[XTARGET_HARDCAP];
+ /* ResyncInv Stuff - Deletegates (Private:) */
+ Timer *ResyncInvCallBackTimer;
+ void ResyncInvCallBack();
+ void ResyncInvProcSlots(sint16 slot_begin, sint16 slot_end, const ItemInst* token_inst = NULL, bool update_null = true, bool reg_delete = true, bool chk_parent = false);
+ void ResyncInvClDelItem(sint16 slot_id, const ItemInst* token_inst = NULL, bool reg_delete = true);
+ int8 ResyncInvCount;
+ int8 ResyncInvCursorCount;
+ int32 ResyncInvCallBackDelay;
+#define CURSOR_LIMIT 37
+
};
#include "parser.h"
Index: zone/client_packet.cpp
===================================================================
--- zone/client_packet.cpp (revision 2241)
+++ zone/client_packet.cpp (working copy)
@@ -3306,63 +3306,59 @@
casting_spell_id);
database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
safe_delete_array(detect);
+ // This Kick() can be deleted unless an automatic ban is in use. (Unremark the code below) -U
Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots
+ //Message(13, "Warning: You have attempted an item move while casting a spell - this action is not allowed!");
+ //ResyncInventory();
return;
}
}
- // Added checks for illegal bagslot swaps..should help with certain cheats (currently checks personal and cursor bag slots.)
- // - If a player has used an illegal inventory cheat, they can become bugged at some point (especially concerning lore items.)
- //* Start
+ // Illegal bagslot useage checks. Currently, user only receives a message if this check is triggered. -U
bool mi_hack = false;
if (mi->from_slot >= 251 && mi->from_slot <= 340) {
- if (mi->from_slot > 330)
- mi_hack = true; // why are we moving from a cursor bagslot when you can't open it?
+ if (mi->from_slot > 330) { mi_hack = true; } // illegal move FROM cursor bagslot
else {
- sint16 from_invslot = Inventory::CalcSlotId(mi->from_slot);
- const ItemInst *from_invslotitem = GetInv().GetItem(from_invslot);
+ sint16 from_parent = m_inv.CalcSlotId(mi->from_slot);
- if (!from_invslotitem) // trying to move from bag slots when parent inventory slot is empty
- mi_hack = true;
- else if (from_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
- if ((Inventory::CalcBagIdx(mi->from_slot) + 1) > from_invslotitem->GetItem()->BagSlots)
- mi_hack = true; // trying to move from slots beyond parent container size
- }
- else // trying to move from bag slots when inventory slot item is not a container
- mi_hack = true;
+ if (!m_inv[from_parent]) { mi_hack = true; } // illegal move FROM empty parent slot
+ else if (m_inv[from_parent]->GetItem()->ItemClass != 1) { mi_hack = true; } // illegal move FROM non-container parent
+ // illegal move FROM slot beyond parent container size
+ else if((m_inv.CalcBagIdx(mi->from_slot) + 1) > m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
if (mi->to_slot >= 251 && mi->to_slot <= 340) {
- if (mi->to_slot > 330)
- mi_hack = true; // why are we moving to a cursor bagslot when you can't open it?
- else {
- sint16 to_invslot = Inventory::CalcSlotId(mi->to_slot);
- const ItemInst *to_invslotitem = GetInv().GetItem(to_invslot);
+ if (mi->to_slot > 330) { mi_hack = true; } // illegal move TO cursor bagslot
+ else {
+ sint16 to_parent = m_inv.CalcSlotId(mi->to_slot);
- if (!to_invslotitem) // trying to move into bag slots when parent inventory slot is empty
- mi_hack = true;
- else if (to_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
- if ((Inventory::CalcBagIdx(mi->to_slot) + 1) > to_invslotitem->GetItem()->BagSlots)
- mi_hack = true; // trying to move into slots beyond parent container size
- }
- else // trying to move into bag slots when inventory slot item is not a container
- mi_hack = true;
+ if (!m_inv[to_parent]) { mi_hack = true; } // illegal move TO empty parent slot
+ else if (m_inv[to_parent]->GetItem()->ItemClass != 1) { mi_hack = true; } // illegal move TO non-container parent
+ // illegal move TO slot beyond parent container size
+ else if((m_inv.CalcBagIdx(mi->to_slot) + 1) > m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
- if (mi_hack) { // a CSD can also cause this condition, but more likely the use of a cheat
- Message(13, "Hack detected: Illegal use of inventory bag slots!");
- // TODO: Decide whether to log player as hacker - currently has no teeth...
- // Kick();
- // return;
- } // End */
+ if (mi_hack) { Message(15, "Caution: Illegal use of inaccessable inventory bag slots!"); }
- // if this swapitem call fails, then the server and client could be de-sync'd
- if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
- Message(0, "Client SwapItem request failure - verify inventory integrity.");
+ if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
+ Message(13, "Client OP_MoveItem request error!");
+ ResyncInventory();
+
+ if(mi_hack) {
+ Message(15, "Caution: If you use 3rd-party software to manipulate slots,");
+ Message(15, "this action may or may not correct problems in these slots.");
+ Message(15, "To ensure this issue is corrected, you must zone or re-log.");
+ }
+ }
+ // Test code - deleteable
+ //Message(5, "movein->from_slot: %i", mi->from_slot);
+ //Message(5, "movein->to_slot: %i", mi->to_slot);
+ //Message(5, "movein->number_in_stack: %i", mi->number_in_stack);
+
return;
}
Index: zone/client_process.cpp
===================================================================
--- zone/client_process.cpp (revision 2241)
+++ zone/client_process.cpp (working copy)
@@ -746,6 +746,9 @@
Message(0,"Your enemies have forgotten you!");
}
+ /* ResyncInv Stuff - Timer Check */
+ if(ResyncInvCallBackTimer && ResyncInvCallBackTimer->Enabled() && ResyncInvCallBackTimer->Check(false)) { ResyncInvCallBack(); }
+
return ret;
}
Index: zone/command.cpp
===================================================================
--- zone/command.cpp (revision 2241)
+++ zone/command.cpp (working copy)
@@ -459,7 +459,8 @@
command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) ||
command_add("printquestitems","Returns available quest items for multiquesting currently on the target npc.",200,command_printquestitems) ||
command_add("clearquestitems","Clears quest items for multiquesting currently on the target npc.",200,command_clearquestitems) ||
- command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", 250, command_zopp)
+ command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", 250, command_zopp) ||
+ command_add("resyncinv", "Client inventory resyncronation command. Use when you suspect an issue with your inventory.", 0, command_resyncinv)
)
{
command_deinit();
@@ -11701,7 +11702,15 @@
ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges);
c->SendItemPacket(slotid, FakeItemInst, packettype);
- c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.", packettype==ItemPacketTrade?"Trade":"Summon", FakeItem->Name, itemid, charges, abs(charges==1)?"charge":"charges", slotid);
+ c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u), quantity: %i, to slot %i.", packettype==ItemPacketTrade?"Trade":"Summon", FakeItem->Name, itemid, charges, slotid);
safe_delete(FakeItemInst);
}
}
+
+void command_resyncinv(Client *c, const Seperator *sep) {
+
+ if(!c) { return; }
+
+ c->Message(15, "Player initiated inventory resyncronization:");
+ c->ResyncInventory(false);
+}
Index: zone/command.h
===================================================================
--- zone/command.h (revision 2241)
+++ zone/command.h (working copy)
@@ -323,6 +323,7 @@
void command_printquestitems(Client *c, const Seperator *sep);
void command_clearquestitems(Client *c, const Seperator *sep);
void command_zopp(Client *c, const Seperator *sep);
+void command_resyncinv(Client *c, const Seperator *sep);
#ifdef EMBPERL
void command_embperl_plugin(Client *c, const Seperator *sep);
Index: zone/inventory.cpp
===================================================================
--- zone/inventory.cpp (revision 2241)
+++ zone/inventory.cpp (working copy)
@@ -965,6 +965,7 @@
banker ? banker->GetName() : "UNKNOWN NPC", distance);
database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName());
safe_delete_array(hacked_string);
+ // This Kick() can be deleted unless an automatic ban is in use. A resyncinv is triggered on the 'return false;' -U
Kick(); // Kicking player to avoid item loss do to client and server inventories not being sync'd
return false;
}
@@ -1020,12 +1021,16 @@
move_in->from_slot = dst_slot_check;
move_in->to_slot = src_slot_check;
move_in->number_in_stack = dst_inst->GetCharges();
- if (!SwapItem(move_in)) // shouldn't fail because call wouldn't exist otherwise, but just in case...
- this->Message(13, "Error: Internal SwapItem call returned a failure!");
+ if (!SwapItem(move_in)) {
+#if (EQDEBUG>= 5)
+ LogFile->write(EQEMuLog::Debug, "Client::SwapItem() %s's recursive swapitem call resulted in an unknown failure.", GetName());
+#endif
+ }
}
- Message(13, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
- LogFile->write(EQEMuLog::Debug, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
- this->DeleteItemInInventory(dst_slot_id,0,true);
+ // This code is no longer needed :) -U
+ //Message(13, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
+ //LogFile->write(EQEMuLog::Debug, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
+ //this->DeleteItemInInventory(dst_slot_id,0,true);
return false;
}
//verify shared bank transactions in the database
@@ -1210,9 +1215,9 @@
else {
// Nothing in destination slot: split stack into two
if ((sint16)move_in->number_in_stack >= src_inst->GetCharges()) {
+ // Move entire stack
+ if(!m_inv.SwapItem(src_slot_id, dst_slot_id)) { return false; }
mlog(INVENTORY__SLOTS, "Move entire stack from %d to %d with stack size %d. Dest empty.", src_slot_id, dst_slot_id, move_in->number_in_stack);
- // Move entire stack
- m_inv.SwapItem(src_slot_id, dst_slot_id);
}
else {
// Split into two
@@ -1232,8 +1237,8 @@
}
SetMaterial(dst_slot_id,src_inst->GetItem()->ID);
}
+ if(!m_inv.SwapItem(src_slot_id, dst_slot_id)) { return false; }
mlog(INVENTORY__SLOTS, "Moving entire item from slot %d to slot %d", src_slot_id, dst_slot_id);
- m_inv.SwapItem(src_slot_id, dst_slot_id);
}
int matslot = SlotConvert2(dst_slot_id);
@@ -1258,6 +1263,174 @@
return true;
}
+void Client::ResyncInventory(bool server_call, bool timer_callback) {
+ // This method is used to syncronize client and server inventories when a swapitem request fails -U
+
+ // Ranges not updated: Tribute, Trader, Trader Bags, World Container (Can reassess later)
+
+ // 1) NEED TO DETERMINE ALL CLIENT CURSOR LIMITS (SoF IS 37 {0..36})
+ // 2) REALLY LEANING TOWARDS CLOSING ALL CONTAINERS - INCLUDING BAGS - CAN'T UPDATE TRADER OR WORLD CONTAINERS PROPERLY
+ // ---(Had an open 4-slot bag in slot 25 -> used #zopp to send a 10-slot to replace it in the client -> both bags were open at the same time...)
+ // 3) ALL BANK SLOTS DO NOT ACCEPT NORMAL DELETE ITEM REQUESTS - CODE IN PLACE TO HANDLE FIX - FIND FIX!
+ // 4) USING CALLBACK TIMER TO ALLEVIATE WASTING CLOCK CYCLES - CLIENT DOESN'T IMMEDIATELY 'POP' FROM CURSOR LIST
+ // 5) CONSIDER 'STUNNING' PLAYER WHILE RESYNC IS PROCESSING - WILL IT HURT? WILL IT HELP?
+ // 6) WHEN USING BANK SLOT HACK CODE, ANY EMPTY SLOTS (OR BAG SLOTS IF PARENT IS CONTAINER) WILL GENERATE CLIENT MESSAGE
+ // 7) SHARED BANK SLOTS ARE NOT FIXABLE USING HACK CODE. CAN ONLY OVER-WRITE EXISTING AND CLIENT CAN STILL HAVE CSD'S HERE
+ // 8) NOT ALL CSD'S ARE FIXABLE USING THIS METHOD. ZONING OR LOGGING ARE THE ONLY WAY TO FIX ALL CSD ISSUES.
+ // 9) 'ResyncInvCallBackDelay' SET TO ~125MS SEEMS TO WORK..MAY NEED TO FIND CLIENT PING AND ADD %10 ~ %20
+ // 10) FUTURE WORK INCLUDES TRIMMING DOWN ARGUMENTS AND PROCESSES
+
+ /* DO INITIAL CALL WORK */
+ if(!timer_callback) {
+ if(!ResyncInvCount) {
+ Message(15, "Attempting to syncronize %s's inventory [STAND-BY]", GetName());
+
+#if (EQDEBUG>=5)
+ if(server_call) { LogFile->write(EQEMuLog::Debug, "Client::ResyncInventory() server swapitem failure called for resync of %s's inventory", GetName()); }
+#endif
+ }
+ // Close all containers - if possible
+
+ ResyncInvCallBackDelay = 125; /* SET CALLBACK DELAY HERE */
+ ResyncInvCount += 1;
+
+ if(ResyncInvCount > 3) {
+ ResyncInvCallBackTimer->Disable();
+ ResyncInvCount = 0;
+ ResyncInvCursorCount = 0;
+
+ Kick();
+ }
+ else if(ResyncInvCount > 1) {
+ Message(13, "Warning: Do not perform any actions until syncronization completes!");
+ ResyncInvCursorCount = CURSOR_LIMIT;
+ }
+ else {
+ if(m_inv.CursorSize() < CURSOR_LIMIT) { ResyncInvCursorCount = m_inv.CursorSize() + 1; }
+ else { ResyncInvCursorCount = CURSOR_LIMIT; }
+ }
+
+ ResyncInvCallBackTimer->Start(ResyncInvCallBackDelay);
+
+ return;
+ }
+
+ /* DO CURSOR DELETION WORK ON EACH CALLBACK */
+ const Item_Struct* resync_token1 = database.GetItem(22292); // 22292 = 'Copper Coin' (non-lore item)
+ ItemInst* token_inst1 = database.CreateItem(resync_token1, 1);
+
+ // Delete Current Cursor
+ SendItemPacket(SLOT_CURSOR, token_inst1, ItemPacketTrade);
+ ResyncInvClDelItem(SLOT_CURSOR, token_inst1, true);
+
+ if(ResyncInvCursorCount) { return; }
+
+ /* DO THE REST OF THE WORK NOW THAT CALLBACKS ARE OVER */
+ const Item_Struct* resync_token2 = database.GetItem(1041); // 1041 = 'Worthless Coin' (lore item)
+ ItemInst* token_inst2 = database.CreateItem(resync_token2, 1); // Part of Bank Sync Hack Process
+
+ ResyncInvProcSlots(0, 21, token_inst1); // Sync Worn
+ ResyncInvProcSlots(22, 29, token_inst1); // Sync Personal
+ ResyncInvProcSlots(251, 330, token_inst1, true, true, true); // Sync Personal Bags
+ /* BROKEN */ //ResyncInvProcSlots(400, 404, /* unknown_token_type */, false, /* unknown_delete_type */, false); // Sync Tribute
+
+ if(GetClientVersion() < EQClientSoF) {
+ /* IN-WORK */ ResyncInvProcSlots(2000, 2015, token_inst2, false, false, false); // Sync Bank (Deletion Issue)
+ /* IN-WORK */ ResyncInvProcSlots(2031, 2190, token_inst2, false, false, true); // Sync Bank Bags (Deletion Issue)
+ }
+ else {
+ ResyncInvProcSlots(9999, 9999, token_inst1); // Sync Power Source
+ /* IN-WORK */ ResyncInvProcSlots(2000, 2023, token_inst2, false, false, false); // Sync Bank (Deletion Issue)
+ /* IN-WORK */ ResyncInvProcSlots(2031, 2270, token_inst2, false, false, true); // Sync Bank Bags (Deletion Issue)
+ }
+
+ /* IN-WORK */ ResyncInvProcSlots(2500, 2501, token_inst2, false, false, false); // Sync Shared Bank (Deletion Issue)
+ /* IN-WORK */ ResyncInvProcSlots(2531, 2550, token_inst2, false, false, true); // Sync Shared Bank Bags (Deletion Issue)
+
+ /* IN-WORK */ //ResyncInvClDelItem(SLOT_CURSOR, token_inst2); // Part of Bank Sync Hack Process
+
+ /* BROKEN */ //ResyncInvProcSlots(3000, 3007, /* unknown_token_type */, false, /* unknown_delete_type */, false); // Sync Trader
+ /* BROKEN */ //ResyncInvProcSlots(3100, 3179, /* unknown_token_type */, false, /* unknown_delete_type */, true); // Sync Trader Bags
+ /* BROKEN */ //ResyncInvProcSlots(4000, 4009, /* unknown_token_type */, false, /* unknown_delete_type */, false); // Sync World Container
+
+ int8 cursor_count = 1; // Sync Cursor Array
+ for(std::list<ItemInst*>::const_iterator cursor_iter = m_inv.cursor_begin(); cursor_iter != m_inv.cursor_end() && cursor_count <= CURSOR_LIMIT;
+ cursor_iter++, cursor_count++) { SendItemPacket(SLOT_CURSOR, *cursor_iter, ItemPacketSummonItem); }
+
+ ResyncInvProcSlots(331, 340, token_inst1, true, true, true); // Sync Cursor Bags
+
+ if (cursor_count > CURSOR_LIMIT) {
+ Message(15, "Caution: The server's cursor count exceeds client capacity.");
+ Message(15, "To avoid issues, remove all cursor items and zone or relog.");
+ }
+
+ if(ResyncInvCount) { ResyncInvCount -= 1; }
+ if(ResyncInvCount) { ResyncInvCallBack(); }
+ else { Message(14, "%s's inventory syncronization complete", GetName()); }
+}
+
+void Client::ResyncInvCallBack() {
+
+ ResyncInvCallBackTimer->Disable();
+ ResyncInventory(false, true);
+
+ if(ResyncInvCursorCount) { ResyncInvCursorCount -= 1; ResyncInvCallBackTimer->Start(); }
+}
+
+void Client::ResyncInvProcSlots(sint16 slot_begin, sint16 slot_end, const ItemInst* token_inst, bool update_null, bool reg_delete, bool chk_parent) {
+
+ for(sint16 slot_id = slot_begin; slot_id <= slot_end; slot_id++) {
+ const ItemInst* slot_inst = m_inv[slot_id];
+
+ if(chk_parent) {
+ sint16 parent_slot = m_inv.CalcSlotId(slot_id);
+
+ if(parent_slot != SLOT_INVALID && m_inv[parent_slot] && m_inv[parent_slot]->GetItem()->ItemClass == 1) {
+ if(slot_inst) { SendItemPacket(slot_id, slot_inst, ItemPacketTrade); }
+ else {
+ SendItemPacket(slot_id, token_inst, ItemPacketTrade);
+ if(update_null) { ResyncInvClDelItem(slot_id, token_inst, reg_delete); }
+ }
+ }
+ }
+ else {
+ if(slot_inst) { SendItemPacket(slot_id, slot_inst, ItemPacketTrade); }
+ else {
+ SendItemPacket(slot_id, token_inst, ItemPacketTrade);
+ if(update_null) { ResyncInvClDelItem(slot_id, token_inst, reg_delete); }
+ }
+ }
+ }
+}
+
+void Client::ResyncInvClDelItem(sint16 slot_id, const ItemInst* token_inst, bool reg_delete) {
+
+ if(!token_inst) { return; } // Part of Bank Sync Hack Process
+ else if(token_inst->GetID() == 1041) { SendItemPacket(slot_id, token_inst, ItemPacketTrade); } // Part of Bank Sync Hack Process
+ else if(reg_delete) {
+ EQApplicationPacket* outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
+ DeleteItem_Struct* delete_slot = (DeleteItem_Struct*)outapp->pBuffer;
+ delete_slot->from_slot = slot_id;
+ delete_slot->to_slot = 0xFFFFFFFF;
+ delete_slot->number_in_stack = 0xFFFFFFFF;
+
+ QueuePacket(outapp);
+ safe_delete(outapp);
+ }
+ else { /* IN-WORK */
+ EQApplicationPacket* outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
+ DeleteItem_Struct* delete_slot = (DeleteItem_Struct*)outapp->pBuffer;
+ delete_slot->from_slot = slot_id;
+ delete_slot->to_slot = 0xFFFFFFFF;
+ delete_slot->number_in_stack = 0xFFFF; // Test value
+
+ QueuePacket(outapp);
+ safe_delete(outapp);
+ }
+
+ /* IF 'OP_DeleteItem' METHOD FOR ALTERNATE DELETE CAN BE FIGURED OUT - REMOVE 'token_inst' FROM ARGUMENTS */
+}
+
void Client::DyeArmor(DyeStruct* dye){
sint16 slot=0;
for(int i=0;i<7;i++){
|