[SPOILER="How the Get All Items by SubType Code Was Made"]



This explains how the original Get All Clothing code was extended to filter items by both ItemType and a more specific SubType.



The addresses below are for:



[CODE]

Disney Dreamlight Valley v1.23.0

Title ID: 0100D39012C1A800

Build: v3801088

[/CODE]



This post assumes that the previous Get All Clothing Items explanation has already been read.



The following parts are unchanged and will not be explained again here:



The WardrobeMenu.OnFocusIn hook
The DebugAddItem developer-check bypass
MissionManager.get_MetaClient
ItemDatabase.get_Instance
The IL2CPP array layout
Reading Item from item-data object +0x18
Calling Client.DebugAddItem
The array loop and asynchronous processing
The basic code-cave selection


This post covers only the additional work required to call the generic GetAllByType method with both an ItemType and a SubType.



[SPOILER="1. Why ItemType alone is not always enough"]



The original Clothing code uses:



[CODE]

ItemDatabase.GetAllByType(ItemType.Clothing)

[/CODE]



This is sufficient when the entire ItemType should be added.



Some ItemTypes contain several groups that should not be handled together.



For example:



[CODE]

ItemType.Building

    House

    Stall

    Garden

    Other

    OffGridBuilding

    PlayerHouse

[/CODE]



Adding every Building entry is not desirable when the goal is only to unlock player-house items.



It could also include NPC houses, stalls, gardens or other building data that is not intended to be granted as a player-house selection.



The Building SubType enum is:



[CODE]

public enum BuildingItemType

{

    House           = 0,

    Stall           = 1,

    Garden          = 2,

    Other           = 3,

    OffGridBuilding = 4,

    PlayerHouse     = 5

}

[/CODE]



The Companion ItemType also contains several different groups:



[CODE]

public enum CompanionItemType

{

    Pet     = 0,

    Critter = 1,

    Snippet = 2,

    Mount   = 3

}

[/CODE]



The three configurations used by this code are:



[CODE]

PlayerHouse

    ItemDataType = BuildingItemData

    ItemType     = Building (2)

    SubType enum = BuildingItemType

    SubType      = PlayerHouse (5)



Pet

    ItemDataType = PetItemData

    ItemType     = Companion (12)

    SubType enum = CompanionItemType

    SubType      = Pet (0)



Mount

    ItemDataType = MountItemData

    ItemType     = Companion (12)

    SubType enum = CompanionItemType

    SubType      = Mount (3)

[/CODE]



The purpose of the SubType version is therefore:



[CODE]

Get every item of the requested ItemType

    +

keep only the requested SubType

    +

return the requested concrete ItemDataType

[/CODE]



[/SPOILER]



[SPOILER="2. Finding the generic GetAllByType overload"]



The original Clothing code uses:



[CODE]

public IEnumerable<IItemData>

    GetAllByType(ItemType itemType);

[/CODE]



ItemDatabase also contains the following generic overload:



[CODE]

public IEnumerable<ItemDataType>

    GetAllByType<ItemDataType, SubItemEnumType>(

        ItemType itemType,

        SubItemEnumType subItemEnumType

    );

[/CODE]



Il2CppDumper identifies its shared native implementation as:



[CODE]

RVA:     0x3677620

Address: 0x7103677620



ItemDatabase.GetAllByType<

    __Il2CppFullySharedGenericType,

    __Il2CppFullySharedGenericStructType

>

[/CODE]



The first generic parameter selects the concrete item-data class.



Examples:



[CODE]

BuildingItemData

PetItemData

MountItemData

[/CODE]



The second generic parameter selects the enum type used for the SubType.



Examples:



[CODE]

BuildingItemType

CompanionItemType

[/CODE]



At a high level, the calls represented by the three configurations are:



[CODE]

database.GetAllByType<

    BuildingItemData,

    BuildingItemType

>(

    ItemType.Building,

    BuildingItemType.PlayerHouse

);

[/CODE]



[CODE]

database.GetAllByType<

    PetItemData,

    CompanionItemType

>(

    ItemType.Companion,

    CompanionItemType.Pet

);

[/CODE]



[CODE]

database.GetAllByType<

    MountItemData,

    CompanionItemType

>(

    ItemType.Companion,

    CompanionItemType.Mount

);

[/CODE]



Unlike the non-generic overload, the native shared implementation also needs information describing the concrete generic types used by the call.



That information is supplied through the concrete Method$ entry.



[/SPOILER]



[SPOILER="3. Using an existing game function as the call template"]



Rather than guessing the native calling convention, I examined an existing game function that calls the same generic method.



`Meta.DebugUnlockAllCritters.Types.Response.ApplyThis` calls:



[CODE]

ItemDatabase.GetAllByType<

    CritterItemData,

    CompanionItemType

>(

    ItemType.Companion,

    CompanionItemType.Critter

);

[/CODE]



The relevant game code is:



[CODE]

ADRP  X8, Method$ItemDatabase.GetAllByType<

              CritterItemData,

              CompanionItemType>



ADD   X2, SP, #subTypeStorage



LDR   X3, [X8,

           Method$ItemDatabase.GetAllByType<

               CritterItemData,

               CompanionItemType>@PAGEOFF]



MOV   W8, #1

MOV   W1, #0xC

STR   W8, [SP,#subTypeStorage]



BL    ItemDatabase.GetAllByType<

          FullySharedGenericType,

          FullySharedGenericStructType>

[/CODE]



The same function calls the Pet version like this:



[CODE]

ADRP  X8, Method$ItemDatabase.GetAllByType<

              PetItemData,

              CompanionItemType>



ADD   X2, SP, #subTypeStorage

STR   WZR, [SP,#subTypeStorage]



LDR   X3, [X8,

           Method$ItemDatabase.GetAllByType<

               PetItemData,

               CompanionItemType>@PAGEOFF]



MOV   W1, #0xC



BL    ItemDatabase.GetAllByType<

          FullySharedGenericType,

          FullySharedGenericStructType>

[/CODE]



These calls establish the native argument layout:



[CODE]

X0 = ItemDatabase*

W1 = ItemType

X2 = pointer to the SubType value

X3 = concrete generic MethodInfo*

[/CODE]



The custom code reproduces this same call pattern.



[/SPOILER]



[SPOILER="4. The concrete Method$ slots"]



The generic implementation at 0x7103677620 is shared by many combinations of generic types.



The concrete type combination is identified through a Method$ entry.



The relevant entries in the game's data section are:



[CODE]

0x710ABE7990

Method$Definitions.Items.ItemDatabase.GetAllByType<

    BuildingItemData,

    BuildingItemType

>

[/CODE]



[CODE]

0x710ABE7A40

Method$Definitions.Items.ItemDatabase.GetAllByType<

    PetItemData,

    CompanionItemType

>

[/CODE]



[CODE]

0x710ABE7A28

Method$Definitions.Items.ItemDatabase.GetAllByType<

    MountItemData,

    CompanionItemType

>

[/CODE]



All three entries are on the same page:



[CODE]

0x710ABE7000

[/CODE]



Their page offsets are:



[CODE]

PlayerHouse: 0x990

Pet:         0xA40

Mount:       0xA28

[/CODE]



The same Method$ entry is used twice in the custom routine.



First, its address is passed to the metadata warm-up helper:



[CODE]

ADRP X0, 0x710ABE7000

ADD  X0, X0, #MethodSlotOffset

[/CODE]



Later, the resolved MethodInfo pointer stored in that slot is loaded into X3:



[CODE]

ADRP X3, 0x710ABE7000

LDR  X3, [X3,#MethodSlotOffset]

[/CODE]



These operations are different.



[CODE]

ADRP + ADD

    -> address of the Method$ slot



ADRP + LDR

    -> MethodInfo pointer stored in the slot

[/CODE]



The offset used by both operations must refer to the same concrete generic method.



Using the Building slot for warm-up and the Pet slot for the actual call would create an invalid combination.



[/SPOILER]



[SPOILER="5. Why the Method$ slot is initialized first"]



The game's own generated code initializes its Method$ entries before using them.



For example:



[CODE]

ADRL X0, Method$ItemDatabase.GetAllByType<

             CritterItemData,

             CompanionItemType>

DMB  ISH

MOV  W1, #1

BL   sub_7100B4C1B0



ADRL X0, Method$ItemDatabase.GetAllByType<

             PetItemData,

             CompanionItemType>

DMB  ISH

MOV  W1, #1

BL   sub_7100B4C1B0

[/CODE]



The helper at:



[CODE]

0x7100B4C1B0

[/CODE]



is used throughout IL2CPP-generated code to prepare metadata entries such as Method$ and TypeInfo slots for runtime use.



The custom code follows the same pattern:



[CODE]

X0 = address of the Method$ slot

W1 = 1

call metadata helper

[/CODE]



I did not separately test a version that omits this call.



The reason it is included is that the original game code performs the same initialization before accessing these Method$ entries.



Why a long call is used



A normal ARM64 `BL` has a range of approximately plus or minus 128 MiB.



The distance from this code cave to the helper is approximately:



[CODE]

0x7108CB4140 - 0x7100B4C1B0

= 0x8167F90

= approximately 129.4 MiB

[/CODE]



This is outside the direct BL range.



The helper address is therefore constructed in X8 and called indirectly:



[CODE]

ADRP X8, 0x7100B4C000

ADD  X8, X8, #0x1B0

BLR  X8

[/CODE]



After the ADD:



[CODE]

X8 = 0x7100B4C1B0

[/CODE]



`BLR X8` calls the address stored in X8 and writes the return address to X30.



X8 is a volatile register, so it is suitable as a temporary branch register here.



[/SPOILER]



[SPOILER="6. Why the SubType is passed through memory"]



The SubType is not passed directly as a normal integer in W2.



Instead, the value is stored on the stack and X2 receives its address:



[CODE]

MOV W8, #5

STR W8, [SP,#0x10]

ADD X2, SP,#0x10

[/CODE]



The existing game code uses the same pattern:



[CODE]

MOV W8, #1

STR W8, [SP,#subTypeStorage]

ADD X2, SP,#subTypeStorage

[/CODE]



The generic function entry confirms how the arguments are received:



[CODE]

0x7103677640    LDR X8, [X3,#0x38]

0x7103677644    MOV X19, X3

0x7103677648    MOV X26, X2

0x710367764C    MOV W20, W1

0x7103677650    MOV X22, X0

[/CODE]



This preserves:



[CODE]

X19 = MethodInfo*

X26 = pointer to SubType data

W20 = ItemType

X22 = ItemDatabase*

[/CODE]



The function then reads the concrete generic value-type size from metadata and copies the SubType value from the memory pointed to by X2:



[CODE]

0x71036776E4    LDR   X9, [X8,#0x10]

0x71036776E8    LDR   W23, [X9,#0xFC]



...



0x7103677730    MOV   X0, X21

0x7103677734    MOV   X1, X26

0x7103677738    MOV   X2, X23

0x710367773C    BL    memcpy

[/CODE]



Conceptually:



[CODE]

subTypeSize = genericMetadata.SubTypeSize;

copy(localSubType, X2, subTypeSize);

[/CODE]



The native function is shared between different generic struct types.



It therefore receives the value through a pointer and uses the concrete MethodInfo metadata to determine how much data must be copied.



The enum values used by these three configurations are 32-bit values, but the shared implementation is not hard-coded specifically for only these enums.



[/SPOILER]



[SPOILER="7. Stack space used for the SubType value"]



The original Clothing routine saved X21 and X22 with:



[CODE]

STP X21, X22, [SP,#-0x10]!

[/CODE]



The SubType version changes this to:



[CODE]

STP X21, X22, [SP,#-0x20]!

[/CODE]



This decreases SP by 32 bytes.



The first 16 bytes store X21 and X22:



[CODE]

SP + 0x00 = saved X21

SP + 0x08 = saved X22

[/CODE]



The remaining 16 bytes are available as temporary storage:



[CODE]

SP + 0x10 = SubType value

SP + 0x14

SP + 0x18

SP + 0x1C

[/CODE]



The code stores the enum at:



[CODE]

STR W8, [SP,#0x10]

[/CODE]



and passes its address with:



[CODE]

ADD X2, SP,#0x10

[/CODE]



The stack remains 16-byte aligned.



At the end of the routine:



[CODE]

LDP X21, X22, [SP],#0x20

[/CODE]



restores X21 and X22 and releases the complete 32-byte block, including the temporary SubType storage.



[/SPOILER]



[SPOILER="8. What the generic GetAllByType method does"]



The shared implementation first converts the generic SubType value into a common enum representation.



Relevant excerpt:



[CODE]

0x7103677924    MOV X0, X26

0x7103677928    MOV X1, XZR

0x710367792C    BL  Definitions.Util.GenericEnum$$Create

[/CODE]



It then combines the ItemType and SubType information through ItemTypeMetaInfo:



[CODE]

0x7103677948    MOV W0, W20

0x710367794C    MOV X1, X26

0x7103677950    MOV X2, X25

0x7103677954    BL  ItemDatabase.ItemTypeMetaInfo$$GetItemTypeMetaInfo

[/CODE]



The ItemDatabase cache uses the following key type:



[CODE]

ValueTuple<ItemType, Enum, Type>

[/CODE]



and stores the result as:



[CODE]

Array

[/CODE]



This allows different combinations such as:



[CODE]

Building + PlayerHouse + BuildingItemData

Companion + Pet + PetItemData

Companion + Mount + MountItemData

[/CODE]



to have separate cached results.



When a cached result does not exist, the generic method first calls the ordinary ItemType-only overload:



[CODE]

0x7103677C80    MOV X0, X22

0x7103677C84    MOV W1, W20

0x7103677C88    MOV X2, XZR

0x7103677C8C    BL  ItemDatabase$$GetAllByType

[/CODE]



Conceptually:



[CODE]

baseItems = GetAllByType(itemType);

[/CODE]



It then creates an additional predicate and applies `Where<IItemData>`:



[CODE]

0x7103677CA0    LDR X8, [X19,#0x38]

0x7103677CA4    MOV X1, X24

0x7103677CAC    MOV X26, X0

0x7103677CB0    LDR X2, [X8,#0x30]

0x7103677CB4    BL  System.Func...ctor



0x7103677CB8    ADRP X8, Method$Enumerable.Where<IItemData>

0x7103677CBC    MOV X0, X25

0x7103677CC4    MOV X1, X26

0x7103677CC8    BL  Enumerable.Where<IItemData>

[/CODE]



After filtering, it selects the requested ItemDataType and creates an array:



[CODE]

0x7103677E44    LDR X2, [X8,#0x60]

0x7103677E48    MOV X0, X25

0x7103677E4C    MOV X1, X26

0x7103677E50    BL  Enumerable.Select



0x7103677E54    LDR X8, [X19,#0x38]

0x7103677E58    LDR X1, [X8,#0x68]

0x7103677E5C    BL  Enumerable.ToArray

[/CODE]



The overall behavior can be represented as:



[CODE]

baseItems = GetAllByType(itemType)



filteredItems =

    baseItems

        .Where(item => item matches the requested SubType)

        .Select(item => requested ItemDataType)



result = filteredItems.ToArray()

[/CODE]



The exact predicate is generated through the concrete MethodInfo and ItemTypeMetaInfo.



The important result for the custom code is that the function finishes by creating a concrete array.



The same direct array loop used in the Clothing code can therefore be reused.



[/SPOILER]



[SPOILER="9. Why Item can still be read from +0x18"]



The three concrete item-data classes used by this code all implement IItemData and store their ID/Item backing value at +0x18.



BuildingItemData:



[CODE]

public sealed class BuildingItemData : ..., IItemData, ...

{

    private UnknownFieldSet _unknownFields; // 0x10



    public const int IDFieldNumber = 1;

    private int iD_;                        // 0x18



    public Item Item { get; }

}

[/CODE]



PetItemData:



[CODE]

public sealed class PetItemData : ..., IItemData, ...

{

    private UnknownFieldSet _unknownFields; // 0x10



    public const int IDFieldNumber = 1;

    private int iD_;                        // 0x18



    public Item Item { get; }

}

[/CODE]



MountItemData:



[CODE]

public sealed class MountItemData : ..., IItemData, ...

{

    private UnknownFieldSet _unknownFields; // 0x10



    public const int IDFieldNumber = 1;

    private int iD_;                        // 0x18



    public Item Item { get; }

}

[/CODE]



The loop can therefore use the same direct load explained in the Clothing post:



[CODE]

LDR X0, [X20, X22, LSL #3]

LDR W1, [X0,#0x18]

[/CODE]



The generic filtering changes which item-data objects are placed in the array.



It does not change the way their Item value is read.



[/SPOILER]



[SPOILER="10. The four configuration points"]



The template contains four values that must be changed together.



[CODE]

Point A:

    Method$ slot address used for metadata warm-up



Point B:

    ItemType value



Point C:

    SubType value



Point D:

    Method$ slot loaded into X3

[/CODE]



The valid settings used by the released codes are:



[CODE]

---------------------------------------------------------------

Target        Point A/D       Point B       Point C

---------------------------------------------------------------

PlayerHouse   offset 0x990    Building 2    PlayerHouse 5

Pet           offset 0xA40    Companion 12  Pet 0

Mount         offset 0xA28    Companion 12  Mount 3

---------------------------------------------------------------

[/CODE]



The concrete generic types represented by the Method$ slots are:



[CODE]

PlayerHouse:

GetAllByType<BuildingItemData, BuildingItemType>



Pet:

GetAllByType<PetItemData, CompanionItemType>



Mount:

GetAllByType<MountItemData, CompanionItemType>

[/CODE]



Points A and D must always use the same slot offset.



Point B must match the broad ItemType.



Point C must be a value from the enum type represented by the selected Method$ slot.



For example, this is a valid combination:



[CODE]

Method$:

    GetAllByType<MountItemData, CompanionItemType>



ItemType:

    Companion



SubType:

    CompanionItemType.Mount

[/CODE]



This would not be a valid combination:



[CODE]

Method$:

    GetAllByType<BuildingItemData, BuildingItemType>



ItemType:

    Companion



SubType:

    CompanionItemType.Mount

[/CODE]



[/SPOILER]



[SPOILER="11. Constructing the PlayerHouse call"]



The released template is configured for PlayerHouse.



First, the Method$ slot address is prepared for warm-up:



[CODE]

0x7108CB412C    ADRP X0, 0x710ABE7000

0x7108CB4130    ADD  X0, X0, #0x990

0x7108CB4134    MOV  W1, #1

[/CODE]



This gives:



[CODE]

X0 = 0x710ABE7990



Method$ItemDatabase.GetAllByType<

    BuildingItemData,

    BuildingItemType

>

[/CODE]



The metadata helper is called through X8:



[CODE]

0x7108CB4138    ADRP X8, 0x7100B4C000

0x7108CB413C    ADD  X8, X8, #0x1B0

0x7108CB4140    BLR  X8

[/CODE]



ItemDatabase.Instance is then obtained:



[CODE]

0x7108CB4144    BL 0x7104A8A200

[/CODE]



The broad ItemType is Building:



[CODE]

0x7108CB4148    MOV W1,#2

[/CODE]



The SubType is PlayerHouse:



[CODE]

0x7108CB414C    MOV W8,#5

0x7108CB4150    STR W8,[SP,#0x10]

0x7108CB4154    ADD X2,SP,#0x10

[/CODE]



The resolved concrete MethodInfo is loaded into X3:



[CODE]

0x7108CB4158    ADRP X3,0x710ABE7000

0x7108CB415C    LDR  X3,[X3,#0x990]

[/CODE]



Immediately before the generic call, the register state is:



[CODE]

X0 = ItemDatabase*

W1 = ItemType.Building

X2 = &BuildingItemType.PlayerHouse

X3 = MethodInfo for

     GetAllByType<

         BuildingItemData,

         BuildingItemType

     >

[/CODE]



The shared implementation is then called:



[CODE]

0x7108CB4160    BL 0x7103677620

[/CODE]



The result is the filtered array containing the requested PlayerHouse entries.



The remaining array traversal and DebugAddItem loop are unchanged from the Clothing code.



[/SPOILER]



[SPOILER="12. Complete assembly"]



[CODE]

// ============================================================================

// Get All Items By SubType (Generic Method Call)

// Target: v1.23.0 [0100D39012C1A800][v3801088][UPD]

// Code Cave Address: 0x7108CB4118

// Config: PlayerHouse

// Variants: Pet and Mount settings are listed below.

// ============================================================================





// --- [Block A] Hook (Mdl.Ui.WardrobeMenu$$OnFocusIn) ------------------------

// Original: MOV X0, X19

0x7107B15AD8    BL    0x7108CB4118





// --- [Block B] DebugAddItem developer-check bypass --------------------------

// Original: CBZ W8, loc_7104CAE46C

0x7104CAE434    NOP





// --- [Block C] Code Cave -----------------------------------------------------



// Save registers and reserve 16 bytes of scratch space for SubType

0x7108CB4118    STP   X19, X30, [SP, #-0x10]!

0x7108CB411C    STP   X19, X20, [SP, #-0x10]!

0x7108CB4120    STP   X21, X22, [SP, #-0x20]!





// Get active Client

0x7108CB4124    BL    0x71035CC3B0

0x7108CB4128    MOV   X19, X0





// ---------------------------------------------------------------------------

// CHANGE POINT A: Method$ slot address for metadata warm-up

//

// PlayerHouse:

//   offset 0x990

//   Method$GetAllByType<BuildingItemData, BuildingItemType>

//

// Pet:

//   offset 0xA40

//   Method$GetAllByType<PetItemData, CompanionItemType>

//

// Mount:

//   offset 0xA28

//   Method$GetAllByType<MountItemData, CompanionItemType>

// ---------------------------------------------------------------------------

0x7108CB412C    ADRP  X0,  0x710ABE7000

0x7108CB4130    ADD   X0,  X0, #0x990

0x7108CB4134    MOV   W1,  #1





// Long call to metadata warm-up helper at 0x7100B4C1B0

0x7108CB4138    ADRP  X8,  0x7100B4C000

0x7108CB413C    ADD   X8,  X8, #0x1B0

0x7108CB4140    BLR   X8





// Get ItemDatabase.Instance

0x7108CB4144    BL    0x7104A8A200





// ---------------------------------------------------------------------------

// CHANGE POINT B: ItemType

//

// PlayerHouse: Building  = 2

// Pet:         Companion = 12

// Mount:       Companion = 12

// ---------------------------------------------------------------------------

0x7108CB4148    MOV   W1,  #2





// ---------------------------------------------------------------------------

// CHANGE POINT C: SubType

//

// PlayerHouse: BuildingItemType.PlayerHouse = 5

// Pet:         CompanionItemType.Pet         = 0

// Mount:       CompanionItemType.Mount       = 3

// ---------------------------------------------------------------------------

0x7108CB414C    MOV   W8,  #5

0x7108CB4150    STR   W8,  [SP, #0x10]

0x7108CB4154    ADD   X2,  SP, #0x10





// ---------------------------------------------------------------------------

// CHANGE POINT D: Load the same Method$ slot used at Point A

//

// PlayerHouse: offset 0x990

// Pet:         offset 0xA40

// Mount:       offset 0xA28

// ---------------------------------------------------------------------------

0x7108CB4158    ADRP  X3,  0x710ABE7000

0x7108CB415C    LDR   X3,  [X3, #0x990]





// Call shared generic GetAllByType<TData,TSubType>

0x7108CB4160    BL    0x7103677620





// Prepare array loop

0x7108CB4164    ADD   X20, X0, #0x20

0x7108CB4168    LDR   W21, [X0, #0x18]

0x7108CB416C    MOV   W22, #0





// Load current ItemData and read Item

0x7108CB4170    LDR   X0,  [X20, X22, LSL #3]

0x7108CB4174    LDR   W1,  [X0, #0x18]





// Client.DebugAddItem(item, 1, default)

0x7108CB4178    MOV   X0,  X19

0x7108CB417C    MOV   W2,  #1

0x7108CB4180    MOV   X3,  XZR

0x7108CB4184    BL    0x7105B5DD30





// Loop control

0x7108CB4188    ADD   W22, W22, #1

0x7108CB418C    CMP   W22, W21

0x7108CB4190    B.LT  0x7108CB4170





// Restore original state

0x7108CB4194    LDP   X21, X22, [SP], #0x20

0x7108CB4198    LDP   X19, X20, [SP], #0x10

0x7108CB419C    LDP   X0,  X30, [SP], #0x10

0x7108CB41A0    RET

[/CODE]



[/SPOILER]



[SPOILER="13. Pet and Mount changes"]



To convert the PlayerHouse configuration to Pet, change all four points.



Pet



[CODE]

Point A:

0x7108CB4130    ADD X0, X0, #0xA40



Point B:

0x7108CB4148    MOV W1, #12



Point C:

0x7108CB414C    MOV W8, #0



Point D:

0x7108CB415C    LDR X3, [X3,#0xA40]

[/CODE]



This represents:



[CODE]

GetAllByType<

    PetItemData,

    CompanionItemType

>(

    ItemType.Companion,

    CompanionItemType.Pet

)

[/CODE]



To convert the configuration to Mount:



Mount



[CODE]

Point A:

0x7108CB4130    ADD X0, X0, #0xA28



Point B:

0x7108CB4148    MOV W1, #12



Point C:

0x7108CB414C    MOV W8, #3



Point D:

0x7108CB415C    LDR X3, [X3,#0xA28]

[/CODE]



This represents:



[CODE]

GetAllByType<

    MountItemData,

    CompanionItemType

>(

    ItemType.Companion,

    CompanionItemType.Mount

)

[/CODE]



No other part of the routine changes.



[/SPOILER]



[SPOILER="14. Version updates and adding another SubType"]



The following values are version-specific:



The generic implementation address
The metadata warm-up helper address
The Method$ slot addresses
The ItemDatabase functions
The Client.DebugAddItem function
The hook and code-cave addresses


The current generic implementation is:



[CODE]

0x7103677620

[/CODE]



The current warm-up helper is:



[CODE]

0x7100B4C1B0

[/CODE]



The current Method$ entries are:



[CODE]

BuildingItemData, BuildingItemType

    0x710ABE7990



PetItemData, CompanionItemType

    0x710ABE7A40



MountItemData, CompanionItemType

    0x710ABE7A28

[/CODE]



Do not assume that these addresses remain valid after an update.



To create another SubType configuration, identify:



The broad ItemType.
The required SubType enum and numeric value.
The concrete ItemDataType.
The Method$ entry for GetAllByType<ItemDataType, SubTypeEnum>.
The shared generic implementation address.


Then update all four configuration points.



The warm-up call is included because it reproduces the metadata-initialization pattern used by the game's own generated code.



I did not separately test a version that omits the warm-up step, so it should not be described as experimentally proven that every omission will crash.



As with the earlier GetAll codes, only one configuration should occupy this hook and code-cave location at a time.



[/SPOILER]



[/SPOILER]
