Skip to content

Commit 8fa344a

Browse files
committed
refactor(item): name CGItem deref idioms via Item::InstanceBlock / ObjectFields
Add item/CGItem.{h,cpp} with two null-safe accessors for a CGItem's two descriptor-like pointers: InstanceBlock(cgItem) -> CGItem + 0x08 (item GUID @ +0, itemID @ +0x0C) ObjectFields(cgItem) -> CGItem + 0x114 (stack/flags/charges/durability/...) Replace the 30 hand-written `*reinterpret_cast<const uint8_t *const *>(x + OFF_ITEM_INSTANCE_BLOCK/OFF_ITEM_DESCRIPTOR)` derefs across 24 files with these calls. Behavior-preserving: same deref, all reads were already const, and each site keeps its own null-check and field reads. Helpers add a cgItem null guard (strictly safer).
1 parent 2612118 commit 8fa344a

26 files changed

Lines changed: 126 additions & 60 deletions

src/auctionhouse/PostItem.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include "Game.h"
5656
#include "Offsets.h"
5757
#include "event/Custom.h"
58+
#include "item/CGItem.h"
5859
#include "item/ID.h"
5960
#include "item/Location.h"
6061
#include "item/Swap.h"
@@ -108,16 +109,14 @@ const uint8_t *PeekItemRecord(uint32_t itemID) {
108109
}
109110

110111
int CGItemCount(const uint8_t *item) {
111-
auto *desc = *reinterpret_cast<const uint8_t *const *>(
112-
item + Offsets::OFF_ITEM_DESCRIPTOR);
112+
auto *desc = Item::ObjectFields(item);
113113
if (desc == nullptr)
114114
return 0;
115115
return *reinterpret_cast<const int *>(desc + Offsets::OFF_DESCRIPTOR_STACK_COUNT);
116116
}
117117

118118
uint64_t CGItemGuid(const uint8_t *item) {
119-
auto *inst = *reinterpret_cast<const uint8_t *const *>(
120-
item + Offsets::OFF_ITEM_INSTANCE_BLOCK);
119+
auto *inst = Item::InstanceBlock(item);
121120
if (inst == nullptr)
122121
return 0;
123122
return *reinterpret_cast<const uint64_t *>(inst + Offsets::OFF_INSTANCE_BLOCK_GUID);

src/container/ItemInfo.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "Game.h"
5151
#include "Offsets.h"
5252
#include "dbc/Lookup.h"
53+
#include "item/CGItem.h"
5354
#include "item/ID.h"
5455
#include "item/Link.h"
5556
#include "item/Location.h"
@@ -80,8 +81,7 @@ bool ItemReadable(const uint8_t *item, const uint8_t *record) {
8081
if (record != nullptr &&
8182
*reinterpret_cast<const uint32_t *>(record + Offsets::OFF_ITEMSTATS_PAGE_TEXT) != 0)
8283
return true;
83-
const uint8_t *descriptor = *reinterpret_cast<const uint8_t *const *>(
84-
item + Offsets::OFF_ITEM_DESCRIPTOR);
84+
const uint8_t *descriptor = Item::ObjectFields(item);
8585
return descriptor != nullptr &&
8686
*reinterpret_cast<const uint32_t *>(
8787
descriptor + Offsets::OFF_DESCRIPTOR_READABLE_TEXT_ID) != 0;
@@ -111,8 +111,7 @@ int __fastcall Script_C_Container_GetContainerItemInfo(void *L) {
111111
: nullptr;
112112

113113
// Live per-instance descriptor fields.
114-
const uint8_t *descriptor = *reinterpret_cast<const uint8_t *const *>(
115-
item + Offsets::OFF_ITEM_DESCRIPTOR);
114+
const uint8_t *descriptor = Item::ObjectFields(item);
116115
int stackCount = 0;
117116
bool isBound = false;
118117
if (descriptor != nullptr) {

src/equipmentset/Api.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "Offsets.h"
3636
#include "Set.h"
3737
#include "event/Custom.h"
38+
#include "item/CGItem.h"
3839
#include "item/Location.h"
3940
#include "item/Swap.h"
4041

@@ -72,8 +73,7 @@ const char *ArgString(void *L, int idx) {
7273
int ResolveItemID(const uint8_t *cgItem) {
7374
if (cgItem == nullptr)
7475
return 0;
75-
auto *instance = *reinterpret_cast<const uint8_t *const *>(
76-
cgItem + Offsets::OFF_ITEM_INSTANCE_BLOCK);
76+
auto *instance = Item::InstanceBlock(cgItem);
7777
if (instance == nullptr)
7878
return 0;
7979
return static_cast<int>(*reinterpret_cast<const uint32_t *>(

src/item/Bound.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313

1414
#include "Game.h"
1515
#include "Offsets.h"
16+
#include "item/CGItem.h"
1617
#include "item/Location.h"
1718

1819
#include <cstdint>
1920

2021
namespace Item::Bound {
2122

2223
static bool ItemIsSoulbound(const uint8_t *item) {
23-
auto *descriptor = *reinterpret_cast<const uint8_t *const *>(
24-
item + Offsets::OFF_ITEM_DESCRIPTOR);
24+
auto *descriptor = Item::ObjectFields(item);
2525
if (descriptor == nullptr)
2626
return false;
2727
const uint32_t flags = *reinterpret_cast<const uint32_t *>(

src/item/CGItem.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// This file is part of ClassicAPI.
2+
//
3+
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
4+
// of the GNU General Public License as published by the Free Software Foundation, either
5+
// version 3 of the License, or (at your option) any later version.
6+
//
7+
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
8+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9+
// PURPOSE. See the GNU General Public License for more details.
10+
//
11+
// You should have received a copy of the GNU General Public License along with
12+
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
13+
14+
#include "CGItem.h"
15+
16+
#include "Offsets.h"
17+
18+
namespace Item {
19+
20+
const uint8_t *InstanceBlock(const uint8_t *cgItem) {
21+
if (cgItem == nullptr)
22+
return nullptr;
23+
return *reinterpret_cast<const uint8_t *const *>(
24+
cgItem + Offsets::OFF_ITEM_INSTANCE_BLOCK);
25+
}
26+
27+
const uint8_t *ObjectFields(const uint8_t *cgItem) {
28+
if (cgItem == nullptr)
29+
return nullptr;
30+
return *reinterpret_cast<const uint8_t *const *>(
31+
cgItem + Offsets::OFF_ITEM_DESCRIPTOR);
32+
}
33+
34+
} // namespace Item

src/item/CGItem.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// This file is part of ClassicAPI.
2+
//
3+
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
4+
// of the GNU General Public License as published by the Free Software Foundation, either
5+
// version 3 of the License, or (at your option) any later version.
6+
//
7+
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
8+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9+
// PURPOSE. See the GNU General Public License for more details.
10+
//
11+
// You should have received a copy of the GNU General Public License along with
12+
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
13+
14+
#pragma once
15+
16+
#include <cstdint>
17+
18+
// Accessors for a `CGItem`'s two descriptor-like pointers (see the "Item
19+
// lookups" notes in CLAUDE.md). Every item module used to spell out the same
20+
// `*reinterpret_cast<const uint8_t *const *>(cgItem + OFF_...)` deref; these
21+
// name it once.
22+
23+
namespace Item {
24+
25+
// The item's **instance block** (`CGItem + 0x08` dereferenced): a `uint64`
26+
// item GUID at `+0x00` and the `uint32` itemID at `+0x0C`. This is the block
27+
// the canonical inventory→cache path reads the itemID from. Returns nullptr
28+
// for a null `cgItem`; the stored pointer itself may still be null (callers
29+
// null-check the result before reading fields).
30+
const uint8_t *InstanceBlock(const uint8_t *cgItem);
31+
32+
// The item's **m_objectFields descriptor** (`CGItem + 0x114` dereferenced):
33+
// the UpdateField block holding stack count (`+0x20`), flags (`+0x3C`),
34+
// spell charges (`+0x28`), durability (`+0xA0`), enchantments, etc. Distinct
35+
// from the instance block. Returns nullptr for a null `cgItem`.
36+
const uint8_t *ObjectFields(const uint8_t *cgItem);
37+
38+
} // namespace Item

src/item/Charges.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "../Game.h"
1717
#include "../Offsets.h"
18+
#include "CGItem.h"
1819

1920
#include <cstdlib>
2021

@@ -23,8 +24,7 @@ namespace Item::Charges {
2324
int PushChargesForItem(void *L, const uint8_t *item) {
2425
if (item == nullptr)
2526
return 0;
26-
auto *descriptor = *reinterpret_cast<const uint8_t *const *>(
27-
item + Offsets::OFF_ITEM_DESCRIPTOR);
27+
auto *descriptor = Item::ObjectFields(item);
2828
if (descriptor == nullptr)
2929
return 0;
3030
const int32_t stack = static_cast<int32_t>(*reinterpret_cast<const uint32_t *>(

src/item/Count.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "Game.h"
1717
#include "Offsets.h"
1818
#include "item/Arg.h"
19+
#include "item/CGItem.h"
1920
#include "item/ID.h"
2021
#include "item/Location.h"
2122
#include "object/Resolve.h"
@@ -33,8 +34,7 @@ namespace {
3334
int GetStackCount(const uint8_t *cgItem) {
3435
if (cgItem == nullptr)
3536
return 0;
36-
auto *descriptor = *reinterpret_cast<const uint8_t *const *>(
37-
cgItem + Offsets::OFF_ITEM_DESCRIPTOR);
37+
auto *descriptor = Item::ObjectFields(cgItem);
3838
if (descriptor == nullptr)
3939
return 0;
4040
return static_cast<int>(*reinterpret_cast<const uint32_t *>(
@@ -52,8 +52,7 @@ int GetStackCount(const uint8_t *cgItem) {
5252
int GetUsesPerItem(const uint8_t *cgItem) {
5353
if (cgItem == nullptr)
5454
return 1;
55-
auto *descriptor = *reinterpret_cast<const uint8_t *const *>(
56-
cgItem + Offsets::OFF_ITEM_DESCRIPTOR);
55+
auto *descriptor = Item::ObjectFields(cgItem);
5756
if (descriptor == nullptr)
5857
return 1;
5958
const int32_t raw = *reinterpret_cast<const int32_t *>(

src/item/Cursor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "Game.h"
1717
#include "Offsets.h"
1818
#include "cursor/Info.h"
19+
#include "item/CGItem.h"
1920
#include "item/Location.h"
2021

2122
#include <cstdint>
@@ -44,8 +45,7 @@ bool ItemLocked(const uint8_t *item) {
4445
// Reads a CGItem's 64-bit instance GUID into lo/hi. False if the instance
4546
// block pointer is absent.
4647
bool ReadItemGuid(const uint8_t *item, uint32_t *lo, uint32_t *hi) {
47-
auto *instance = *reinterpret_cast<const uint8_t *const *>(
48-
item + Offsets::OFF_ITEM_INSTANCE_BLOCK);
48+
auto *instance = Item::InstanceBlock(item);
4949
if (instance == nullptr)
5050
return false;
5151
*lo = *reinterpret_cast<const uint32_t *>(instance + Offsets::OFF_INSTANCE_BLOCK_GUID);

src/item/Data.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Offsets.h"
1616
#include "event/Custom.h"
1717
#include "item/Arg.h"
18+
#include "item/CGItem.h"
1819
#include "item/Data.h"
1920
#include "item/Location.h"
2021
#include "tick/WorldTick.h"
@@ -119,8 +120,7 @@ static int ResolveLocationToItemID(void *L, int idx) {
119120
const uint8_t *item = Item::Location::Resolve(L, idx);
120121
if (item == nullptr)
121122
return 0;
122-
auto *instance = *reinterpret_cast<const uint8_t *const *>(
123-
item + Offsets::OFF_ITEM_INSTANCE_BLOCK);
123+
auto *instance = Item::InstanceBlock(item);
124124
if (instance == nullptr)
125125
return 0;
126126
return static_cast<int>(*reinterpret_cast<const uint32_t *>(

0 commit comments

Comments
 (0)