Disney Dreamlight Valley [0100D39012C1A000]

  • Thread starter Thread starter morarin
  • Start date Start date
  • Views Views 30,923
  • Replies Replies 193
  • Likes Likes 33
Disney Dreamlight Valley v1.21.0 BID=45FD4E5B488E96F6

Hi all, update of @morarin code using code updater, this is what i get, not all code are tested.

This is 1st time I try to used code updater, any code issue please report & discuss here

Reminder: Before using any cheat codes, be sure to back up your save data. You use cheat codes at your own risk.
Great thanks for the codes just seems the master code doesn't seem to like the game it crashes the game very quick but thank you for trying and thank you for the codes 🙏
 
  • Like
Reactions: mauroalexand
It seems il2CppDumper doesn't support the latest version of this game. This makes it extremely difficult for me to create new cheat codes. While I can continue updating existing cheat codes, I'll have to halt work on several new ones I was trying. However, I'm not giving up on creating new cheat codes. Even though I have no programming experience whatsoever, I'm planning to learn from scratch and attempt to update il2CppDumper myself. Honestly, that's a pretty unrealistic goal for me right now, and even if I succeed, it'll likely take a very long time, so please keep your expectations tempered.
many tools can extract the main file from the latest UPD.nsp or UPD.nsz file. for instance the NSGame Manager 13.3.3.22ff or use zzpong cheat code updater . both of the two tools need latest prod.keys file to open latest .nsp or .nsz (22.0.0 or 21.2.0)
 
Hello everyone, again

It has been a while. As I mentioned in my previous post, I had completely stepped away from the game. However, the recent update on June 3rd caught my attention, and I decided to boot up Disney Dreamlight Valley for the first time in a long while. To my surprise, it was incredibly relaxing and turned out to be exactly the kind of rest I needed.

To play the game more casually, I generated some codes for myself. At the same time, I noticed that no one had taken over sharing codes since my departure. It honestly made me feel bad to see that the gaming experience had significantly dropped for many of you who used to enjoy the game with them. Because of this, I felt the desire to start sharing my codes with you all again.

So, I am officially lifting my hiatus. To ensure I don't push myself too hard and can maintain a healthy balance, I will only share codes when I have the spare time.

If you wish to use my codes moving forward, please accept the following ground rules:

  • No guarantee for every version: If I don't have time, I will simply skip updating for that version.
  • No hotfix updates: I generally will not update codes for minor patches (where the main version number doesn't change).
  • Priority on low-maintenance codes: My priority will always be codes that can be updated automatically or require very little effort.
  • Complex codes come last: I will only release the "Unlock All" or "Vanellope" codes if I have extra time.
  • Longer wait times: Please do not expect updates within a few days of a patch like before.
  • Radio silence: When I am busy, I will likely go off the grid and be completely unreachable.

I am glad to be back and sharing what I can. I hope my codes help you enjoy the game to the fullest once again!
 
Last edited by morarin,
Hello everyone, again

It has been a while. As I mentioned in my previous post, I had completely stepped away from the game. However, the recent update on June 3rd caught my attention, and I decided to boot up Disney Dreamlight Valley for the first time in a long while. To my surprise, it was incredibly relaxing and turned out to be exactly the kind of rest I needed.

To play the game more casually, I generated some codes for myself. At the same time, I noticed that no one had taken over sharing codes since my departure. It honestly made me feel bad to see that the gaming experience had significantly dropped for many of you who used to enjoy the game with them. Because of this, I felt the desire to start sharing my codes with you all again.

So, I am officially lifting my hiatus. To ensure I don't push myself too hard and can maintain a healthy balance, I will only share codes when I have the spare time.

If you wish to use my codes moving forward, please accept the following ground rules:


  • No guarantee for every version: If I don't have time, I will simply skip updating for that version.
  • No hotfix updates: I generally will not update codes for minor patches (where the main version number doesn't change).
  • Priority on low-maintenance codes: My priority will always be codes that can be updated automatically or require very little effort.
  • Complex codes come last: I will only release the "Get All" or "Vanellope" codes if I have extra time.
  • Longer wait times: Please do not expect updates within a few days of a patch like before.
  • Radio silence: When I am busy, I will likely go off the grid and be completely unreachable.

I am glad to be back and sharing what I can. I hope my codes help you enjoy the game to the fullest once again.
Seeing you appear is like seeing hope. Welcome back.
I'm really looking forward to the cheat codes for version 1.23.0. I'm still on 1.20.11.
 
  • Like
Reactions: morarin
DDV_Update23_KeyArt.png

{MasterCode}
04000000 054B7BAC 6B1302A8
04000000 072427C0 A9BA7BFD
04000000 072427C4 F9000BFB
04000000 054A97D0 3607F500
04000000 04E521DC 97FFFE41
04000000 04E55FD8 94192236
04000000 04D43240 D10283FF
04000000 04D434B0 D101C3FF
04000000 053973A4 39412268
04000000 053982E4 39412288
04000000 0538BCCC 394092C8
04000000 05382428 B9401F48
04000000 032F4F04 F9406800
04000000 032F4F08 B40002A0
04000000 032F4F0C B9402041
04000000 032F4F10 AA1F03E2
04000000 032F4F14 9400229B
04000000 032F4F18 F9406E60
04000000 032F4F1C B4000200
04000000 032F4F20 AA1F03E1
04000000 04D1C140 2A0003F5
04000000 04D1C1E4 39411108
04000000 04D1C214 7100051F
04000000 04D1C218 1A9F17E8
04000000 04D1C230 54000141
04000000 04D1C234 52800068
04000000 04CFD518 97FAA2AE
04000000 04CFD820 944F6E3C
04000000 04D074E0 A9BB7BFD
04000000 04D07840 D101C3FF
04000000 04D517D8 F8018D00
04000000 04E72380 97D35758
04000000 04E729BC 547135CB
04000000 0537E75C 0B180101
04000000 054D5E4C B9402A78
04000000 054D5E50 0B140316
04000000 053107A4 B94026E8
04000000 053107AC 0B150108
04000000 054A0994 0B180108
04000000 054A0998 F81F03BF
04000000 054A438C 1A89B2B8
04000000 054A4394 1A89B115
04000000 05DCE5B8 2A0303F5
04000000 07EABE90 1A9F17E0
04000000 07EC7264 71000D1F
04000000 07EC7268 1A9F17E0
04000000 058FAFA8 54CA8861
04000000 05DC0D94 5400032D
04000000 05DC427C 6B08013F
04000000 05DC4280 540000AA
04000000 05DC4284 2A1F03E0
04000000 05056C8C 37000140
04000000 05056CC8 54000081
04000000 05057088 B9403108
04000000 050571AC B940016B
04000000 07B15AD8 AA1303E0
04000000 04CAA488 2A1502C8
04000000 054ABDA8 540005E1
04000000 054ABE60 54FFFA60
04000000 054ABDEC 2A180108
04000000 04F28180 1A9F07E0
04000000 04F281AC 52800020
04000000 04F2A010 3707F380
04000000 04F2C07C 36003060
04000000 04F2CC84 9415DD17
04000000 0555ABCC 360014C0
04000000 035DA7D0 17FFF0F4

[R MoveSpeed x2]
04000000 034B29EC 1E204140
04000000 034B29F0 1E204161
04000000 034B29F8 1E204182
80000080
04000000 034B29EC 1E2A2940
04000000 034B29F0 1E2B2961
04000000 034B29F8 1E2C2982
20000000

[EnergyNoDecrease]
04000000 054B7BAC 6B1F02A8

[CurrencyNoDecrease]
04000000 072427C0 52800000
04000000 072427C4 D65F03C0

[R PickupToMax]
04000000 04BA561C B94017FA
04000000 04BA5844 4B19035A
80000080
04000000 04BA561C 2A1B03FA
04000000 04BA5844 2A1F03FA
20000000

[ZL NoConsumeItems]
04000000 04BA5FD0 D10283FF
04000000 04BA5FD4 A9047BFD
04000000 04BA6970 D10243FF
04000000 04BA6974 A9037BFD
80000100
04000000 04BA5FD0 52800020
04000000 04BA5FD4 D65F03C0
04000000 04BA6970 52800020
04000000 04BA6974 D65F03C0
20000000

[ShowAllCraftingRecipe]
04000000 054A97D0 D503201F

[FreeCraft]
04000000 04E521DC 52800000
04000000 04E55FD8 52800020

[CookKeepItems]
04000000 04D43240 D65F03C0
04000000 04D434B0 D65F03C0

[AlwaysCriticalSuccess]
04000000 053973A4 52800028
04000000 053982E4 52800028

[AlwaysBurning]
04000000 0538BCCC 52800028

[AlwaysActivityBonusRewards]
04000000 05382428 52807D08

[EasyFishing]
04000000 032F4F04 F9406660
04000000 032F4F08 AA1F03E1
04000000 032F4F0C 94001B91
04000000 032F4F10 F9406660
04000000 032F4F14 52800001
04000000 032F4F18 AA1F03E2
04000000 032F4F1C 94001B39
04000000 032F4F20 1400000C

[--SectionStart:ForceFishRarity--]
00000000 00000000 00000000
[ForceNormalFish]
04000000 04D1C140 52800035
04000000 04D1C1E4 52800008
04000000 04D1C214 7100051F
04000000 04D1C218 1A9F07E8
04000000 04D1C230 54000140
04000000 04D1C234 52800028

[ForceUncommonFish]
04000000 04D1C140 52800035
04000000 04D1C1E4 52800008
04000000 04D1C214 7100091F
04000000 04D1C218 1A9F07E8
04000000 04D1C230 54000140
04000000 04D1C234 52800048

[ForceRareFish]
04000000 04D1C140 52800035
04000000 04D1C1E4 52800008
04000000 04D1C214 71000D1F
04000000 04D1C218 1A9F07E8
04000000 04D1C230 54000140
[--SectionEnd:ForceFishRarity--]
00000000 00000000 00000000

[EasyGardening]
04000000 04CFD518 52800020
04000000 04CFD820 D503201F

[InfHarvesting]
04000000 04D074E0 D65F03C0
04000000 04D07840 D65F03C0

[InfMiningRock]
04000000 04D517D8 F8018D1F

[EasyUnlockCritter]
04000000 04E72380 52800020
04000000 04E729BC D503201F

[PetFriendshipMax(add)]
04000000 0537E75C 2A1503E1

[MountBondMax(add)]
04000000 054D5E4C 52A00036
04000000 054D5E50 729C6CD6

[FriendshipMax(add)]
04000000 053107A4 52A00028
04000000 053107AC 729C6CC8

[XPMax(add)]
04000000 054A0994 529FD008
04000000 054A0998 72A001E8

[CurrencyMax(add)]
04000000 054A438C 1A89B138
04000000 054A4394 1A89B135

[EasyClaimDuties]
04000000 05DCE5B8 52800035
04000000 07EABE90 52800020
04000000 07EC7264 7100111F
04000000 07EC7268 1A9F07E0
04000000 058FAFA8 D503201F

[ClaimAllAchievements]
04000000 05DC0D94 D503201F
04000000 05DC427C B9007668
04000000 05DC4280 B9009268
04000000 05DC4284 14000004

[--SectionStart:EasyScramblecoin--]
00000000 00000000 00000000
[6Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 528000CB

[12Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 5280018B

[15Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 528001EB

[18Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 5280024B

[21Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 528002AB

[50Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 5280064B
[--SectionEnd:EasyScramblecoin--]
00000000 00000000 00000000

[--SectionStart:GetAllCodes--]
00000000 00000000 00000000
[GetAllClothing]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528000A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllGliders]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528000E1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllFacePaint&Hair]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528001C1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllTool&Accessory]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800161
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllFurniture999]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF57F4
04000000 08CB4120 A9BF5FF6
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800081
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A97
04000000 08CB414C F9405E60
04000000 08CB4150 F9401400
04000000 08CB4154 B9401AE1
04000000 08CB4158 AA1F03E2
04000000 08CB415C 971FA979
04000000 08CB4160 52807CE2
04000000 08CB4164 6B000042
04000000 08CB4168 540000AD
04000000 08CB416C AA1303E0
04000000 08CB4170 B9401AE1
04000000 08CB4174 AA1F03E3
04000000 08CB4178 973AA6EE
04000000 08CB417C 110006D6
04000000 08CB4180 6B1502DF
04000000 08CB4184 54FFFE2B
04000000 08CB4188 A8C15FF6
04000000 08CB418C A8C157F4
04000000 08CB4190 A8C17BF3
04000000 08CB4194 AA1303E0
04000000 08CB4198 D65F03C0

[GetAllWallpaper&Flooring]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800201
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllPlayerHouse]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BE5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C F000F980
04000000 08CB4130 91264000
04000000 08CB4134 52800021
04000000 08CB4138 90FBF4C8
04000000 08CB413C 9106C108
04000000 08CB4140 D63F0100
04000000 08CB4144 96F7582F
04000000 08CB4148 52800041
04000000 08CB414C 528000A8
04000000 08CB4150 B90013E8
04000000 08CB4154 910043E2
04000000 08CB4158 F000F983
04000000 08CB415C F944C863
04000000 08CB4160 96A70D30
04000000 08CB4164 91008014
04000000 08CB4168 B9401815
04000000 08CB416C 52800016
04000000 08CB4170 F8767A80
04000000 08CB4174 B9401801
04000000 08CB4178 AA1303E0
04000000 08CB417C 52800022
04000000 08CB4180 AA1F03E3
04000000 08CB4184 973AA6EB
04000000 08CB4188 110006D6
04000000 08CB418C 6B1502DF
04000000 08CB4190 54FFFF0B
04000000 08CB4194 A8C25BF5
04000000 08CB4198 A8C153F3
04000000 08CB419C A8C17BE0
04000000 08CB41A0 D65F03C0

[GetAllCompanion]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BE5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C F000F980
04000000 08CB4130 91290000
04000000 08CB4134 52800021
04000000 08CB4138 90FBF4C8
04000000 08CB413C 9106C108
04000000 08CB4140 D63F0100
04000000 08CB4144 96F7582F
04000000 08CB4148 52800181
04000000 08CB414C 52800008
04000000 08CB4150 B90013E8
04000000 08CB4154 910043E2
04000000 08CB4158 F000F983
04000000 08CB415C F9452063
04000000 08CB4160 96A70D30
04000000 08CB4164 91008014
04000000 08CB4168 B9401815
04000000 08CB416C 52800016
04000000 08CB4170 F8767A80
04000000 08CB4174 B9401801
04000000 08CB4178 AA1303E0
04000000 08CB417C 52800022
04000000 08CB4180 AA1F03E3
04000000 08CB4184 973AA6EB
04000000 08CB4188 110006D6
04000000 08CB418C 6B1502DF
04000000 08CB4190 54FFFF0B
04000000 08CB4194 A8C25BF5
04000000 08CB4198 A8C153F3
04000000 08CB419C A8C17BE0
04000000 08CB41A0 D65F03C0

[GetAllMount]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BE5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C F000F980
04000000 08CB4130 9128A000
04000000 08CB4134 52800021
04000000 08CB4138 90FBF4C8
04000000 08CB413C 9106C108
04000000 08CB4140 D63F0100
04000000 08CB4144 96F7582F
04000000 08CB4148 52800181
04000000 08CB414C 52800068
04000000 08CB4150 B90013E8
04000000 08CB4154 910043E2
04000000 08CB4158 F000F983
04000000 08CB415C F9451463
04000000 08CB4160 96A70D30
04000000 08CB4164 91008014
04000000 08CB4168 B9401815
04000000 08CB416C 52800016
04000000 08CB4170 F8767A80
04000000 08CB4174 B9401801
04000000 08CB4178 AA1303E0
04000000 08CB417C 52800022
04000000 08CB4180 AA1F03E3
04000000 08CB4184 973AA6EB
04000000 08CB4188 110006D6
04000000 08CB418C 6B1502DF
04000000 08CB4190 54FFFF0B
04000000 08CB4194 A8C25BF5
04000000 08CB4198 A8C153F3
04000000 08CB419C A8C17BE0
04000000 08CB41A0 D65F03C0

[GetAllMountGear]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528002A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllSkin]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800221
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllMotif]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800141
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllPhotoFrame]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800261
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllCookingRecipe]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528019A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllMemory]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 04CAA488 2A1F03E8
04000000 054ABDA8 D503201F
04000000 054ABE60 17FFFFD3
04000000 054ABDEC 94E020E4
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528001A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0
04000000 08CB417C A9BF07E0
04000000 08CB4180 A9BF0FE2
04000000 08CB4184 96F7581F
04000000 08CB4188 AA1503E1
04000000 08CB418C 96F745D1
04000000 08CB4190 B9406809
04000000 08CB4194 12800008
04000000 08CB4198 5280040A
04000000 08CB419C 4B09014A
04000000 08CB41A0 1ACA2508
04000000 08CB41A4 A8C10FE2
04000000 08CB41A8 A8C107E0
04000000 08CB41AC 171FDF11

[--SectionEnd:GetAllCodes--]
00000000 00000000 00000000

[--SectionStart:FixCodes--]
00000000 00000000 00000000
[SellToTrash]
04000000 04F28180 2A1F03E0
04000000 04F281AC 2A1F03E0
04000000 04F2A010 17FFFF9C
04000000 04F2C07C D503201F
04000000 04F2CC84 52800000

[FixMissionRewards]
04000000 0555ABCC D503201F

[WelcomeVanellope]
04000000 035DA7D0 B4FE1E81
04000000 035DA7D4 155B6677
04000000 08CB41B0 B9402028
04000000 08CB41B4 7100051F
04000000 08CB41B8 54914F41
04000000 08CB41BC A9BF7BF3
04000000 08CB41C0 A9BF57F4
04000000 08CB41C4 A9BF5FF6
04000000 08CB41C8 A9BF67F8
04000000 08CB41CC A9BF6FFA
04000000 08CB41D0 AA0003F3
04000000 08CB41D4 F9400C28
04000000 08CB41D8 B9401914
04000000 08CB41DC 96A48A71
04000000 08CB41E0 96A460AC
04000000 08CB41E4 F9401800
04000000 08CB41E8 2A1403E1
04000000 08CB41EC AA1F03E2
04000000 08CB41F0 9721344C
04000000 08CB41F4 AA0003F4
04000000 08CB41F8 97419E26
04000000 08CB41FC F9400C08
04000000 08CB4200 F9400908
04000000 08CB4204 B9401915
04000000 08CB4208 F9400909
04000000 08CB420C 91008137
04000000 08CB4210 52800016
04000000 08CB4214 6B1502DF
04000000 08CB4218 5400042A
04000000 08CB421C F8767AEA
04000000 08CB4220 F9400D4B
04000000 08CB4224 F940096B
04000000 08CB4228 B9401978
04000000 08CB422C F940096C
04000000 08CB4230 9100819A
04000000 08CB4234 52800019
04000000 08CB4238 6B18033F
04000000 08CB423C 540002CA
04000000 08CB4240 F8797B40
04000000 08CB4244 B9402801
04000000 08CB4248 7100043F
04000000 08CB424C 54000060
04000000 08CB4250 7100083F
04000000 08CB4254 540001C1
04000000 08CB4258 F9403C0D
04000000 08CB425C B94049A1
04000000 08CB4260 71033C3F
04000000 08CB4264 540000A0
04000000 08CB4268 7102303F
04000000 08CB426C 54000101
04000000 08CB4270 528001C1
04000000 08CB4274 14000002
04000000 08CB4278 528001A1
04000000 08CB427C F94019A3
04000000 08CB4280 AA1403E2
04000000 08CB4284 AA1303E0
04000000 08CB4288 96A498CA
04000000 08CB428C 11000739
04000000 08CB4290 17FFFFEA
04000000 08CB4294 110006D6
04000000 08CB4298 17FFFFDF
04000000 08CB429C A8C16FFA
04000000 08CB42A0 A8C167F8
04000000 08CB42A4 A8C15FF6
04000000 08CB42A8 A8C157F4
04000000 08CB42AC A8C17BF3
04000000 08CB42B0 D65F03C0
[--SectionEnd:FixCodes--]
00000000 00000000 00000000
[Update: June 5, 2026]
Fixed: [GetAllPlayerHouse], [GetAllCompanion], [GetAllMount].
Note: The previous versions caused crashes. Please use the new ones.






Note: The required XP points have been updated following the player max level cap increase from 40 to 50 in v1.23.0.
LevelTotal XP required to reach levelXP required for next level
30365,70025,600
31391,30026,400
32417,70027,300
33445,00028,100
34473,10029,000
35502,10029,800
36531,90030,800
37562,70031,500
38594,20032,500
39626,70033,300
40660,00034,300
41694,30035,300
42729,60036,300
43765,90037,300
44803,20038,300
45841,50039,300
46880,80040,300
47921,10041,300
48962,40042,300
491,004,70043,300
501,048,000
 

Attachments

Last edited by morarin,
Using your explanation for the fishing, I was able to update my game codes all except most of the "get all" codes. When time allows for you, a walkthrough of how you made the vanelope cheat, and maybe how you did one of the big "get all" cheats would be extremely helpful if you're up to it. No rush because I have a long drawn out method that works, but it can definitely be easier than I'm making it. Thanks!
View attachment 576477
{MasterCode}
04000000 054B7BAC 6B1302A8
04000000 072427C0 A9BA7BFD
04000000 072427C4 F9000BFB
04000000 054A97D0 3607F500
04000000 04E521DC 97FFFE41
04000000 04E55FD8 94192236
04000000 04D43240 D10283FF
04000000 04D434B0 D101C3FF
04000000 053973A4 39412268
04000000 053982E4 39412288
04000000 0538BCCC 394092C8
04000000 05382428 B9401F48
04000000 032F4F04 F9406800
04000000 032F4F08 B40002A0
04000000 032F4F0C B9402041
04000000 032F4F10 AA1F03E2
04000000 032F4F14 9400229B
04000000 032F4F18 F9406E60
04000000 032F4F1C B4000200
04000000 032F4F20 AA1F03E1
04000000 04D1C140 2A0003F5
04000000 04D1C1E4 39411108
04000000 04D1C214 7100051F
04000000 04D1C218 1A9F17E8
04000000 04D1C230 54000141
04000000 04D1C234 52800068
04000000 04CFD518 97FAA2AE
04000000 04CFD820 944F6E3C
04000000 04D074E0 A9BB7BFD
04000000 04D07840 D101C3FF
04000000 04D517D8 F8018D00
04000000 04E72380 97D35758
04000000 04E729BC 547135CB
04000000 0537E75C 0B180101
04000000 054D5E4C B9402A78
04000000 054D5E50 0B140316
04000000 053107A4 B94026E8
04000000 053107AC 0B150108
04000000 054A0994 0B180108
04000000 054A0998 F81F03BF
04000000 054A438C 1A89B2B8
04000000 054A4394 1A89B115
04000000 05DCE5B8 2A0303F5
04000000 07EABE90 1A9F17E0
04000000 07EC7264 71000D1F
04000000 07EC7268 1A9F17E0
04000000 058FAFA8 54CA8861
04000000 05DC0D94 5400032D
04000000 05DC427C 6B08013F
04000000 05DC4280 540000AA
04000000 05DC4284 2A1F03E0
04000000 05056C8C 37000140
04000000 05056CC8 54000081
04000000 05057088 B9403108
04000000 050571AC B940016B
04000000 07B15AD8 AA1303E0
04000000 04CAA488 2A1502C8
04000000 054ABDA8 540005E1
04000000 054ABE60 54FFFA60
04000000 054ABDEC 2A180108
04000000 04F28180 1A9F07E0
04000000 04F281AC 52800020
04000000 04F2A010 3707F380
04000000 04F2C07C 36003060
04000000 04F2CC84 9415DD17
04000000 0555ABCC 360014C0
04000000 035DA7D0 17FFF0F4

[R MoveSpeed x2]
04000000 034B29EC 1E204140
04000000 034B29F0 1E204161
04000000 034B29F8 1E204182
80000080
04000000 034B29EC 1E2A2940
04000000 034B29F0 1E2B2961
04000000 034B29F8 1E2C2982
20000000

[EnergyNoDecrease]
04000000 054B7BAC 6B1F02A8

[CurrencyNoDecrease]
04000000 072427C0 52800000
04000000 072427C4 D65F03C0

[R PickupToMax]
04000000 04BA561C B94017FA
04000000 04BA5844 4B19035A
80000080
04000000 04BA561C 2A1B03FA
04000000 04BA5844 2A1F03FA
20000000

[ZL NoConsumeItems]
04000000 04BA5FD0 D10283FF
04000000 04BA5FD4 A9047BFD
04000000 04BA6970 D10243FF
04000000 04BA6974 A9037BFD
80000100
04000000 04BA5FD0 52800020
04000000 04BA5FD4 D65F03C0
04000000 04BA6970 52800020
04000000 04BA6974 D65F03C0
20000000

[ShowAllCraftingRecipe]
04000000 054A97D0 D503201F

[FreeCraft]
04000000 04E521DC 52800000
04000000 04E55FD8 52800020

[CookKeepItems]
04000000 04D43240 D65F03C0
04000000 04D434B0 D65F03C0

[AlwaysCriticalSuccess]
04000000 053973A4 52800028
04000000 053982E4 52800028

[AlwaysBurning]
04000000 0538BCCC 52800028

[AlwaysActivityBonusRewards]
04000000 05382428 52807D08

[EasyFishing]
04000000 032F4F04 F9406660
04000000 032F4F08 AA1F03E1
04000000 032F4F0C 94001B91
04000000 032F4F10 F9406660
04000000 032F4F14 52800001
04000000 032F4F18 AA1F03E2
04000000 032F4F1C 94001B39
04000000 032F4F20 1400000C

[--SectionStart:ForceFishRarity--]
00000000 00000000 00000000
[ForceNormalFish]
04000000 04D1C140 52800035
04000000 04D1C1E4 52800008
04000000 04D1C214 7100051F
04000000 04D1C218 1A9F07E8
04000000 04D1C230 54000140
04000000 04D1C234 52800028

[ForceUncommonFish]
04000000 04D1C140 52800035
04000000 04D1C1E4 52800008
04000000 04D1C214 7100091F
04000000 04D1C218 1A9F07E8
04000000 04D1C230 54000140
04000000 04D1C234 52800048

[ForceRareFish]
04000000 04D1C140 52800035
04000000 04D1C1E4 52800008
04000000 04D1C214 71000D1F
04000000 04D1C218 1A9F07E8
04000000 04D1C230 54000140
[--SectionEnd:ForceFishRarity--]
00000000 00000000 00000000

[EasyGardening]
04000000 04CFD518 52800020
04000000 04CFD820 D503201F

[InfHarvesting]
04000000 04D074E0 D65F03C0
04000000 04D07840 D65F03C0

[InfMiningRock]
04000000 04D517D8 F8018D1F

[EasyUnlockCritter]
04000000 04E72380 52800020
04000000 04E729BC D503201F

[PetFriendshipMax(add)]
04000000 0537E75C 2A1503E1

[MountBondMax(add)]
04000000 054D5E4C 52A00036
04000000 054D5E50 729C6CD6

[FriendshipMax(add)]
04000000 053107A4 52A00028
04000000 053107AC 729C6CC8

[XPMax(add)]
04000000 054A0994 529FD008
04000000 054A0998 72A001E8

[CurrencyMax(add)]
04000000 054A438C 1A89B138
04000000 054A4394 1A89B135

[EasyClaimDuties]
04000000 05DCE5B8 52800035
04000000 07EABE90 52800020
04000000 07EC7264 7100111F
04000000 07EC7268 1A9F07E0
04000000 058FAFA8 D503201F

[ClaimAllAchievements]
04000000 05DC0D94 D503201F
04000000 05DC427C B9007668
04000000 05DC4280 B9009268
04000000 05DC4284 14000004

[--SectionStart:EasyScramblecoin--]
00000000 00000000 00000000
[6Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 528000CB

[12Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 5280018B

[15Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 528001EB

[18Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 5280024B

[21Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 528002AB

[50Points]
04000000 05056C8C 1400000A
04000000 05056CC8 14000004
04000000 05057088 52800008
04000000 050571AC 5280064B
[--SectionEnd:EasyScramblecoin--]
00000000 00000000 00000000

[--SectionStart:GetAllCodes--]
00000000 00000000 00000000
[GetAllClothing]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528000A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllGliders]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528000E1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllFacePaint&Hair]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528001C1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllTool&Accessory]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800161
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllFurniture999]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF57F4
04000000 08CB4120 A9BF5FF6
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800081
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A97
04000000 08CB414C F9405E60
04000000 08CB4150 F9401400
04000000 08CB4154 B9401AE1
04000000 08CB4158 AA1F03E2
04000000 08CB415C 971FA979
04000000 08CB4160 52807CE2
04000000 08CB4164 6B000042
04000000 08CB4168 540000AD
04000000 08CB416C AA1303E0
04000000 08CB4170 B9401AE1
04000000 08CB4174 AA1F03E3
04000000 08CB4178 973AA6EE
04000000 08CB417C 110006D6
04000000 08CB4180 6B1502DF
04000000 08CB4184 54FFFE2B
04000000 08CB4188 A8C15FF6
04000000 08CB418C A8C157F4
04000000 08CB4190 A8C17BF3
04000000 08CB4194 AA1303E0
04000000 08CB4198 D65F03C0

[GetAllWallpaper&Flooring]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800201
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllPlayerHouse]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BE5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C F000F980
04000000 08CB4130 91264000
04000000 08CB4134 52800021
04000000 08CB4138 95FA601E
04000000 08CB413C 96F75831
04000000 08CB4140 52800041
04000000 08CB4144 528000A8
04000000 08CB4148 B90013E8
04000000 08CB414C 910043E2
04000000 08CB4150 F000F983
04000000 08CB4154 F944C863
04000000 08CB4158 96A70D32
04000000 08CB415C 91008014
04000000 08CB4160 B9401815
04000000 08CB4164 52800016
04000000 08CB4168 F8767A80
04000000 08CB416C B9401801
04000000 08CB4170 AA1303E0
04000000 08CB4174 52800022
04000000 08CB4178 AA1F03E3
04000000 08CB417C 973AA6ED
04000000 08CB4180 110006D6
04000000 08CB4184 6B1502DF
04000000 08CB4188 54FFFF0B
04000000 08CB418C A8C25BF5
04000000 08CB4190 A8C153F3
04000000 08CB4194 A8C17BE0
04000000 08CB4198 D65F03C0

[GetAllCompanion]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BE5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C F000F980
04000000 08CB4130 91290000
04000000 08CB4134 52800021
04000000 08CB4138 95FA601E
04000000 08CB413C 96F75831
04000000 08CB4140 52800181
04000000 08CB4144 52800008
04000000 08CB4148 B90013E8
04000000 08CB414C 910043E2
04000000 08CB4150 F000F983
04000000 08CB4154 F9452063
04000000 08CB4158 96A70D32
04000000 08CB415C 91008014
04000000 08CB4160 B9401815
04000000 08CB4164 52800016
04000000 08CB4168 F8767A80
04000000 08CB416C B9401801
04000000 08CB4170 AA1303E0
04000000 08CB4174 52800022
04000000 08CB4178 AA1F03E3
04000000 08CB417C 973AA6ED
04000000 08CB4180 110006D6
04000000 08CB4184 6B1502DF
04000000 08CB4188 54FFFF0B
04000000 08CB418C A8C25BF5
04000000 08CB4190 A8C153F3
04000000 08CB4194 A8C17BE0
04000000 08CB4198 D65F03C0

[GetAllMount]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BE5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C F000F980
04000000 08CB4130 9128A000
04000000 08CB4134 52800021
04000000 08CB4138 95FA601E
04000000 08CB413C 96F75831
04000000 08CB4140 52800181
04000000 08CB4144 52800068
04000000 08CB4148 B90013E8
04000000 08CB414C 910043E2
04000000 08CB4150 F000F983
04000000 08CB4154 F9451463
04000000 08CB4158 96A70D32
04000000 08CB415C 91008014
04000000 08CB4160 B9401815
04000000 08CB4164 52800016
04000000 08CB4168 F8767A80
04000000 08CB416C B9401801
04000000 08CB4170 AA1303E0
04000000 08CB4174 52800022
04000000 08CB4178 AA1F03E3
04000000 08CB417C 973AA6ED
04000000 08CB4180 110006D6
04000000 08CB4184 6B1502DF
04000000 08CB4188 54FFFF0B
04000000 08CB418C A8C25BF5
04000000 08CB4190 A8C153F3
04000000 08CB4194 A8C17BE0
04000000 08CB4198 D65F03C0

[GetAllMountGear]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528002A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllSkin]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800221
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllMotif]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800141
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllPhotoFrame]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 52800261
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllCookingRecipe]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528019A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0

[GetAllMemory]
04000000 07B15AD8 94467990
04000000 04CAE434 D503201F
04000000 04CAA488 2A1F03E8
04000000 054ABDA8 D503201F
04000000 054ABE60 17FFFFD3
04000000 054ABDEC 94E020E4
04000000 08CB4118 A9BF7BF3
04000000 08CB411C A9BF53F3
04000000 08CB4120 A9BF5BF5
04000000 08CB4124 96A460A3
04000000 08CB4128 AA0003F3
04000000 08CB412C 96F75835
04000000 08CB4130 528001A1
04000000 08CB4134 AA1F03E2
04000000 08CB4138 96F74792
04000000 08CB413C 91008014
04000000 08CB4140 B9401815
04000000 08CB4144 52800016
04000000 08CB4148 F8767A80
04000000 08CB414C B9401801
04000000 08CB4150 AA1303E0
04000000 08CB4154 52800022
04000000 08CB4158 AA1F03E3
04000000 08CB415C 973AA6F5
04000000 08CB4160 110006D6
04000000 08CB4164 6B1502DF
04000000 08CB4168 54FFFF0B
04000000 08CB416C A8C15BF5
04000000 08CB4170 A8C153F3
04000000 08CB4174 A8C17BE0
04000000 08CB4178 D65F03C0
04000000 08CB417C A9BF07E0
04000000 08CB4180 A9BF0FE2
04000000 08CB4184 96F7581F
04000000 08CB4188 AA1503E1
04000000 08CB418C 96F745D1
04000000 08CB4190 B9406809
04000000 08CB4194 12800008
04000000 08CB4198 5280040A
04000000 08CB419C 4B09014A
04000000 08CB41A0 1ACA2508
04000000 08CB41A4 A8C10FE2
04000000 08CB41A8 A8C107E0
04000000 08CB41AC 171FDF11

[--SectionEnd:GetAllCodes--]
00000000 00000000 00000000

[--SectionStart:FixCodes--]
00000000 00000000 00000000
[SellToTrash]
04000000 04F28180 2A1F03E0
04000000 04F281AC 2A1F03E0
04000000 04F2A010 17FFFF9C
04000000 04F2C07C D503201F
04000000 04F2CC84 52800000

[FixMissionRewards]
04000000 0555ABCC D503201F

[WelcomeVanellope]
04000000 035DA7D0 B4FE1E81
04000000 035DA7D4 155B6677
04000000 08CB41B0 B9402028
04000000 08CB41B4 7100051F
04000000 08CB41B8 54914F41
04000000 08CB41BC A9BF7BF3
04000000 08CB41C0 A9BF57F4
04000000 08CB41C4 A9BF5FF6
04000000 08CB41C8 A9BF67F8
04000000 08CB41CC A9BF6FFA
04000000 08CB41D0 AA0003F3
04000000 08CB41D4 F9400C28
04000000 08CB41D8 B9401914
04000000 08CB41DC 96A48A71
04000000 08CB41E0 96A460AC
04000000 08CB41E4 F9401800
04000000 08CB41E8 2A1403E1
04000000 08CB41EC AA1F03E2
04000000 08CB41F0 9721344C
04000000 08CB41F4 AA0003F4
04000000 08CB41F8 97419E26
04000000 08CB41FC F9400C08
04000000 08CB4200 F9400908
04000000 08CB4204 B9401915
04000000 08CB4208 F9400909
04000000 08CB420C 91008137
04000000 08CB4210 52800016
04000000 08CB4214 6B1502DF
04000000 08CB4218 5400042A
04000000 08CB421C F8767AEA
04000000 08CB4220 F9400D4B
04000000 08CB4224 F940096B
04000000 08CB4228 B9401978
04000000 08CB422C F940096C
04000000 08CB4230 9100819A
04000000 08CB4234 52800019
04000000 08CB4238 6B18033F
04000000 08CB423C 540002CA
04000000 08CB4240 F8797B40
04000000 08CB4244 B9402801
04000000 08CB4248 7100043F
04000000 08CB424C 54000060
04000000 08CB4250 7100083F
04000000 08CB4254 540001C1
04000000 08CB4258 F9403C0D
04000000 08CB425C B94049A1
04000000 08CB4260 71033C3F
04000000 08CB4264 540000A0
04000000 08CB4268 7102303F
04000000 08CB426C 54000101
04000000 08CB4270 528001C1
04000000 08CB4274 14000002
04000000 08CB4278 528001A1
04000000 08CB427C F94019A3
04000000 08CB4280 AA1403E2
04000000 08CB4284 AA1303E0
04000000 08CB4288 96A498CA
04000000 08CB428C 11000739
04000000 08CB4290 17FFFFEA
04000000 08CB4294 110006D6
04000000 08CB4298 17FFFFDF
04000000 08CB429C A8C16FFA
04000000 08CB42A0 A8C167F8
04000000 08CB42A4 A8C15FF6
04000000 08CB42A8 A8C157F4
04000000 08CB42AC A8C17BF3
04000000 08CB42B0 D65F03C0
[--SectionEnd:FixCodes--]
00000000 00000000 00000000


Note: The required XP points have been updated following the player max level cap increase from 40 to 50 in v1.23.0.
[TABLE=full]
[TR]
[th]Level[/th][th]Total XP required to reach level[/th][th]XP required for next level[/th]
[/TR]
[TR]
[td]30[/td][td]365,700[/td][td]25,600[/td]
[/TR]
[TR]
[td]31[/td][td]391,300[/td][td]26,400[/td]
[/TR]
[TR]
[td]32[/td][td]417,700[/td][td]27,300[/td]
[/TR]
[TR]
[td]33[/td][td]445,000[/td][td]28,100[/td]
[/TR]
[TR]
[td]34[/td][td]473,100[/td][td]29,000[/td]
[/TR]
[TR]
[td]35[/td][td]502,100[/td][td]29,800[/td]
[/TR]
[TR]
[td]36[/td][td]531,900[/td][td]30,800[/td]
[/TR]
[TR]
[td]37[/td][td]562,700[/td][td]31,500[/td]
[/TR]
[TR]
[td]38[/td][td]594,200[/td][td]32,500[/td]
[/TR]
[TR]
[td]39[/td][td]626,700[/td][td]33,300[/td]
[/TR]
[TR]
[td]40[/td][td]660,000[/td][td]34,300[/td]
[/TR]
[TR]
[td]41[/td][td]694,300[/td][td]35,300[/td]
[/TR]
[TR]
[td]42[/td][td]729,600[/td][td]36,300[/td]
[/TR]
[TR]
[td]43[/td][td]765,900[/td][td]37,300[/td]
[/TR]
[TR]
[td]44[/td][td]803,200[/td][td]38,300[/td]
[/TR]
[TR]
[td]45[/td][td]841,500[/td][td]39,300[/td]
[/TR]
[TR]
[td]46[/td][td]880,800[/td][td]40,300[/td]
[/TR]
[TR]
[td]47[/td][td]921,100[/td][td]41,300[/td]
[/TR]
[TR]
[td]48[/td][td]962,400[/td][td]42,300[/td]
[/TR]
[TR]
[td]49[/td][td]1,004,700[/td][td]43,300[/td]
[/TR]
[TR]
[td]50[/td][td]1,048,000[/td][td]—[/td]
[/TR]
[/TABLE]
 
  • Like
Reactions: morarin
Hello everyone, again

It has been a while. As I mentioned in my previous post, I had completely stepped away from the game. However, the recent update on June 3rd caught my attention, and I decided to boot up Disney Dreamlight Valley for the first time in a long while. To my surprise, it was incredibly relaxing and turned out to be exactly the kind of rest I needed.

To play the game more casually, I generated some codes for myself. At the same time, I noticed that no one had taken over sharing codes since my departure. It honestly made me feel bad to see that the gaming experience had significantly dropped for many of you who used to enjoy the game with them. Because of this, I felt the desire to start sharing my codes with you all again.

So, I am officially lifting my hiatus. To ensure I don't push myself too hard and can maintain a healthy balance, I will only share codes when I have the spare time.

If you wish to use my codes moving forward, please accept the following ground rules:


  • No guarantee for every version: If I don't have time, I will simply skip updating for that version.
  • No hotfix updates: I generally will not update codes for minor patches (where the main version number doesn't change).
  • Priority on low-maintenance codes: My priority will always be codes that can be updated automatically or require very little effort.
  • Complex codes come last: I will only release the "Get All" or "Vanellope" codes if I have extra time.
  • Longer wait times: Please do not expect updates within a few days of a patch like before.
  • Radio silence: When I am busy, I will likely go off the grid and be completely unreachable.

I am glad to be back and sharing what I can. I hope my codes help you enjoy the game to the fullest once again.
Thank you
 
Using your explanation for the fishing, I was able to update my game codes all except most of the "get all" codes. When time allows for you, a walkthrough of how you made the vanelope cheat, and maybe how you did one of the big "get all" cheats would be extremely helpful if you're up to it. No rush because I have a long drawn out method that works, but it can definitely be easier than I'm making it. Thanks!

This code was originally made for Vanellope's unlock quest, but strictly speaking, it is not really a "Vanellope-only" code. The actual purpose is more specific:
It forces the two DreamSnaps-related mission objectives to advance even while offline.
The two problematic steps are:
  • Opening the DreamSnaps menu/page to view the current DreamSnaps information.
  • Submitting something to DreamSnaps.
Both of these normally require an online connection. If the game is offline, those steps cannot be completed normally. So the point of the code is not to skip Vanellope's whole mission. It is only meant to handle those two online-only DreamSnaps blockers.
If another mission used the same kind of DreamSnaps-related objectives, the same idea could apply there too.

Why I used the tracked mission function
One of the first problems was: how do I tell the code which mission I want to process?
The game can have multiple active missions at the same time, but the player can only track one mission at once. That made the tracking system a convenient entry point. When the tracked activity changes, the game receives information about the newly tracked activity. So I searched dump.cs for a function related to that and found:
Code:
Mdl.Missions.MissionManager$$OnTrackedMissionChanged
In IDA, this function was very small. It basically just branched to:
Code:
Mdl.Missions.MissionManager$$RefreshCurrentFollower
That made it a good hook point:
  • It runs when the player selects a tracked mission.
  • The tracked activity is passed as an argument.
  • If the tracked activity is a mission, the missionId can be read from that argument.
  • The original function is small, so it is easy to preserve the original behavior.
  • It was also convenient for a code cave hook.
The missionId itself is not the real filter. It is just a convenient way to get the MissionSlot for the mission the player is currently tracking.

Getting the missionId
The tracked activity object can represent different kinds of tracked activities, not just missions. So the code first checks whether the tracked activity is actually a mission:
Code:
TrackedActivity.activityCase_ == Mission
If it is not a mission, the code just returns to the original behavior. If it is a mission, the code reads the TrackedMission object and gets the missionId from it:
Code:
if trackedActivity.activityCase_ != Mission:
return RefreshCurrentFollower()

missionId = trackedActivity.activity_.missionId
Again, the missionId is only used to find the currently tracked MissionSlot. The code does not depend on a hardcoded Vanellope missionId.

Keeping the original behavior
After getting the missionId, the code still calls the function that the original code was going to call:
Code:
MissionManager.RefreshCurrentFollower()
The hook is not meant to replace the original behavior. It only adds extra logic after the normal tracked-mission update has happened.

Getting the current mission data
Once the code has the missionId, it gets the actual mission data from the profile. The path is roughly:
Code:
MissionManager
-> Profile
-> ProfileWorld
-> GetMissionSlot(missionId, null)
So the code gets the ProfileWorld and calls:
Code:
ProfileWorld.GetMissionSlot(missionId, null)
That returns the MissionSlot for the currently tracked mission.

Walking from the mission to the actual objective
The mission structure is nested. It is roughly:
Code:
MissionSlot
-> CurrentStep
-> SubSteps
-> Objectives
-> ObjectiveData
So the code gets the current step:
Code:
MissionSlot.get_CurrentStep()
Then it loops through the SubSteps, and inside each SubStep it loops through the Objectives. This is why the code has a double loop. The mission itself is not enough. I needed to reach the actual MissionObjective inside the current step.

Filtering the objectives
For each MissionObjective, the code first checks the status. It only handles:
Code:
Ongoing            = 1
ReadyToBeCompleted = 2
Anything else is skipped. Then it checks:
Code:
MissionObjective.Data.customStepCase_
For the DreamSnaps-related blockers, the relevant objective types are:
Code:
MenuAction      = 207
DesignChallenge = 140
In this quest, the MenuAction objective is the DreamSnaps menu/page step, and the DesignChallenge objective is the DreamSnaps submission-related step. So the logic is basically:
Code:
if customStepCase_ == MenuAction:
condition = MenuAction

else if customStepCase_ == DesignChallenge:
condition = ForceSkipDesignChallenge

else:
skip it
The condition values passed to the advance function are:
Code:
MenuAction               = 13
ForceSkipDesignChallenge = 14
This keeps the code focused on the two objective types that were blocking offline progress, instead of force-advancing unrelated mission steps that could have much bigger side effects.

Why I did not skip the whole mission
I did not want to force-complete the whole mission. That would be risky because some quest steps do more than just update the objective text. They can give items, unlock objects, initialize later quest data, or change the world state.
For example, Vanellope's quest includes a step where the player has to place Vanellope's house. If the mission was skipped too far, that step might never initialize correctly. In the worst case, the player could end up unable to place Vanellope's house properly.
That is why I chose to advance only the specific offline-blocking objectives instead of skipping the mission itself.

Why I used CheckForAdvanceStep
This was the part that took the most trial and error. There was also a more direct way to force the mission forward, but it did not trigger all of the events or notifications correctly.
For example, the objective could appear to advance, but later quest logic did not initialize properly. One bad result was that Vanellope's house was not added to the inventory when the quest reached the part where it should be placed. So directly forcing progress was not enough.
Mission progress is not just:
Code:
status = completed
There are other things tied to it:
  • objective completion handling
  • step advancement
  • event dispatch
  • notifications
  • UI updates
  • item or reward handling
  • next-step initialization
The function I ended up using was:
Code:
Mdl.Missions.MissionManager$$CheckForAdvanceStep
This function takes the condition, the MissionSlot, and the stepName:
Code:
MissionManager.CheckForAdvanceStep(
condition,
missionSlot,
stepName
)
So instead of simply editing the objective status, the code sends the objective through a function that checks and advances the mission step more properly. That made the forced progress work with the required event/notification behavior instead of only changing the visible state.

The workflow
In practice, the workflow was:
  • Choose a function where the target mission can be identified.
  • Use the tracked mission argument to get the missionId.
  • Use that missionId to get the MissionSlot.
  • From the MissionSlot, get the current step.
  • Use a double loop to reach the actual MissionObjective.
  • Filter only the DreamSnaps-related objective types.
  • Pass the matching condition to CheckForAdvanceStep.
So the code is not really a "complete Vanellope quest" code. It is closer to a targeted workaround for the two DreamSnaps objectives that normally cannot be completed offline.

Code:
// ============================================================================
// WelcomeVanellope
// Target: v1.23.0 [0100D39012C1A800][v3801088][UPD]
// Code Cave Address: 0x7108CB41B0
// ============================================================================

// --- [Block A] Hook (Mdl.Missions.MissionManager$$OnTrackedMissionChanged)
// Address: 0x71035DA7D0
// Original: B Mdl.Missions.MissionManager$$RefreshCurrentFollower (0x71035D6BA0)
0x71035DA7D0    CBZ   X1, 0x71035D6BA0              // If TrackedActivity is NULL, jump to original target
0x71035DA7D4    B     0x7108CB41B0                  // Jump to Code Cave

// --- [Block B] Code Cave (Start: 0x7108CB41B0) ------------------------------
// 1. Initial Type Check
0x7108CB41B0    LDR   W8, [X1, #0x20]               // W8 = TrackedActivity.activityCase_
0x7108CB41B4    CMP   W8, #1                        // ActivityCase == Mission (1)?
0x7108CB41B8    B.NE  0x71035D6BA0                  // If not, jump to RefreshCurrentFollower

// 2. Prologue
0x7108CB41BC    STP   X19, X30, [SP, #-0x10]!
0x7108CB41C0    STP   X20, X21, [SP, #-0x10]!
0x7108CB41C4    STP   X22, X23, [SP, #-0x10]!
0x7108CB41C8    STP   X24, X25, [SP, #-0x10]!
0x7108CB41CC    STP   X26, X27, [SP, #-0x10]!

0x7108CB41D0    MOV   X19, X0                       // X19 = MissionManager*
0x7108CB41D4    LDR   X8,  [X1, #0x18]              // X8 = TrackedActivity.activity_ (TrackedMission*)
0x7108CB41D8    LDR   W20, [X8, #0x18]              // W20 = missionId

// 3. Execute Original Intercepted Call
0x7108CB41DC    BL    0x71035D6BA0                  // Call RefreshCurrentFollower()

// 4. Retrieve ProfileWorld
0x7108CB41E0    BL    0x71035CC490                  // Call MissionManager.get_Profile()
0x7108CB41E4    LDR   X0,  [X0, #0x30]              // X0 = ProfileWorld* (Profile.world_)

// 5. Get MissionSlot
0x7108CB41E8    MOV   W1,  W20                      // Arg 1: missionId
0x7108CB41EC    MOV   X2,  XZR                      // Arg 2: predicate = NULL
0x7108CB41F0    BL    0x7105501320                  // Call ProfileWorld.GetMissionSlot()
0x7108CB41F4    MOV   X20, X0                       // X20 = MissionSlot*

// 6. Get Current MissionStep
0x7108CB41F8    BL    0x7105D1BA90                  // Call MissionSlot.get_CurrentStep()

// 7. Prepare Outer Loop (SubSteps)
0x7108CB41FC    LDR   X8,  [X0, #0x18]              // X8 = MissionStep.subSteps_
0x7108CB4200    LDR   X8,  [X8, #0x10]              // X8 = List<MissionSubStep>
0x7108CB4204    LDR   W21, [X8, #0x18]              // W21 = subStepCount
0x7108CB4208    LDR   X9,  [X8, #0x10]              // X9 = items array
0x7108CB420C    ADD   X23, X9,  #0x20               // X23 = first element address
0x7108CB4210    MOV   W22, #0                       // i = 0

// ===== Outer Loop Start =====
0x7108CB4214    CMP   W22, W21
0x7108CB4218    B.GE  0x7108CB429C                  // Exit outer loop if i >= count

0x7108CB421C    LDR   X10, [X23, X22, LSL #3]       // X10 = MissionSubStep*

// 8. Prepare Inner Loop (Objectives)
0x7108CB4220    LDR   X11, [X10, #0x18]             // X11 = MissionSubStep.objectives_
0x7108CB4224    LDR   X11, [X11, #0x10]             // X11 = List<MissionObjective>
0x7108CB4228    LDR   W24, [X11, #0x18]             // W24 = objectiveCount
0x7108CB422C    LDR   X12, [X11, #0x10]             // X12 = items array
0x7108CB4230    ADD   X26, X12, #0x20               // X26 = first element address
0x7108CB4234    MOV   W25, #0                       // j = 0

// ----- Inner Loop Start -----
0x7108CB4238    CMP   W25, W24
0x7108CB423C    B.GE  0x7108CB4294                  // Exit inner loop if j >= count

0x7108CB4240    LDR   X0,  [X26, X25, LSL #3]       // X0 = MissionObjective*

// 9. Process Objective State
0x7108CB4244    LDR   W1,  [X0, #0x28]              // W1 = MissionObjective.status_
0x7108CB4248    CMP   W1,  #1                       // status == Ongoing (1)?
0x7108CB424C    B.EQ  0x7108CB4258                  // If yes, proceed to logic
0x7108CB4250    CMP   W1,  #2                       // status == ReadyToBeCompleted (2)?
0x7108CB4254    B.NE  0x7108CB428C                  // If neither, skip objective

// 10. Check Custom Step Case
0x7108CB4258    LDR   X13, [X0, #0x78]              // X13 = MissionObjective.Data (MissionObjectiveData*)
0x7108CB425C    LDR   W1,  [X13, #0x48]             // W1 = customStepCase_
0x7108CB4260    CMP   W1,  #207                     // MenuAction (207)?
0x7108CB4264    B.EQ  0x7108CB4278                  // Jump to MenuAction override
0x7108CB4268    CMP   W1,  #140                     // DesignChallenge (140)?
0x7108CB426C    B.NE  0x7108CB428C                  // If neither, skip objective

// DesignChallenge Override
0x7108CB4270    MOV   W1,  #14                      // Condition = ForceSkipDesignChallenge (14)
0x7108CB4274    B     0x7108CB427C

// MenuAction Override
0x7108CB4278    MOV   W1,  #13                      // Condition = MenuAction (13)

// 11. Force Advance Step
0x7108CB427C    LDR   X3,  [X13, #0x30]             // Arg 4 (X3): stepName_
0x7108CB4280    MOV   X2,  X20                      // Arg 3 (X2): MissionSlot*
0x7108CB4284    MOV   X0,  X19                      // Arg 1 (X0): MissionManager*
0x7108CB4288    BL    0x71035DA5B0                  // Call MissionManager.CheckForAdvanceStep()

// Inner Loop Advance
0x7108CB428C    ADD   W25, W25, #1
0x7108CB4290    B     0x7108CB4238

// Outer Loop Advance
0x7108CB4294    ADD   W22, W22, #1
0x7108CB4298    B     0x7108CB4214

// 12. Epilogue
0x7108CB429C    LDP   X26, X27, [SP], #0x10
0x7108CB42A0    LDP   X24, X25, [SP], #0x10
0x7108CB42A4    LDP   X22, X23, [SP], #0x10
0x7108CB42A8    LDP   X20, X21, [SP], #0x10
0x7108CB42AC    LDP   X19, X30, [SP], #0x10
0x7108CB42B0    RET

This is a line-by-line style walkthrough of the final code. I will group repeated patterns, like register save/restore and loop increments, instead of explaining the exact same thing several times.

Block A: Hooking OnTrackedMissionChanged

Original function:

Code:
Mdl.Missions.MissionManager$$OnTrackedMissionChanged

Original behavior:

Code:
B Mdl.Missions.MissionManager$$RefreshCurrentFollower

So originally, this function just jumped directly to RefreshCurrentFollower.

The hook changes it to:

Code:
0x71035DA7D0    CBZ   X1, 0x71035D6BA0
0x71035DA7D4    B     0x7108CB41B0

Code:
CBZ X1, 0x71035D6BA0

means:

Code:
if X1 == 0:
branch to 0x71035D6BA0

Here, X1 is the trackedActivity argument.

So this is:

Code:
if trackedActivity == null:
go to RefreshCurrentFollower

Then:

Code:
B 0x7108CB41B0

jumps to the code cave.

So the hook does this:

Code:
if trackedActivity is null:
run original behavior
else:
jump to custom code

The hook itself only does a null check. The more specific mission check happens at the start of the code cave.

Block B-1: Check whether the tracked activity is a mission

Code:

Code:
0x7108CB41B0    LDR   W8, [X1, #0x20]
0x7108CB41B4    CMP   W8, #1
0x7108CB41B8    B.NE  0x71035D6BA0

This reads:

Code:
trackedActivity.activityCase_

because:

Code:
TrackedActivity.activityCase_ = 0x20

So:

Code:
LDR W8, [X1, #0x20]

means:

Code:
W8 = trackedActivity.activityCase_

Then:

Code:
CMP W8, #1

checks whether the activity case is 1.

In the enum:

Code:
Mission = 1

So this means:

Code:
if trackedActivity.activityCase_ != Mission:
go back to RefreshCurrentFollower

This is needed because TrackedActivity can be Mission, StarPath, Crafting, Duty, Story, Keyhole, etc.

This prevents the code from treating a non-mission tracked activity as a mission.

Block B-2: Prologue / saving registers

Code:

Code:
0x7108CB41BC    STP   X19, X30, [SP, #-0x10]!
0x7108CB41C0    STP   X20, X21, [SP, #-0x10]!
0x7108CB41C4    STP   X22, X23, [SP, #-0x10]!
0x7108CB41C8    STP   X24, X25, [SP, #-0x10]!
0x7108CB41CC    STP   X26, X27, [SP, #-0x10]!

This saves registers on the stack.

The code will use X19-X27 to keep important values while calling other functions.

Important registers used later:

Code:
X19 = MissionManager instance
W20 = missionId first
X20 = MissionSlot later
W21 = SubStep count
W22 = SubStep loop index
X23 = first SubStep element address
W24 = Objective count
W25 = Objective loop index
X26 = first Objective element address
X30 = return address / link register

X0-X7 are commonly used for function arguments and return values, so they can be overwritten by function calls.

X19-X27 are better for keeping values across function calls, but if custom code uses them, it should restore them before returning.

This block does not do mission logic. It just protects registers so the game can continue normally after the code cave returns.

Block B-3: Save MissionManager and read missionId

Code:

Code:
0x7108CB41D0    MOV   X19, X0
0x7108CB41D4    LDR   X8,  [X1, #0x18]
0x7108CB41D8    LDR   W20, [X8, #0x18]

At this point:

Code:
X0 = MissionManager instance
X1 = trackedActivity

First:

Code:
MOV X19, X0

saves the MissionManager instance.

So:

Code:
X19 = MissionManager

Next:

Code:
LDR X8, [X1, #0x18]

reads:

Code:
trackedActivity.activity_

because:

Code:
TrackedActivity.activity_ = 0x18

The code already checked that activityCase_ is Mission, so activity_ can be treated as TrackedMission.

Then:

Code:
LDR W20, [X8, #0x18]

reads:

Code:
trackedMission.missionId_

because:

Code:
TrackedMission.missionId_ = 0x18

So this block means:

Code:
MissionManager* missionManager = X0;
TrackedMission* trackedMission = trackedActivity->activity_;
int missionId = trackedMission->missionId_;

After this:

Code:
X19 = MissionManager
W20 = missionId

Block B-4: Run the original intercepted call

Code:

Code:
0x7108CB41DC    BL    0x71035D6BA0

This calls:

Code:
MissionManager.RefreshCurrentFollower()

This was the original function that OnTrackedMissionChanged jumped to.

So the custom code does not remove the original behavior. It gets the missionId first, then runs the original tracked-mission behavior.

This helps avoid breaking normal UI/follower/tracking behavior.

Block B-5: Get ProfileWorld

Code:

Code:
0x7108CB41E0    BL    0x71035CC490
0x7108CB41E4    LDR   X0,  [X0, #0x30]

The first instruction calls:

Code:
MissionManager.get_Profile()

The return value comes back in X0.

Then:

Code:
LDR X0, [X0, #0x30]

reads:

Code:
Profile.world_

So after this block:

Code:
X0 = ProfileWorld

Block B-6: Get MissionSlot from missionId

Code:

Code:
0x7108CB41E8    MOV   W1,  W20
0x7108CB41EC    MOV   X2,  XZR
0x7108CB41F0    BL    0x7105501320
0x7108CB41F4    MOV   X20, X0

This prepares arguments for:

Code:
ProfileWorld.GetMissionSlot(missionId, null)

Argument registers:

Code:
X0 = ProfileWorld
W1 = missionId
X2 = null predicate

Then:

Code:
BL 0x7105501320

calls GetMissionSlot.

The result comes back in X0.

Then:

Code:
MOV X20, X0

saves the MissionSlot.

So after this block:

Code:
X20 = MissionSlot

The missionId is only used to get the currently tracked MissionSlot. The real filter later is the objective type, not a hardcoded Vanellope missionId.

Block B-7: Get current MissionStep

Code:

Code:
0x7108CB41F8    BL    0x7105D1BA90

This calls:

Code:
MissionSlot.get_CurrentStep()

At this point, X0 still contains the MissionSlot returned by GetMissionSlot.

The return value comes back in X0.

So after this call:

Code:
X0 = current MissionStep

Conceptually:

Code:
currentStep = missionSlot.CurrentStep

Block B-8: Prepare the outer loop over SubSteps

Code:

Code:
0x7108CB41FC    LDR   X8,  [X0, #0x18]
0x7108CB4200    LDR   X8,  [X8, #0x10]
0x7108CB4204    LDR   W21, [X8, #0x18]
0x7108CB4208    LDR   X9,  [X8, #0x10]
0x7108CB420C    ADD   X23, X9,  #0x20
0x7108CB4210    MOV   W22, #0

Current MissionStep is in X0.

First:

Code:
LDR X8, [X0, #0x18]

reads:

Code:
currentStep.subSteps_

because:

Code:
MissionStep.subSteps_ = 0x18

Then:

Code:
LDR X8, [X8, #0x10]

gets the internal List from the RepeatedField.

Then:

Code:
LDR W21, [X8, #0x18]

gets the list count.

So:

Code:
W21 = subStepCount

Then:

Code:
LDR X9, [X8, #0x10]

gets the internal items array.

Then:

Code:
ADD X23, X9, #0x20

moves from the array object to the first element.

So:

Code:
X23 = address of first SubStep pointer

Finally:

Code:
MOV W22, #0

sets:

Code:
i = 0

So this block prepares:

Code:
for i = 0; i < subStepCount; i++

Block B-9: Outer loop start

Code:

Code:
0x7108CB4214    CMP   W22, W21
0x7108CB4218    B.GE  0x7108CB429C

0x7108CB421C    LDR   X10, [X23, X22, LSL #3]

First:

Code:
CMP W22, W21

compares:

Code:
i with subStepCount

Then:

Code:
B.GE 0x7108CB429C

means:

Code:
if i >= subStepCount:
exit the outer loop

If there are still SubSteps left:

Code:
LDR X10, [X23, X22, LSL #3]

loads:

Code:
subStepItems[i]

`LSL #3` means multiply by 8.

Each object pointer is 8 bytes on 64-bit ARM, so:

Code:
X10 = current MissionSubStep

Block B-10: Prepare the inner loop over Objectives

Code:

Code:
0x7108CB4220    LDR   X11, [X10, #0x18]
0x7108CB4224    LDR   X11, [X11, #0x10]
0x7108CB4228    LDR   W24, [X11, #0x18]
0x7108CB422C    LDR   X12, [X11, #0x10]
0x7108CB4230    ADD   X26, X12, #0x20
0x7108CB4234    MOV   W25, #0

Current MissionSubStep is in X10.

First:

Code:
LDR X11, [X10, #0x18]

reads:

Code:
subStep.objectives_

because:

Code:
MissionSubStep.objectives_ = 0x18

Then:

Code:
LDR X11, [X11, #0x10]

gets the internal List.

Then:

Code:
LDR W24, [X11, #0x18]

gets the objective count.

So:

Code:
W24 = objectiveCount

Then:

Code:
LDR X12, [X11, #0x10]

gets the items array.

Then:

Code:
ADD X26, X12, #0x20

gets the address of the first Objective pointer.

So:

Code:
X26 = address of first Objective pointer

Finally:

Code:
MOV W25, #0

sets:

Code:
j = 0

So this prepares:

Code:
for j = 0; j < objectiveCount; j++

Block B-11: Inner loop start

Code:

Code:
0x7108CB4238    CMP   W25, W24
0x7108CB423C    B.GE  0x7108CB4294

0x7108CB4240    LDR   X0,  [X26, X25, LSL #3]

First:

Code:
CMP W25, W24

compares:

Code:
j with objectiveCount

Then:

Code:
B.GE 0x7108CB4294

means:

Code:
if j >= objectiveCount:
exit the inner loop and go to the next SubStep

If there are still Objectives left:

Code:
LDR X0, [X26, X25, LSL #3]

loads:

Code:
objectiveItems[j]

So:

Code:
X0 = current MissionObjective

This is the point where the code has finally reached an actual MissionObjective inside the current mission step.

Block B-12: Check objective status

Code:

Code:
0x7108CB4244    LDR   W1,  [X0, #0x28]
0x7108CB4248    CMP   W1,  #1
0x7108CB424C    B.EQ  0x7108CB4258
0x7108CB4250    CMP   W1,  #2
0x7108CB4254    B.NE  0x7108CB428C

Current MissionObjective is in X0.

First:

Code:
LDR W1, [X0, #0x28]

reads:

Code:
objective.status_

because:

Code:
MissionObjective.status_ = 0x28

Then:

Code:
CMP W1, #1

checks:

Code:
status == Ongoing

If yes:

Code:
B.EQ 0x7108CB4258

continues to the next logic.

If not, it checks:

Code:
CMP W1, #2

This checks:

Code:
status == ReadyToBeCompleted

If it is neither 1 nor 2:

Code:
B.NE 0x7108CB428C

skips this objective.

So the logic is:

Code:
if status == Ongoing:
continue

else if status == ReadyToBeCompleted:
continue

else:
skip objective

This prevents the code from processing objectives that are not active or already finished.

Block B-13: Read ObjectiveData and customStepCase

Code:

Code:
0x7108CB4258    LDR   X13, [X0, #0x78]
0x7108CB425C    LDR   W1,  [X13, #0x48]

First:

Code:
LDR X13, [X0, #0x78]

reads:

Code:
objective.Data

because:

Code:
MissionObjective.Data = 0x78

Then:

Code:
LDR W1, [X13, #0x48]

reads:

Code:
objective.Data.customStepCase_

because:

Code:
MissionObjectiveData.customStepCase_ = 0x48

So after this:

Code:
X13 = MissionObjectiveData
W1 = customStepCase_

Block B-14: Check for MenuAction or DesignChallenge

Code:

Code:
0x7108CB4260    CMP   W1,  #207
0x7108CB4264    B.EQ  0x7108CB4278
0x7108CB4268    CMP   W1,  #140
0x7108CB426C    B.NE  0x7108CB428C

First:

Code:
CMP W1, #207

checks:

Code:
customStepCase_ == MenuAction

If yes:

Code:
B.EQ 0x7108CB4278

jumps to the MenuAction override.

If not, it checks:

Code:
CMP W1, #140

This checks:

Code:
customStepCase_ == DesignChallenge

If it is neither MenuAction nor DesignChallenge:

Code:
B.NE 0x7108CB428C

skips this objective.

So this block means:

Code:
if customStepCase_ == MenuAction:
use MenuAction condition

else if customStepCase_ == DesignChallenge:
use ForceSkipDesignChallenge condition

else:
skip objective

This is the main filter that keeps the code focused on the two DreamSnaps-related objective types.

Block B-15: Convert customStepCase to CheckForAdvanceStep condition

For DesignChallenge:

Code:
0x7108CB4270    MOV   W1,  #14
0x7108CB4274    B     0x7108CB427C

This means:

Code:
condition = ForceSkipDesignChallenge

For MenuAction:

Code:
0x7108CB4278    MOV   W1,  #13

This means:

Code:
condition = MenuAction

This can be confusing because the customStepCase values and condition values are different.

customStepCase values:

Code:
MenuAction      = 207
DesignChallenge = 140

MissionCompleteStep condition values:

Code:
MenuAction               = 13
ForceSkipDesignChallenge = 14

So the code is converting:

Code:
customStepCase_ -> MissionCompleteStep condition

Block B-16: Call CheckForAdvanceStep

Code:

Code:
0x7108CB427C    LDR   X3,  [X13, #0x30]
0x7108CB4280    MOV   X2,  X20
0x7108CB4284    MOV   X0,  X19
0x7108CB4288    BL    0x71035DA5B0

At this point:

Code:
W1 = condition
X13 = MissionObjectiveData
X20 = MissionSlot
X19 = MissionManager

First:

Code:
LDR X3, [X13, #0x30]

reads:

Code:
MissionObjectiveData.stepName_

because:

Code:
stepName_ = 0x30

So:

Code:
X3 = stepName

Then:

Code:
MOV X2, X20

sets:

Code:
X2 = MissionSlot

Then:

Code:
MOV X0, X19

sets:

Code:
X0 = MissionManager

Then:

Code:
BL 0x71035DA5B0

calls:

Code:
MissionManager.CheckForAdvanceStep(
condition,
missionSlot,
stepName
)

Native argument layout:

Code:
X0 = MissionManager instance
W1 = condition
X2 = MissionSlot
X3 = stepName

This is the actual force-advance call.

It does not directly write:

Code:
objective.status = completed

Instead, it passes the condition to the game's mission-advance check function.

That is why this approach can trigger the required mission events/notifications more properly than a raw status overwrite.

Block B-17: Advance the inner loop

Code:

Code:
0x7108CB428C    ADD   W25, W25, #1
0x7108CB4290    B     0x7108CB4238

This means:

Code:
j++
go back to inner loop start

So after checking one Objective, the code moves to the next Objective in the same SubStep.

Block B-18: Advance the outer loop

Code:

Code:
0x7108CB4294    ADD   W22, W22, #1
0x7108CB4298    B     0x7108CB4214

This means:

Code:
i++
go back to outer loop start

So after all Objectives in one SubStep are checked, the code moves to the next SubStep.

Block B-19: Epilogue / restore registers

Code:

Code:
0x7108CB429C    LDP   X26, X27, [SP], #0x10
0x7108CB42A0    LDP   X24, X25, [SP], #0x10
0x7108CB42A4    LDP   X22, X23, [SP], #0x10
0x7108CB42A8    LDP   X20, X21, [SP], #0x10
0x7108CB42AC    LDP   X19, X30, [SP], #0x10
0x7108CB42B0    RET

This restores the registers saved at the beginning.

It restores them in the reverse order.

Then:

Code:
RET

returns to the caller.

This is cleanup. The code borrowed registers, used them, then restored them before returning.

This section is just some background for reading the code. I am not trying to explain every detail of C#, IL2CPP, or AArch64 here. These are only the parts that matter for understanding this patch.

Class, instance, and field
In dump.cs, a class is basically a type of object.

For example:

Code:
public sealed class TrackedActivity
public sealed class TrackedMission
public sealed class MissionSlot
public sealed class MissionObjective
public sealed class MissionObjectiveData

An instance is an actual object of that class while the game is running.

For example, when the game calls:

Code:
MissionManager.OnTrackedMissionChanged(this, trackedActivity, method)

the trackedActivity argument is an actual TrackedActivity object in memory.

A field is data stored inside that object.

For example:

Code:
private object activity_; // 0x18
private TrackedActivity.ActivityOneofCase activityCase_; // 0x20

This means a TrackedActivity object has:

  • activity_ at offset 0x18
  • activityCase_ at offset 0x20

So when the assembly does:

Code:
LDR W8, [X1, #0x20]

it means:

Code:
read a 32-bit value from the object pointed to by X1, at offset 0x20

In this case, X1 is the trackedActivity argument, so this reads:

Code:
trackedActivity.activityCase_

Why offsets matter
dump.cs tells us where fields are located inside each object.

For example:

Code:
// TrackedActivity
activity_     // 0x18
activityCase_ // 0x20

// TrackedMission
missionId_    // 0x18

So the assembly can read them directly with offsets:

Code:
LDR X8,  [X1, #0x18]  // trackedActivity.activity_
LDR W20, [X8, #0x18]  // trackedMission.missionId_

This is one of the main ways dump.cs and IDA are used together.

dump.cs tells you what the fields are.
IDA shows you how the compiled code accesses them.

Function arguments in AArch64
On AArch64, the first few function arguments are usually passed in registers:

Code:
X0 = first argument
X1 = second argument
X2 = third argument
X3 = fourth argument
X4 = fifth argument
...

For an instance method, X0 is usually the instance itself, also called this.

So for something like:

Code:
MissionManager.OnTrackedMissionChanged(trackedActivity)

the native call is roughly:

Code:
X0 = MissionManager instance
X1 = trackedActivity
X2 = MethodInfo pointer

That is why the patch treats X0 as MissionManager and X1 as TrackedActivity.

Instance methods and static methods
This is important when calling functions manually.

For an instance method:

Code:
X0 = this
X1 = first normal argument
X2 = second normal argument
X3 = third normal argument

For a static method:

Code:
X0 = first argument
X1 = second argument
X2 = third argument

So if a function is an instance method and you forget to put the correct object in X0, the game will usually crash.

That is why this patch saves the MissionManager instance early:

Code:
MOV X19, X0

and later puts it back into X0 before calling:

Code:
MissionManager.CheckForAdvanceStep(...)

Registers used in this patch
The important registers are used roughly like this:

Code:
X0  = function argument / return value
X1  = function argument
X2  = function argument
X3  = function argument

X19 = MissionManager instance
W20 = missionId first, then X20 = MissionSlot later
W21 = SubStep count
W22 = SubStep loop index
X23 = SubStep array first element
W24 = Objective count
W25 = Objective loop index
X26 = Objective array first element
X30 = link register / return address

X0-X7 are often overwritten by function calls, so the patch uses X19-X27 to keep important values across calls.

Why registers are saved and restored
The patch saves registers like this:

Code:
STP X19, X30, [SP, #-0x10]!
STP X20, X21, [SP, #-0x10]!
STP X22, X23, [SP, #-0x10]!
STP X24, X25, [SP, #-0x10]!
STP X26, X27, [SP, #-0x10]!

This means the code stores those registers on the stack before using them.

At the end, it restores them:

Code:
LDP X26, X27, [SP], #0x10
LDP X24, X25, [SP], #0x10
LDP X22, X23, [SP], #0x10
LDP X20, X21, [SP], #0x10
LDP X19, X30, [SP], #0x10
RET

So the patch borrows those registers, does its work, and then puts them back before returning.

This is not the main logic of the patch. It is just necessary cleanup so the game can continue normally after the custom code runs.

The first problem was choosing where to hook.

The goal was to process one specific mission, but the game can have many active missions at the same time. So I needed a place where the game already knows which mission the player selected.

The tracked mission system was useful for this.

When the player tracks a mission, the game calls:

Code:
Mdl.Missions.MissionManager$$OnTrackedMissionChanged

In IDA, the original function was extremely small:

Code:
Mdl.Missions.MissionManager$$OnTrackedMissionChanged:
B Mdl.Missions.MissionManager$$RefreshCurrentFollower

So originally, OnTrackedMissionChanged just jumped to RefreshCurrentFollower.

That made it a convenient hook point because:

  • it runs when the tracked activity changes
  • the tracked activity is passed as an argument
  • if the tracked activity is a mission, the missionId can be obtained from that argument
  • the original function is very small
  • it is easy to preserve the original behavior

The hook replacement
The hook changes the start of the function to:

Code:
CBZ X1, 0x71035D6BA0
B   0x7108CB41B0

This is only two instructions.

The first one is:

Code:
CBZ X1, 0x71035D6BA0

CBZ means:

Code:
Compare and Branch if Zero

So this means:

Code:
if X1 == 0:
branch to 0x71035D6BA0

X1 is the trackedActivity argument.

So in plain English:

Code:
if trackedActivity == null:
go to RefreshCurrentFollower

The second instruction is:

Code:
B 0x7108CB41B0

That simply jumps to the code cave.

So the hook means:

Code:
if trackedActivity is null:
run the original behavior
else:
go to the custom code cave

Why the first null check is useful
If there is no tracked activity, there is nothing useful for the patch to process.

So the safest behavior is to skip the custom code and return to the original function.

That is what this does:

Code:
CBZ X1, 0x71035D6BA0

This first check is only a basic safety check. The more specific "is this actually a mission?" check happens inside the code cave.

The first check inside the code cave
At the start of the code cave:

Code:
LDR W8, [X1, #0x20]
CMP W8, #1
B.NE 0x71035D6BA0

This reads:

Code:
trackedActivity.activityCase_

The dump.cs field is:

Code:
private TrackedActivity.ActivityOneofCase activityCase_; // 0x20

So:

Code:
LDR W8, [X1, #0x20]

means:

Code:
W8 = trackedActivity.activityCase_

Then:

Code:
CMP W8, #1

compares activityCase_ with 1.

The enum says:

Code:
public const TrackedActivity.ActivityOneofCase Mission = 1;

So this is checking whether the tracked activity is a Mission.

Then:

Code:
B.NE 0x71035D6BA0

means:

Code:
if activityCase_ is not Mission:
go to RefreshCurrentFollower

So the code cave begins like this:

Code:
if trackedActivity.activityCase_ != Mission:
return to the original RefreshCurrentFollower behavior

Why this check is needed
TrackedActivity is not always a mission.

The enum contains several possible activity types:

Code:
None    = 0
Mission = 1
StarPath = 2
Crafting = 3
Duty    = 4
Story   = 5
Keyhole = 6

So without this check, the code could treat StarPath, Crafting, Duty, Story, or Keyhole as if it were a mission.

That would be wrong and could easily crash the game.

So the first real filter is: only continue if the tracked activity is a mission.

Part 1 in plain English
This part of the code does only this:

  • Hook OnTrackedMissionChanged.
  • If trackedActivity is null, return to the original function.
  • Jump to the code cave.
  • Inside the code cave, read trackedActivity.activityCase_.
  • If the tracked activity is not a Mission, return to the original function.
  • Only continue if the player tracked a mission.

At this point, the code has not advanced anything yet.
It has only confirmed that the tracked activity exists and that it is actually a mission.

At the end of Part 1, the code has only confirmed one thing:

Code:
trackedActivity exists
trackedActivity.activityCase_ == Mission

So at this point, it is safe to treat:

Code:
trackedActivity.activity_

as a TrackedMission object.

The next goal is to get the missionId from that TrackedMission.

The relevant dump.cs fields

From TrackedActivity:

Code:
private object activity_; // 0x18
private TrackedActivity.ActivityOneofCase activityCase_; // 0x20

From TrackedMission:

Code:
private int missionId_; // 0x18

So the structure is:

Code:
TrackedActivity
-> activity_      // 0x18
-> activityCase_  // 0x20

TrackedMission
-> missionId_     // 0x18

The code already checked:

Code:
TrackedActivity.activityCase_ == Mission

So now it can read:

Code:
TrackedActivity.activity_

and treat it as:

Code:
TrackedMission*

The actual assembly

This is the relevant part:

Code:
STP X19, X30, [SP, #-0x10]!
STP X20, X21, [SP, #-0x10]!
STP X22, X23, [SP, #-0x10]!
STP X24, X25, [SP, #-0x10]!
STP X26, X27, [SP, #-0x10]!

MOV X19, X0
LDR X8,  [X1, #0x18]
LDR W20, [X8, #0x18]

The register save part was explained earlier, so the important lines here are:

Code:
MOV X19, X0
LDR X8,  [X1, #0x18]
LDR W20, [X8, #0x18]

What X0 and X1 are here

The original function is roughly:

Code:
MissionManager.OnTrackedMissionChanged(
trackedActivity
)

As a native instance method, the arguments are passed roughly like this:

Code:
X0 = MissionManager instance
X1 = trackedActivity
X2 = MethodInfo

So at the start of the function:

Code:
X0 = this MissionManager
X1 = trackedActivity

Saving the MissionManager instance

The first important instruction is:

Code:
MOV X19, X0

This copies X0 into X19.

Since X0 is the MissionManager instance, this means:

Code:
X19 = MissionManager instance

The reason for saving it is simple: X0 will be reused many times as an argument and return-value register.

When the code calls other functions with BL, X0 can be overwritten. So the patch stores the MissionManager instance in X19, a callee-saved register, so it can use it later.

Later, when calling CheckForAdvanceStep, the code needs the MissionManager instance again:

Code:
MOV X0, X19

That puts the saved MissionManager back into X0.

In short: X19 is used as a safe place to keep the MissionManager pointer while the rest of the code calls other functions.

Reading trackedActivity.activity_

The next instruction is:

Code:
LDR X8, [X1, #0x18]

From dump.cs:

Code:
private object activity_; // 0x18

So this reads:

Code:
trackedActivity.activity_

Since X1 is trackedActivity, this means:

Code:
X8 = trackedActivity.activity_

Because Part 1 already confirmed:

Code:
trackedActivity.activityCase_ == Mission

this activity_ object should be a TrackedMission.

So conceptually:

Code:
TrackedMission trackedMission = trackedActivity.activity_;

Reading trackedMission.missionId_

The next instruction is:

Code:
LDR W20, [X8, #0x18]

From dump.cs:

Code:
private int missionId_; // 0x18

So this reads:

Code:
trackedMission.missionId_

Since missionId_ is an int, the code uses W20 instead of X20.

Code:
W20 = trackedMission.missionId_

In C-like pseudocode, these two instructions are:

Code:
TrackedMission* trackedMission = trackedActivity->activity_;
int missionId = trackedMission->missionId_;

Why W20, not X20?

AArch64 has 64-bit X registers and 32-bit W views of the same registers.

For example:

Code:
X20 = full 64-bit register
W20 = lower 32-bit part of X20

missionId_ is an int, so it is a 32-bit value.

That is why the code uses:

Code:
LDR W20, [X8, #0x18]

not:

Code:
LDR X20, [X8, #0x18]

Later, when the code needs to pass missionId as an argument, it uses W20:

Code:
MOV W1, W20

because the function expects an int mission item / mission id value.

What has been obtained at this point

After this block:

Code:
MOV X19, X0
LDR X8,  [X1, #0x18]
LDR W20, [X8, #0x18]

the code has two important values saved:

Code:
X19 = MissionManager instance
W20 = missionId of the tracked mission

Nothing has been advanced yet.

The code has only identified which mission the player tracked.

Calling the original tracked-mission behavior

After getting the missionId, the code calls:

Code:
BL 0x71035D6BA0

This is:

Code:
Mdl.Missions.MissionManager$$RefreshCurrentFollower

This was the original function that OnTrackedMissionChanged was going to branch to.

So the patch does not skip the original behavior.

The flow is:

Code:
read missionId from trackedActivity
call original RefreshCurrentFollower
continue custom logic

This matters because the tracked mission change may also update UI, follower behavior, or other normal game state. The patch should not remove that behavior unless necessary.

Part 2 in plain English

This part of the code does this:

  • Save the MissionManager instance from X0 into X19.
  • Read trackedActivity.activity_ from X1 + 0x18.
  • Because activityCase_ was Mission, treat activity_ as TrackedMission.
  • Read trackedMission.missionId_ from activity_ + 0x18.
  • Store that missionId in W20.
  • Call the original RefreshCurrentFollower function.

At this point, the code knows which mission the player tracked, but it has not found the mission step or objective yet.

That happens in the next part, where the missionId is used to get the MissionSlot and then walk down to the current MissionObjective.

Before explaining the double loop, it is probably better to explain what I mean by RepeatedField and List here.

In dump.cs, the mission step does not directly contain just one substep. It contains this:

Code:
private readonly RepeatedField<MissionSubStep> subSteps_; // 0x18

And each substep does not directly contain just one objective. It contains this:

Code:
private readonly RepeatedField<MissionObjective> objectives_; // 0x18

If you are not familiar with C# or protobuf, the important part is not the exact name RepeatedField.

For this patch, I just treated it as:

a container that holds multiple objects of the same type.

So:

Code:
RepeatedField<MissionSubStep>

basically means:

Code:
a list of MissionSubStep objects

And:

Code:
RepeatedField<MissionObjective>

basically means:

Code:
a list of MissionObjective objects

This is not meant to be a perfect explanation of Google's protobuf RepeatedField. For this patch, the important thing is simply that it behaves like a list of entries.

What a list looks like conceptually

A list is just a group of items arranged in order.

For example:

Code:
Objectives:
[0] MissionObjective
[1] MissionObjective
[2] MissionObjective
[3] MissionObjective

To loop through it, you need two things:

  • how many items are in the list
  • where the items start

The first one is the count.

The second one is the item array.

So conceptually, the code needs:

Code:
count = how many objectives exist
items = where the objective pointers are stored

Then it can do:

Code:
for i = 0; i < count; i++:
objective = items[i]

Why count is easy to understand

The List<T>.get_Count function is very simple in IDA:

Code:
LDR W0, [X0,#0x18]
RET

That means the count is stored at:

Code:
list + 0x18

So when the code does:

Code:
LDR W21, [X8, #0x18]

or:

Code:
LDR W24, [X11, #0x18]

it is reading the number of items in the list.

In plain English:

Code:
W21 = number of SubSteps
W24 = number of Objectives

What "items" means

The word "Item" can sound more complicated than it really is.

Here, it just means one entry in the list.

If the list is:

Code:
[ MissionObjective, MissionObjective, MissionObjective ]

then:

Code:
Item[0] = first MissionObjective
Item[1] = second MissionObjective
Item[2] = third MissionObjective

Internally, the list has an array that stores these entries.

On 64-bit, object references are 8 bytes each.

So if the first element starts at some address, the next one is 8 bytes after it, and the next one is another 8 bytes after that.

Conceptually:

Code:
first item address + index * 8

That is what this means:

Code:
LDR X10, [X23, X22, LSL #3]

`LSL #3` means multiply by 8.

So this line means:

Code:
X10 = subStepItems[i]

The same idea is used for objectives:

Code:
LDR X0, [X26, X25, LSL #3]

which means:

Code:
X0 = objectiveItems[j]

Why the code uses +0x20

In IL2CPP, the array object itself has a header before the actual elements.

So the pointer to the array object is not the same as the pointer to the first element.

The actual element data starts after the array header.

In this case, the first element is treated as:

Code:
items array + 0x20

So the code does:

Code:
ADD X23, X9, #0x20

for SubSteps, and:

Code:
ADD X26, X12, #0x20

for Objectives.

In plain English:

Code:
X23 = address of the first SubStep pointer
X26 = address of the first Objective pointer

After that, the code can read each entry by adding index * 8.

The simple mental model

The easiest way to think about it is this:

Code:
RepeatedField<T>
-> internal List<T>
-> count
-> array of item pointers
-> item[0]
-> item[1]
-> item[2]

The code does not need to understand every detail of protobuf.

It only needs to know:

  • where the count is
  • where the item array is
  • where the first item starts
  • how large each item pointer is

For this code, the useful pattern is:

Code:
list          = repeatedField + 0x10
count         = list + 0x18
items array   = list + 0x10
first item    = items array + 0x20
item[index]   = first item + index * 8

Once that pattern is known, the double loop becomes much easier to read.

It is just:

Code:
for each SubStep in currentStep.SubSteps:
for each Objective in subStep.Objectives:
check this Objective

In Part 2, the code got the missionId from the tracked mission.

The next goal is to use that missionId to get the current mission data, then walk down to the actual MissionObjective.

The structure is not flat. It is:

Code:
MissionSlot
-> CurrentStep
-> SubSteps
-> Objectives
-> MissionObjective

So this part has two jobs:

  • Get the MissionSlot from the missionId.
  • Walk through the current step's SubSteps and Objectives.

Getting the MissionSlot

The code first gets the profile:

Code:
BL  0x71035CC490
LDR X0, [X0, #0x30]

The first instruction calls:

Code:
MissionManager.get_Profile()

The return value is in X0.

Then:

Code:
LDR X0, [X0, #0x30]

gets the ProfileWorld from the profile.

After that, the code prepares arguments for:

Code:
ProfileWorld.GetMissionSlot(missionId, null)

The assembly is:

Code:
MOV W1, W20
MOV X2, XZR
BL  0x7105501320
MOV X20, X0

At this point:

Code:
X0 = ProfileWorld
W1 = missionId
X2 = null

After the call returns:

Code:
X0 = MissionSlot

So the code saves it:

Code:
X20 = MissionSlot

The missionId is not used as the main filter. It is only used to obtain the MissionSlot for the mission currently being tracked.

Getting the current step

Next, the code calls:

Code:
BL 0x7105D1BA90

This is:

Code:
MissionSlot.get_CurrentStep()

The MissionSlot class has:

Code:
private int currentStepIndex_; // 0x20
private readonly RepeatedField<MissionStep> missionSteps_; // 0x28

So CurrentStep is basically selected from missionSteps_ using currentStepIndex_.

The original game function also shows this idea. It reads the current step index from the MissionSlot, checks it against the missionSteps count, and then gets the item from the RepeatedField.

So after this call:

Code:
X0 = current MissionStep

How I knew this was a nested repeated-field structure

dump.cs already shows that MissionStep contains a repeated field of MissionSubStep:

Code:
private readonly RepeatedField<MissionSubStep> subSteps_; // 0x18

And MissionSubStep contains a repeated field of MissionObjective:

Code:
private readonly RepeatedField<MissionObjective> objectives_; // 0x18

So the high-level structure is clear:

Code:
MissionStep
-> RepeatedField<MissionSubStep> subSteps_
-> RepeatedField<MissionObjective> objectives_

But dump.cs alone does not fully explain how to access the native memory layout safely from a code cave.

For that, I checked how the game itself handles these fields in IDA.

The useful functions were:

Code:
MissionStep.get_AllObjectives
MissionStep.get_ActiveObjectives
MissionStep.FirstObjectiveOf
MissionSlot.get_CurrentStep

For example, MissionStep.get_AllObjectives uses the MissionStep's subSteps_ field and then applies SelectMany to collect objectives from the substeps.

MissionStep.FirstObjectiveOf also calls get_AllObjectives first, then applies a predicate to find the first matching MissionObjective.

So the idea was not to invent the structure from nothing. I checked how the original game code treats the same fields, then used the same kind of layout knowledge in the code cave.

RepeatedField and List layout

RepeatedField<T> internally contains a List<T>:

Code:
private readonly List<T> list; // 0x0

The List<T> implementation shows the important native offsets.

The Count getter is:

Code:
LDR W0, [X0,#0x18]
RET

So List<T>.Count is at:

Code:
list + 0x18

The Item getter also reads the item array from:

Code:
list + 0x10

and then reads from the array data area.

For an Il2Cpp array, the actual element data starts after the array object header, so the first element is at:

Code:
items + 0x20

Since these are object references, each element is 8 bytes on 64-bit ARM.

So the direct-access pattern is:

Code:
count         = list + 0x18
items array   = list + 0x10
first element = items array + 0x20
element[i]    = first element + i * 8

That is the pattern used by the code cave.

This is why the code uses +0x10, +0x18, +0x20, and LSL #3. LSL #3 means index * 8, because each object pointer is 8 bytes.

Outer loop: SubSteps

After MissionSlot.get_CurrentStep(), X0 contains the current MissionStep.

The code then gets the subSteps_ field:

Code:
LDR X8, [X0, #0x18]

From dump.cs:

Code:
private readonly RepeatedField<MissionSubStep> subSteps_; // 0x18

So this means:

Code:
X8 = currentStep.subSteps_

Then:

Code:
LDR X8, [X8, #0x10]

RepeatedField<T> contains a List<T>, so this gets the internal List<T>.

Then:

Code:
LDR W21, [X8, #0x18]

reads the List count:

Code:
W21 = subStepCount

Then:

Code:
LDR X9, [X8, #0x10]
ADD X23, X9, #0x20
MOV W22, #0

This means:

Code:
X9  = items array
X23 = first element address
W22 = i = 0

So the outer loop is:

Code:
for i in range(subStepCount):
subStep = subSteps[i]

In assembly:

Code:
CMP W22, W21
B.GE exit_outer_loop

LDR X10, [X23, X22, LSL #3]

`X22, LSL #3` means:

Code:
i * 8

So:

Code:
X10 = subStepItems[i]

Inner loop: Objectives

Now X10 is the current MissionSubStep.

The code gets its objectives_ field:

Code:
LDR X11, [X10, #0x18]

From dump.cs:

Code:
private readonly RepeatedField<MissionObjective> objectives_; // 0x18

So:

Code:
X11 = subStep.objectives_

Then it follows the same pattern:

Code:
LDR X11, [X11, #0x10]
LDR W24, [X11, #0x18]
LDR X12, [X11, #0x10]
ADD X26, X12, #0x20
MOV W25, #0

This means:

Code:
objectiveList  = objectives_.list
objectiveCount = objectiveList.Count
objectiveItems = objectiveList._items
firstObjective = objectiveItems + 0x20
j = 0

Then the inner loop is:

Code:
CMP W25, W24
B.GE exit_inner_loop

LDR X0, [X26, X25, LSL #3]

So:

Code:
if j >= objectiveCount:
go to next SubStep

X0 = objectiveItems[j]

At this point, X0 is the actual MissionObjective pointer.

Why the code uses a double loop

The double loop exists because the mission data is nested:

Code:
MissionStep has many SubSteps
Each SubStep has many Objectives

So one loop is not enough.

The outer loop walks:

Code:
MissionStep.SubSteps

The inner loop walks:

Code:
MissionSubStep.Objectives

Only after both loops does the code reach a MissionObjective.

Part 3 in plain English

This part does this:

  • Use missionId to get the current MissionSlot.
  • Call MissionSlot.get_CurrentStep() to get the current MissionStep.
  • Read currentStep.subSteps_.
  • Use the internal List count and items array to loop through SubSteps.
  • For each SubStep, read subStep.objectives_.
  • Use the same List pattern to loop through Objectives.
  • Put the current MissionObjective pointer in X0.

At the end of this part, the code has not advanced anything yet.

It has only walked down from the tracked mission to each MissionObjective in the current step.

The actual filtering happens in the next part.

At this point, the code has already done the difficult part.

It has:

  • found the currently tracked mission
  • got the MissionSlot
  • got the current MissionStep
  • looped through SubSteps and Objectives
  • found a MissionObjective that matches one of the two DreamSnaps-related cases

So now the code needs to actually advance that objective.

This is the part where it calls:

Code:
Mdl.Missions.MissionManager$$CheckForAdvanceStep

Why not just edit the objective status?

A simple approach would be to directly change the objective status.

For example, something like:

Code:
objective.status = Completed

But that is not enough.

Mission progress in this game is not just a number changing from Ongoing to Completed. A mission step can also trigger:

  • completion events
  • notifications
  • UI updates
  • item giving
  • next-step initialization
  • world-state changes

I tried more direct ways to force mission progress, but that caused problems. The objective could appear to advance, but later quest logic did not initialize correctly.

One example was Vanellope's house. The quest could move forward, but the house was not added or initialized correctly afterward.

So the safer approach was to avoid directly overwriting the mission state and instead pass the objective through a game function that already handles mission advancement.

The function used

The function used here is:

Code:
Mdl.Missions.MissionManager$$CheckForAdvanceStep

Conceptually, the call is:

Code:
MissionManager.CheckForAdvanceStep(
condition,
missionSlot,
stepName
)

Since this is an instance method, the native arguments are arranged like this:

Code:
X0 = MissionManager instance
W1 = condition
X2 = MissionSlot
X3 = stepName

That is why the code prepares those registers before the call.

Condition value: MenuAction or ForceSkipDesignChallenge

In Part 4, the code checked:

Code:
MissionObjectiveData.customStepCase_

The two objective types were:

Code:
MenuAction      = 207
DesignChallenge = 140

But these are not the same values passed to CheckForAdvanceStep.

CheckForAdvanceStep expects a MissionCompleteStep condition.

The relevant condition enum is:

Code:
MenuAction               = 13
ForceSkipDesignChallenge = 14

So the code converts the custom step type into the condition value that CheckForAdvanceStep expects.

For DesignChallenge:

Code:
MOV W1, #14

That means:

Code:
condition = ForceSkipDesignChallenge

For MenuAction:

Code:
MOV W1, #13

That means:

Code:
condition = MenuAction

This is an easy place to get confused. customStepCase_ identifies the objective type. The condition value is what CheckForAdvanceStep uses to test or complete that kind of step.

Getting stepName

Once the correct condition is in W1, the code reads the stepName:

Code:
LDR X3, [X13, #0x30]

At this point, X13 is the MissionObjectiveData pointer.

From dump.cs, MissionObjectiveData contains:

Code:
private string stepName_; // 0x30

So this instruction means:

Code:
X3 = objective.Data.stepName_

stepName is passed as the fourth argument.

Passing the MissionSlot

The code already saved the MissionSlot earlier in X20.

So it does:

Code:
MOV X2, X20

That means:

Code:
X2 = MissionSlot

This is the third argument to CheckForAdvanceStep.

Passing the MissionManager instance

The code saved the MissionManager instance at the beginning of the code cave:

Code:
MOV X19, X0

That was done because X0 gets overwritten by function calls.

Now, before calling CheckForAdvanceStep, the code puts the MissionManager instance back into X0:

Code:
MOV X0, X19

So:

Code:
X0 = MissionManager instance

This is important because CheckForAdvanceStep is an instance method. If X0 does not contain the correct MissionManager instance, the call will not work correctly.

The actual call

The final call setup is:

Code:
LDR X3, [X13, #0x30]
MOV X2, X20
MOV X0, X19
BL  0x71035DA5B0

In plain English:

Code:
stepName = objective.Data.stepName_

MissionManager.CheckForAdvanceStep(
condition,
missionSlot,
stepName
)

Where:

Code:
X0 = MissionManager
W1 = condition
X2 = MissionSlot
X3 = stepName

The condition was already set just before this block:

Code:
MenuAction               -> W1 = 13
DesignChallenge           -> W1 = 14

Why this worked better than direct forcing

The important part is that CheckForAdvanceStep is closer to the game's normal manual-completion path.

The MissionSlot class also has functions like:

Code:
CheckManualCompletion(...)
CheckManualCompletionForBringItem(...)
AdvanceStep()

So the mission system already has its own way to check conditions and advance steps.

By calling CheckForAdvanceStep with the right MissionSlot, condition, and stepName, the patch lets the game's mission system do more of the normal work.

That is why it can trigger the required event/notification behavior better than simply changing a status value.

The patch is not just saying "this objective is completed now." It is asking the mission system to process the matching condition for the current mission step.

After the call

After CheckForAdvanceStep returns, the code does not immediately stop the whole loop.

It continues:

Code:
ADD W25, W25, #1
B   0x7108CB4238

That means:

Code:
j++
continue checking objectives

When all objectives in the current SubStep are done, it goes to the next SubStep:

Code:
ADD W22, W22, #1
B   0x7108CB4214

That means:

Code:
i++
continue checking subSteps

So even after one matching objective is processed, the loop structure stays normal.

Restoring registers and returning

At the end, the code restores the registers it saved at the beginning:

Code:
LDP X26, X27, [SP], #0x10
LDP X24, X25, [SP], #0x10
LDP X22, X23, [SP], #0x10
LDP X20, X21, [SP], #0x10
LDP X19, X30, [SP], #0x10
RET

This puts back the saved registers and returns normally.

This is just cleanup. The important work was already done by the CheckForAdvanceStep call.

Part 5 in plain English

This part does this:

  • Convert the matched objective type into the correct MissionCompleteStep condition.
  • Read stepName from MissionObjectiveData.
  • Pass the current MissionSlot.
  • Pass the MissionManager instance.
  • Call MissionManager.CheckForAdvanceStep.
  • Continue the loop normally.
  • Restore registers and return.

So the final action is not a raw status overwrite.

It is:

Code:
Find the right objective
prepare the condition
call the game's mission-advance check function

That is the main reason this approach works without skipping too much of the quest logic.

This is just the reference material I used while reading the code. The main explanation above is easier to read, but these excerpts show where the offsets and enum values came from.

Code:
// Namespace: Meta
public sealed class TrackedActivity : IMessage<TrackedActivity>, IMessage, IEquatable<TrackedActivity>, IDeepCloneable<TrackedActivity>, IMessageFieldAccessor, IMessageOneofAccessor, IJsonWritableFields // TypeDefIndex: 3751
{
// Fields
private static readonly MessageParser<TrackedActivity> *parser; // 0x0
private UnknownFieldSet *unknownFields; // 0x10
public const int MissionFieldNumber = 1;
public const int StarPathFieldNumber = 2;
public const int CraftingFieldNumber = 3;
public const int DutyFieldNumber = 4;
public const int StoryFieldNumber = 5;
public const int KeyholeFieldNumber = 6;
private object activity*; // 0x18
private TrackedActivity.ActivityOneofCase activityCase*; // 0x20
}

Code:
// Namespace: Meta
public sealed class TrackedMission : IMessage<TrackedMission>, IMessage, IEquatable<TrackedMission>, IDeepCloneable<TrackedMission>, IMessageFieldAccessor, IJsonWritableFields // TypeDefIndex: 3738
{
// Fields
private static readonly MessageParser<TrackedMission> _parser; // 0x0
private UnknownFieldSet *unknownFields; // 0x10
public const int MissionIdFieldNumber = 1;
private int missionId*; // 0x18
}

Code:
// Namespace:
public enum TrackedActivity.ActivityOneofCase // TypeDefIndex: 3749
{
// Fields
public int value__; // 0x0
public const TrackedActivity.ActivityOneofCase None = 0;
public const TrackedActivity.ActivityOneofCase Mission = 1;
public const TrackedActivity.ActivityOneofCase StarPath = 2;
public const TrackedActivity.ActivityOneofCase Crafting = 3;
public const TrackedActivity.ActivityOneofCase Duty = 4;
public const TrackedActivity.ActivityOneofCase Story = 5;
public const TrackedActivity.ActivityOneofCase Keyhole = 6;
}

Code:
// Namespace: Meta.Missions
public sealed class MissionSlot : IMessage<MissionSlot>, IMessage, IEquatable<MissionSlot>, IDeepCloneable<MissionSlot>, IMessageFieldAccessor, IJsonWritableFields, IMissionIdentifier // TypeDefIndex: 6503
{
// Fields
private static readonly MessageParser<MissionSlot> *parser; // 0x0
private UnknownFieldSet *unknownFields; // 0x10
public const int CharacterIdFieldNumber = 1;
private int characterId*; // 0x18
public const int MissionIdFieldNumber = 2;
private int missionId*; // 0x1C
public const int CurrentStepIndexFieldNumber = 3;
private int currentStepIndex_; // 0x20
public const int MissionStepsFieldNumber = 4;
private static readonly FieldCodec<MissionStep> *repeated_missionSteps_codec; // 0x8
private readonly RepeatedField<MissionStep> missionSteps*; // 0x28
}

Code:
// Namespace: Meta.Missions
public sealed class MissionStep : IMessage<MissionStep>, IMessage, IEquatable<MissionStep>, IDeepCloneable<MissionStep>, IMessageFieldAccessor, IJsonWritableFields, IMissionIdentifier // TypeDefIndex: 6421
{
// Fields
private static readonly MessageParser<MissionStep> _parser; // 0x0
private UnknownFieldSet _unknownFields; // 0x10
public const int SubStepsFieldNumber = 1;
private static readonly FieldCodec<MissionSubStep> *repeated_subSteps_codec; // 0x8
private readonly RepeatedField<MissionSubStep> subSteps*; // 0x18
[CompilerGenerated]
private int <StepIndex>k__BackingField; // 0x20
[CompilerGenerated]
private MissionStepData <Data>k__BackingField; // 0x28
internal MissionSlot MissionSlot; // 0x30
}

Code:
// Namespace: Meta.Missions
public sealed class MissionSubStep : IMessage<MissionSubStep>, IMessage, IEquatable<MissionSubStep>, IDeepCloneable<MissionSubStep>, IMessageFieldAccessor, IJsonWritableFields, IMissionIdentifier // TypeDefIndex: 6428
{
// Fields
private static readonly MessageParser<MissionSubStep> _parser; // 0x0
private UnknownFieldSet _unknownFields; // 0x10
public const int ObjectivesFieldNumber = 1;
private static readonly FieldCodec<MissionObjective> *repeated_objectives_codec; // 0x8
private readonly RepeatedField<MissionObjective> objectives*; // 0x18
}

Code:
// Namespace: Meta.Missions
public sealed class MissionObjective : IMessage<MissionObjective>, IMessage, IEquatable<MissionObjective>, IDeepCloneable<MissionObjective>, IMessageFieldAccessor, IJsonWritableFields, IMissionIdentifier, IEquationKeyProvider // TypeDefIndex: 6481
{
// Fields
private static readonly MessageParser<MissionObjective> *parser; // 0x0
private UnknownFieldSet *unknownFields; // 0x10
public const int TargetAmountFieldNumber = 2;
private float targetAmount*; // 0x18
public const int ProgressKeysFieldNumber = 3;
private static readonly MapField.Codec<string, string> *map_progressKeys_codec; // 0x8
private readonly MapField<string, string> progressKeys*; // 0x20
public const int StatusFieldNumber = 4;
private MissionStepStatus status*; // 0x28
...
[CompilerGenerated]
private MissionObjectiveData <Data>k__BackingField; // 0x78
}

Code:
// Namespace: Definitions.Items
public sealed class MissionObjectiveData : IMessage<MissionObjectiveData>, IMessage, IEquatable<MissionObjectiveData>, IDeepCloneable<MissionObjectiveData>, IMessageFieldAccessor, IMessageOneofAccessor, IJsonWritableFields, IMissionStepName, IStepDescriptionsMobile, ICustomStepOwner, IItemSelector, IItemGeneratorOwner, IDataValidation // TypeDefIndex: 9550
{
// Fields
private static readonly MessageParser<MissionObjectiveData> *parser; // 0x0
private UnknownFieldSet *unknownFields; // 0x10
public const int StepDescriptionFieldNumber = 1;
private string stepDescription*; // 0x18
public const int StepDescriptionMobileFieldNumber = 2;
private string stepDescriptionMobile*; // 0x20
public const int ObjectiveIDFieldNumber = 8;
private int objectiveID_; // 0x28
public const int StepNameFieldNumber = 9;
private string stepName_; // 0x30
...
private object customStep_; // 0x40
private MissionObjectiveData.CustomStepOneofCase customStepCase_; // 0x48
}

Code:
// Namespace: Definitions.Items
public enum MissionStepStatus // TypeDefIndex: 9818
{
// Fields
public int value__; // 0x0
[OriginalName("MissionStepStatus_NotStarted")]
public const MissionStepStatus NotStarted = 0;
[OriginalName("MissionStepStatus_Ongoing")]
public const MissionStepStatus Ongoing = 1;
[OriginalName("MissionStepStatus_ReadyToBeCompleted")]
public const MissionStepStatus ReadyToBeCompleted = 2;
[OriginalName("MissionStepStatus_Completed")]
public const MissionStepStatus Completed = 3;
[OriginalName("MissionStepStatus_Confirmed")]
public const MissionStepStatus Confirmed = 4;
[OriginalName("MissionStepStatus_Init")]
public const MissionStepStatus Init = -1;
}

Code:
// Namespace:
public enum MissionObjectiveData.CustomStepOneofCase // TypeDefIndex: 9547
{
// Fields
public int value__; // 0x0
public const MissionObjectiveData.CustomStepOneofCase None = 0;
...
public const MissionObjectiveData.CustomStepOneofCase DesignChallenge = 140;
...
public const MissionObjectiveData.CustomStepOneofCase MenuAction = 207;
...
}

Code:
// Namespace:
public enum MissionCompleteStep.Types.Condition // TypeDefIndex: 1512
{
// Fields
public int value__; // 0x0
[OriginalName("DialogueStart")]
public const MissionCompleteStep.Types.Condition DialogueStart = 0;
[OriginalName("DialogueEnd")]
public const MissionCompleteStep.Types.Condition DialogueEnd = 1;
...
[OriginalName("MenuAction")]
public const MissionCompleteStep.Types.Condition MenuAction = 13;
[OriginalName("ForceSkipDesignChallenge")]
public const MissionCompleteStep.Types.Condition ForceSkipDesignChallenge = 14;
}

Code:
.text:0000007103AF7C40 ; int32_t System_Collections_Generic_List___Il2CppFullySharedGenericType___get_Count(System_Collections_Generic_List_T__o *this, const MethodInfo_3AF7C40 *method)
.text:0000007103AF7C40 System.Collections.Generic.List___Il2CppFullySharedGenericType_$$get_Count
.text:0000007103AF7C40                 LDR             W0, [X0,#0x18]
.text:0000007103AF7C44                 RET

Code:
.text:0000007103AF7D90 ; Unity_IL2CPP_Metadata___Il2CppFullySharedGenericType_o System_Collections_Generic_List___Il2CppFullySharedGenericType___get_Item(System_Collections_Generic_List_T__o *this, int32_t index, const MethodInfo_3AF7D90 *method)
.text:0000007103AF7D90 System.Collections.Generic.List___Il2CppFullySharedGenericType_$$get_Item
.text:0000007103AF7D98                 LDR             W8, [X0,#0x18]
.text:0000007103AF7D9C                 CMP             W8, W1
.text:0000007103AF7DA0                 B.LS            loc_7103AF7DE0
.text:0000007103AF7DA4                 LDR             X9, [X0,#0x10]
.text:0000007103AF7DA8                 CBZ             X9, loc_7103AF7DE8
...
.text:0000007103AF7DC8                 MADD            X9, X11, X10, X9
...
.text:0000007103AF7DD0                 ADD             X1, X9, #0x20 ; src

Code:
// Hook
0x71035DA7D0    CBZ   X1, 0x71035D6BA0
0x71035DA7D4    B     0x7108CB41B0

Code:
// CheckForAdvanceStep call
0x7108CB427C    LDR   X3,  [X13, #0x30]
0x7108CB4280    MOV   X2,  X20
0x7108CB4284    MOV   X0,  X19
0x7108CB4288    BL    0x71035DA5B0
Post automatically merged:

DLV Profile Decrypt / Encrypt Tool

This is a small tool for decrypting and encrypting the Disney Dreamlight Valley profile.json save file.

It is mainly intended as an emergency tool for manual save editing when unsafe debug furniture causes problems.

Some decoration-focused codes, such as Get All-type codes, may add internal debug furniture items. These items were not meant to be used as normal furniture. Some of them can become impossible to select, move, or remove after being placed in the world.

For debug furniture, using the in-game Hide feature is recommended instead of placing it.

If you still place debug items for decoration and one of them gets stuck, this tool can be used to decrypt profile.json, edit the JSON manually, and encrypt it again.

Requirements:

  • Python must be installed.
  • The Python package pycryptodome is required.

If you do not have pycryptodome installed, open Command Prompt and run:

Code:
pip install pycryptodome

Basic usage:

  1. Extract the ZIP file.
  2. Drag and drop your DLV profile.json file onto dlv_profile_tool.bat.
  3. Choose D to decrypt it.
  4. Edit the JSON file.
  5. Drag and drop the same file onto the bat again.
  6. Choose E to encrypt it back.
  7. Restore it with JKSV.

Make a full backup before editing your save.

For item IDs, this user-friendly list is useful:

Disney Dream Light ID List

For a more complete raw item dump, you can also check:

KOSDDV DDV Item Dump

Do not delete every matching item ID blindly. The same ID can appear in inventory, unlock data, catalogue data, hidden-marker data, placed object data, and other sections.

If you need to remove a stuck placed object, look for the placed-world/grid entry with position data such as ItemID, X, Y, and Orientation.

I like decorating, and I wanted to use the same player house skin in multiple places.

While looking through debug items, I found a player-house-looking object from the Halloween event area: the witch potion shop. It is not actually enterable as a house, but visually it looked perfect. It also did not have the “keep out” sign in front of the door, so it looked like a clean decorative building.

I placed it in the Forgotten Lands, closed furniture mode, and was happy with how good it looked. Then I opened furniture mode again because I wanted to move it to a better spot.

That was when I noticed the problem.

When I moved the cursor over the debug item, it did not highlight as selectable. It behaved almost like an off-grid object. I could not select it, move it, or remove it.

I first tried making a cheat code to force normally unremovable objects to become removable. That worked for things like flowers, rocks, and other normal world objects, but it did not help with this debug item. I still could not even select it.

So I decrypted my profile.json and removed it manually from the save data.

The item name was:

Code:
WitchDungeon

I searched for it in the item ID spreadsheet and found the item ID:

Code:
40004634

Then I searched for 40004634 in the decrypted save.

One result was this:

Code:
"40004634": {
"Amount": 998,
"Marker": "ItemMarker_Hidden"
}

This is not the placed object. This kind of entry is inventory / ownership / furniture-menu data. In this case, it also shows that the item is hidden in the furniture menu. Do not delete entries like this when your goal is to remove a stuck placed object.

The placed object entry looked like this:

Code:
"1526": {
"ID": 1526,
"ItemID": 40004634,
"X": 389,
"Y": 84,
"Orientation": "GridOrientation_Up",
"State": null
}

The important clue is that this entry has placement data: ItemID, X, Y, and Orientation. That means it is an object placed on the world grid.

In my case, this was the part I removed:

Before:

Code:
"1525": {
"ID": 1525,
"ItemID": 40600030,
"X": 392,
"Y": 62,
"Orientation": "GridOrientation_DownLeft",
"State": null
},
"1526": {
"ID": 1526,
"ItemID": 40004634,
"X": 389,
"Y": 84,
"Orientation": "GridOrientation_Up",
"State": null
}

After:

Code:
"1525": {
"ID": 1525,
"ItemID": 40600030,
"X": 392,
"Y": 62,
"Orientation": "GridOrientation_DownLeft",
"State": null
}

I removed the whole 1526 block and also removed the comma after the previous entry so the JSON structure stayed valid.

After encrypting the file again and restoring it with JKSV, the stuck debug item was gone.

When editing the save manually, the basic rule is: do not just delete every matching item ID. First identify what kind of data you are looking at. Inventory, unlock, catalogue, hidden-marker, and placed-world data are different things. For a stuck placed object, you usually want the placed-world/grid entry with coordinates, not the ownership entry.

Also be careful not to break the JSON structure. If you remove an object block, make sure the previous and next entries still have valid commas and braces. Using a text editor with JSON validation helps a lot.

The save data is fairly readable once decrypted, so this can be useful for recovering from stuck objects or removing things the game normally will not let you select. It can also make decoration experiments safer, especially when using debug items.

Always keep a full backup of your save before doing this. Use at your own risk.

It is recommended to test the tool once without making any edits: decrypt the save, encrypt it back, restore it, and confirm that the game loads.

Use at your own risk. This is not a full save editor. It is only a simple decrypt/encrypt tool for manual profile editing.





This tool is mainly for manual profile editing, so it can also be useful for other save edits, not only removing stuck grid objects.

For more save editing methods and examples, check @dreamlightcollecter’s profile posts
 

Attachments

Last edited by morarin,
Using your explanation for the fishing, I was able to update my game codes all except most of the "get all" codes. When time allows for you, a walkthrough of how you made the vanelope cheat, and maybe how you did one of the big "get all" cheats would be extremely helpful if you're up to it. No rush because I have a long drawn out method that works, but it can definitely be easier than I'm making it. Thanks!

This section explains the basic knowledge needed to read and reproduce the four GetAll codes.

It does not explain how to run Il2CppDumper, load the `main` file into IDA, or apply names from `script.json`. Those steps were covered previously.

The goal here is to explain:

  • How to read the useful information in `dump.cs`
  • How that information relates to ARM64 instructions
  • How to find suitable game functions
  • How to plan a hook and code cave
  • How to preserve the original game state safely

The examples use fields and functions that also appear in the GetAll codes.

Addresses and field offsets can change after a game update and must always be checked again.

`dump.cs` is one of the files produced by Il2CppDumper from the game’s `main` file and `global-metadata.dat`.

It is not the original source code written by the developers.

Instead, it reconstructs information such as:

  • Namespaces
  • Classes
  • Fields
  • Properties
  • Methods
  • Method arguments and return types
  • Enums
  • Interfaces
  • Field offsets
  • Method RVAs

For example:

Code:
public sealed class ClothingItemData : IItemData
{
private UnknownFieldSet *unknownFields; // 0x10
private int iD*;                        // 0x18

```
public Item Item { get; }

// RVA: 0x4445010
public Item get_Item();
```

}

This tells us that:

  • A class named `ClothingItemData` exists.
  • It implements the `IItemData` interface.
  • It contains an integer field named `iD_` at offset `+0x18`.
  • It has an `Item` property.
  • The native getter can be found through its RVA.

What `dump.cs` usually does not show is the actual method body.

For that, the native function must be examined in IDA.

A useful way to separate their roles is:

Code:
dump.cs:
What classes, fields and functions exist?

IDA:
What does the native code actually do?

Xrefs:
How does the game call and use that code?

GDB:
What happens when the code runs?

Class

A class describes the data and functions belonging to one kind of object.

It can be thought of as a template.

For example:

Code:
public sealed class ClothingItemData
{
private int iD_; // 0x18
}

This says that a `ClothingItemData` object contains an `iD_` field.

The class declaration itself is not one particular clothing item.

Object or instance

An object, also called an instance, is one actual piece of data created from that class.

Conceptually:

Code:
ClothingItemData class
|
+-- clothing item-data object A
+-- clothing item-data object B
+-- clothing item-data object C

Each object has its own field values.

In ARM64 code, a register such as X0 often contains a pointer to one of these objects:

Code:
X0 = ClothingItemData*

The asterisk means that X0 contains the address of the object, not the complete object itself.

An instruction such as:

Code:
LDR W1, [X0,#0x18]

means:

Code:
Read a 32-bit value from:
object address + 0x18

Store that value in:
W1

If X0 points to a `ClothingItemData` object, the value at `+0x18` is its `iD_` field.

A class contains several different kinds of members.

Fields

Fields store the actual data belonging to an object.

Example:

Code:
private int iD_; // 0x18

This line contains three useful pieces of information:

Code:
Type:    int
Name:    iD_
Offset:  0x18

The offset is the distance from the start of the object.

If X0 points to the object:

Code:
LDR W1, [X0,#0x18]

reads `iD_`.

A reference-type field stores a pointer to another object.

Example:

Code:
private Profile profile; // 0xB8

Because `Profile` is an object reference, it is read with an X register:

Code:
LDR X0, [X19,#0xB8]

Properties

A property provides a controlled way to read or change data.

Example:

Code:
public Item Item { get; }

The corresponding getter is normally shown separately:

Code:
public Item get_Item();

The getter may simply return a field.

For example:

Code:
LDR W19, [X19,#0x18]
MOV W0, W19
RET

This shows that `get_Item()` reads the value at `+0x18` and returns it.

The GetAll codes use the same verified field access directly:

Code:
LDR W1, [X0,#0x18]

Methods

Methods are functions belonging to a class.

Example:

Code:
public int GetItemAmount(
Item item,
ItemState state
);

This tells us:

  • The method returns an `int`.
  • It accepts an `Item`.
  • It accepts an `ItemState`.
  • It belongs to the class in which it is declared.

Constructors

A constructor initializes a newly created object.

It normally has the same name as the class:

Code:
public ClothingItemData();

The GetAll codes mostly use objects already created by the game, so constructors are not a major part of these explanations.

Static members

A static member belongs to the class itself rather than one particular instance.

Example:

Code:
public static ItemDatabase Instance { get; }

This is used as:

Code:
ItemDatabase.Instance

The GetAll codes call its native getter to obtain the game’s shared ItemDatabase object.

Nested types

A class may contain another class, struct or enum.

Examples:

Code:
ListInventory.Types.Data
ItemState.StateOneofCase

The full name shows which outer class contains the nested type.

Class

A class is normally a reference type.

A variable or register contains a pointer to the object.

Example:

Code:
private Profile profile; // 0xB8

Native access:

Code:
LDR X0, [X19,#0xB8]

X0 receives a `Profile*`.

Struct

A struct is a value type.

Its value may be stored directly rather than through a separate object pointer.

Examples include:

Code:
CancellationToken
ValueTuple<ItemType, Enum, Type>

Most ordinary structs do not require special handling in these codes.

The important exception is the shared generic SubType code. Its generic enum value is placed in memory, and a pointer to that value is passed to the function:

Code:
STR W8, [SP,#0x10]
ADD X2, SP,#0x10

The detailed reason is explained in the SubType section.

Interface

An interface defines functionality that several different classes provide.

Example:

Code:
public interface IItemData
{
Item get_Item();
}

Many different item-data classes implement it:

Code:
ClothingItemData
FurnitureItemData
BuildingItemData
PetItemData
MemoryShardItemData

This allows ItemDatabase to return them through one common type:

Code:
IEnumerable<IItemData>

The array elements are typed as `IItemData`, but each element still points to a concrete item-data object.

Enum

An enum gives names to integer values.

Example:

Code:
public enum ItemType
{
Building    = 2,
Furniture   = 4,
Clothing    = 5,
Companion   = 12,
MemoryShard = 13
}

Therefore:

Code:
MOV W1, #5

can represent:

Code:
ItemType.Clothing

The SubType code uses a second enum in addition to the broad ItemType:

Code:
BuildingItemType.PlayerHouse = 5
CompanionItemType.Mount      = 3

Consider this simplified class:

Code:
public sealed class MemoryShardItemData : IItemData
{
private int iD_;             // 0x18
private int numberOfShards_; // 0x68

```
public Item Item { get; }
public int NumberOfShards { get; set; }
```

}

From this class information, we can determine:

Code:
MemoryShardItemData + 0x18 = Item
MemoryShardItemData + 0x68 = NumberOfShards

If X0 points to a `MemoryShardItemData` object:

Code:
LDR W1, [X0,#0x18]
LDR W9, [X0,#0x68]

means:

Code:
W1 = Item
W9 = NumberOfShards

Field size and register size

For the values used in these codes:

Code:
int / enum / most bool values
-> W register

object reference / pointer
-> X register

Examples:

Code:
private int amount_; // 0x18

is read with:

Code:
LDR W0, [X8,#0x18]

while:

Code:
private Profile profile; // 0xB8

is read with:

Code:
LDR X0, [X19,#0xB8]

Method signatures

Example:

Code:
public int GetItemAmount(
Item item,
ItemState state
);

The method returns an integer and accepts two explicit arguments.

Because it is an instance method, it also needs a pointer to the object on which it is called.

The native argument layout is approximately:

Code:
X0 = ProfilePlayer* this
W1 = Item
X2 = ItemState*
W0 = returned int

RVA

Il2CppDumper often shows an RVA above a method:

Code:
// RVA: 0x549E740
public int GetItemAmount(...);

RVA means Relative Virtual Address.

IDA converts this into an address using the module’s image base:

Code:
native address = image base + RVA

The RVA helps locate the native implementation in IDA.

ARM64 normally passes the first arguments through X0–X7 or their 32-bit W equivalents.

Instance method example

C#:

Code:
player.GetItemAmount(item, null);

Native arguments:

Code:
X0 = ProfilePlayer*
W1 = Item
X2 = null

The method returns an integer, so the result is placed in W0:

Code:
BL  ProfilePlayer.GetItemAmount

// After the call:
W0 = current item amount

Object return example

A function returning an object pointer normally returns it in X0:

Code:
BL ItemDatabase.get_Instance

// After the call:
X0 = ItemDatabase*

Important consequence

X0 is commonly used for both:

  • The current function argument
  • The next function’s return value

A value stored only in X0 should not be expected to survive another function call.

If a value is needed later, it must be moved to a suitable saved register or stored on the stack.

MethodInfo

IL2CPP native methods may have an additional `MethodInfo*` argument after their normal arguments.

Many ordinary methods do not use it directly.

Shared generic methods may require it to identify the concrete generic types.

The SubType code therefore passes a concrete MethodInfo pointer in X3:

Code:
X0 = ItemDatabase*
W1 = ItemType
X2 = pointer to SubType value
X3 = MethodInfo*

The full generic behavior is explained in the SubType section.

These three terms are related but not identical.

IEnumerable<T>

`IEnumerable<T>` means that a sequence can be enumerated one element at a time.

It does not by itself describe the exact underlying storage.

List<T>

`List<T>` is a resizable collection.

It stores an internal array and separately tracks how many elements are currently in use.

T[]

`T[]` is a fixed-length array.

The normal GetAllByType declaration returns:

Code:
IEnumerable<IItemData>

but its native implementation calls:

Code:
ToArray<IItemData>()

The actual returned object can therefore be handled as:

Code:
IItemData[]

The array layout used by the game is:

Code:
array + 0x18 = number of elements
array + 0x20 = first element

The GetAll loop prepares these values with:

Code:
ADD X20, X0, #0x20
LDR W21, [X0,#0x18]

After this:

Code:
X20 = address of the first element
W21 = array length

An `IItemData[]` contains object references.

Each reference is eight bytes on this 64-bit build.

The current element is loaded with:

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

`LSL #3` multiplies the index by eight:

Code:
element address =
first element + index * 8

The array contains pointers to item-data objects, not raw Item values.

The Item is read from the selected object afterward:

Code:
LDR W1, [X0,#0x18]

A useful search usually starts with the desired game behavior.

1. Describe the goal simply

Examples:

Code:
Get the current furniture amount.

Find every clothing item.

Complete a memory.

Get only PlayerHouse buildings.

2. Search for relevant nouns

Examples:

Code:
Furniture
Inventory
MemoryShard
ItemDatabase
ProfilePlayer
Building
Companion

3. Search for relevant verbs

Examples:

Code:
Get
Add
TryGet
Unlock
Complete
IsCompleted
GetAll

A search for:

Code:
GetItemAmount

is more likely to find a useful function than searching only for:

Code:
amount

4. Check the arguments and return value

Do not rely only on the function name.

Example:

Code:
public int GetItemAmount(
Item item,
ItemState state
);

This is useful because it accepts an Item and returns an integer amount.

5. Check related fields and enums

If a method uses an ItemType, find its enum values.

If it reads an inventory object, find the relevant class fields.

6. Open the RVA in IDA

The method declaration identifies the candidate.

The native function shows whether the candidate actually performs the required operation.

7. Check Xrefs

If the correct way to call a function is unclear, inspect its callers.

A caller can reveal:

  • Which object is placed in X0
  • Which values are placed in X1–X3
  • Whether a MethodInfo pointer is required
  • How the return value is used
  • Whether preparation is required before the call

Compiler-generated names also provide clues:

Code:
get_Name
property getter

set_Name
property setter

<MethodName>b__0
lambda or compiler-generated callback

<MethodName>g__LocalName|...
local function

<>c__DisplayClass
object used to store values captured by a lambda

ARM64 provides 64-bit X registers and corresponding 32-bit W registers.

Examples:

Code:
X0 = 64-bit register
W0 = lower 32 bits of X0

Writing to W0 clears the upper half of X0.

The GetAll codes mainly use the following registers.

Code:
X0-X7
Main function arguments and return values

X8-X18
Temporary registers
A called function may overwrite them

X19-X28
Callee-saved registers
Useful for values that must survive function calls

X29
Frame pointer

X30
Link register
BL and BLR store the return address here

SP
Stack pointer

XZR / WZR
Zero register

The most important difference is:

Code:
X0-X18:
Do not assume the value survives a function call.

X19-X28:
A called function must preserve these registers.

The custom routine must still restore any X19–X28 registers that it changes before returning to the original game function.

A basic function call looks like:

Code:
MOV X0, objectPointer
MOV W1, value
BL  targetFunction

`BL` does two things:

  • It stores the address of the next instruction in X30.
  • It jumps to the target function.

The called function eventually returns through X30.

Why X30 must be saved

The hook enters the code cave with:

Code:
BL CodeCave

X30 now contains the address where the original function should continue.

If the code cave performs another `BL`, X30 is overwritten.

The original return address must therefore be saved first:

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

Why long-lived values use X19-X28

The furniture code needs the current ItemData pointer both before and after calling `GetItemAmount`.

It stores that pointer in X23:

Code:
LDR X23, [X20,X22,LSL #3]

BL  ProfilePlayer.GetItemAmount

LDR W1, [X23,#0x18]

X23 survives the function call because it is callee-saved.

Stack alignment

SP should remain aligned to 16 bytes when calling functions.

The custom routines therefore allocate stack space in multiples of 16 bytes.

Only the instructions commonly used by these codes are listed here.

Moving values

Code:
MOV W1, #5

Place the value 5 in W1.

Code:
MOV X3, XZR

Set X3 to zero.

Loading and storing memory

Code:
LDR X0, [X19,#0xB8]

Read a 64-bit value from `X19 + 0xB8`.

Code:
LDR W1, [X0,#0x18]

Read a 32-bit value from `X0 + 0x18`.

Code:
STR W8, [SP,#0x10]

Store W8 at `SP + 0x10`.

Saving and restoring register pairs

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

Move SP down by 16 bytes and save X19 and X30.

Code:
LDP X19, X30, [SP],#0x10

Restore X19 and X30, then move SP back up by 16 bytes.

Arithmetic

Code:
ADD W22, W22, #1

Increase W22 by one.

Code:
SUBS W2, W2, W0

Subtract W0 from W2 and update the condition flags.

Code:
LSL W24, W9, W8

Shift W9 left by the amount in W8.

Code:
LSR W8, W8, W10

Shift W8 right by the amount in W10.

Code:
ORR W8, W8, W24

Perform a bitwise OR.

Comparison

Code:
CMP W22, W21

Compare W22 and W21.

Code:
TST W24, W8

Test whether W24 and W8 share any set bits.

Branches and calls

Code:
B target

Jump to `target` without saving a return address.

Code:
BL function

Call a direct address and save the return address in X30.

Code:
BR X8

Jump to the address stored in X8.

Code:
BLR X8

Call the address stored in X8 and save the return address in X30.

Code:
RET

Return through X30.

Conditional branches include:

Code:
B.EQ    equal
B.NE    not equal
B.LT    less than
B.LE    less than or equal
B.GT    greater than
B.GE    greater than or equal

Other useful conditional branches include:

Code:
CBZ X0, target

Branch if X0 is zero.

Code:
TBZ W8, #0, target

Branch if bit zero of W8 is clear.

NOP

Code:
NOP

Perform no meaningful operation and continue to the next instruction.

Replacing a conditional branch with NOP removes that branch while preserving the original four-byte instruction position.

Long calls

A direct `BL` has a limited range.

For a distant target, the address can be constructed in a register:

Code:
ADRP X8, target_page
ADD  X8, X8, #target_offset
BLR  X8

This method is used by the SubType code to call its metadata helper.

A hook redirects execution from an existing game function to custom code.

The basic flow is:

Code:
Original game function
|
v
Custom code cave
|
v
Original game function continues

The GetAll codes replace this original instruction:

Code:
MOV X0, X19

with:

Code:
BL CodeCave

The custom routine performs its work and then recreates the effect of:

Code:
MOV X0, X19

before returning.

A hook does not automatically preserve the original function state.

The custom routine is responsible for:

  • Saving registers it changes
  • Preserving the original return address
  • Restoring SP
  • Recreating the overwritten instruction
  • Returning to the correct continuation address

A hook should be placed at a predictable and safe execution point.

The Wardrobe menu was selected because:

  • The first GetAll code was created for clothing.
  • Opening the menu is a clear manual trigger.
  • The game systems needed by the code are already available.
  • Testing does not require reloading the entire game.
  • The function is not called continuously every frame.

The exact instruction selected for the hook was:

Code:
MOV X0, X19

This is a convenient instruction to replace because:

  • Its behavior is simple.
  • It does not access memory.
  • It does not change condition flags.
  • Its effect can be recreated easily.

When selecting another hook position, check that:

  • The overwritten instruction can be safely reproduced.
  • The instruction is not one half of a related address-building sequence.
  • No important branch enters the middle of the overwritten region.
  • The required game systems are initialized.
  • The custom code will not run too frequently.
  • Execution can safely continue afterward.

A breakpoint in IDA/GDB can be used to confirm that the selected function is triggered by the expected game action.

A code cave is unused executable space where custom ARM64 instructions can be placed.

For these codes, the cave was found near the end of the `.text` segment.

1. Open the Segments view

Find the addresses of:

Code:
.text
.rodata
.data

Custom executable code should be placed in an executable region such as `.text`.

2. Go to the end of .text

Inspect the final defined function.

In this version, the last existing function ends at:

Code:
0x7108CB4114

The next aligned address is:

Code:
0x7108CB4118

3. Find the next segment

The next `.rodata` segment begins at:

Code:
0x7108CB5000

The candidate unused range is therefore:

Code:
0x7108CB4118 - 0x7108CB4FFF

4. Calculate the available size

Code:
0x7108CB5000 - 0x7108CB4118
= 0xEE8 bytes

ARM64 instructions are normally four bytes each.

A routine containing 25 instructions requires:

Code:
25 * 4 = 100 bytes = 0x64

5. Confirm that the area is actually unused

Do not assume that every sequence of zero bytes is safe.

Check that:

  • IDA has not defined functions or data there.
  • There are no Xrefs into the region.
  • It is not part of a jump table or relocation data.
  • The custom code does not overlap `.rodata`.
  • The start address is four-byte aligned.
  • Another cheat code is not already using the same area.

The code cave must be checked again after every game update.

Do not begin by writing ARM64 instructions immediately.

First write the intended operation as simple pseudocode.

For the Clothing code:

Code:
client = MissionManager.MetaClient
database = ItemDatabase.Instance
items = database.GetAllByType(ItemType.Clothing)

for each itemData in items:
item = itemData.Item
client.DebugAddItem(item, 1, default)

Next, identify which values must survive function calls:

Code:
Client pointer
Array data pointer
Array length
Current array index

Assign them to callee-saved registers:

Code:
X19 = Client*
X20 = address of first array element
W21 = array length
W22 = current index

Temporary values can use the normal argument registers:

Code:
X0 = current object / this pointer
W1 = Item
W2 = amount
X3 = ItemState or MethodInfo

A normal code-cave plan is:

  1. Save the original registers and X30.
  2. Obtain the required game objects.
  3. Call the function that returns the target collection.
  4. Prepare the loop state.
  5. Load and process each element.
  6. Advance the loop index.
  7. Restore all saved registers.
  8. Recreate the overwritten instruction.
  9. Return to the original function.

Each time another function call is added, check:

  • Which values are still needed afterward
  • Whether those values are stored in safe registers
  • Whether X30 has already been saved
  • Whether SP remains aligned

The stack is used mainly for:

  • Saving original register values
  • Providing temporary memory

Example:

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

This:

  • Subtracts 16 bytes from SP
  • Stores X19 at the new SP
  • Stores X30 at SP + 8

The matching restore is:

Code:
LDP X19, X30, [SP],#0x10

This restores both registers and returns SP to its previous value.

Temporary stack space

The SubType code uses:

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

This allocates 32 bytes.

The first 16 bytes hold X21 and X22.

The remaining 16 bytes can be used as temporary storage:

Code:
STR W8, [SP,#0x10]
ADD X2, SP,#0x10

This stores the SubType value and passes its address in X2.

Basic stack rules

  • Allocate space in multiples of 16 bytes.
  • Do not overwrite saved registers with temporary data.
  • Restore registers in the reverse order.
  • Return SP to its original value before leaving.

A mismatched `STP` and `LDP` sequence can corrupt the original function or cause a crash.

Static analysis is not enough by itself.

The complete process uses several sources of information:

Code:
dump.cs
Find names, types, fields, enums and RVAs.

IDA
Read the actual ARM64 implementation.

Xrefs
Find examples of how the game calls a function.

GDB
Confirm that a function is triggered and inspect registers.

Hardware testing
Confirm the final game behavior.

Test changes in stages

A new routine is easier to debug when built gradually:

  1. Confirm that the hook is triggered.
  2. Confirm that the code cave is reached.
  3. Add the Client getter.
  4. Add the ItemDatabase getter.
  5. Call the collection function.
  6. Inspect the returned pointer and length.
  7. Process one item.
  8. Add the full loop.
  9. Add any special patches afterward.

If a crash begins after one stage, the cause is easier to isolate.

Record original instructions

For every patch, record both states:

Code:
Original:
0x7104CAE434    CBZ W8, failure

Patched:
0x7104CAE434    NOP

The original instruction is required to disable the code safely and to locate the equivalent logic after an update.

Values that may change after an update

Always verify:

  • Function RVAs
  • Hook addresses
  • Instructions being overwritten
  • Branch destinations
  • Field offsets
  • Method$ entries
  • Shared generic implementations
  • Metadata helper addresses
  • The end of `.text`
  • The available code-cave range

Do not assume that every address moved by the same amount.

The goal when updating is to find the same functions and the same logical operations, not merely to apply one global offset.

Common mistakes

  • Confusing an ItemData pointer with the Item value itself
  • Using an X load for a 32-bit field
  • Expecting X0 to survive another function call
  • Using X19-X28 without restoring them
  • Calling another function without saving X30
  • Breaking the 16-byte stack alignment
  • Forgetting to recreate the overwritten hook instruction
  • Confusing a Method$ slot address with the MethodInfo stored in it
  • Confusing a List object with an array
  • Reusing an old code cave without checking the updated executable
  • Triggering an asynchronous GetAll code again before processing is complete

The following four sections build on this common foundation:

  1. Get All Clothing Items
  2. Raise Every Furniture Inventory Amount to 999
  3. Get All Items by SubType
  4. Unlock All Memories

The Clothing code introduces the basic ItemDatabase loop.

The Furniture code adds an inventory amount check.

The SubType code adds a shared generic method call.

The Memory code adds multiple function patches and bitmask handling.

This explains how to reproduce the ARM64 code that retrieves every clothing item from the game’s ItemDatabase and submits each Item to DebugAddItem.

The addresses used below are for:

Code:
Disney Dreamlight Valley v1.23.0
Title ID: 0100D39012C1A800
Build: v3801088

The finished routine does this:

Code:
client = MissionManager.MetaClient
database = ItemDatabase.Instance
items = database.GetAllByType(ItemType.Clothing)

for each itemData in items:
item = itemData.Item
client.DebugAddItem(item, 1, default)

In ARM64 terms:

Code:
Get the Client pointer
Get the ItemDatabase pointer
Call GetAllByType(Clothing)
Read the returned array length
Read each IItemData pointer from the array
Read Item from itemData + 0x18
Call DebugAddItem(Item, 1, default)

The routine does not wait for each returned Task. It submits all requests and lets the game process them afterward.

The game broadly uses two inventory systems.

Container inventories include the backpack and storage chests. These normally store stackable activity items such as materials, fish and food.

List inventories contain unlocked entries such as clothing, furniture, buildings and companions.

My first attempt directly added clothing to a list inventory. The item appeared in the Wardrobe and could be previewed, but an outfit using it could not be saved correctly.

That meant the entry was visible, but the complete acquisition process had not been performed.

Searching dump.cs for another item-addition method led to:

Code:
public Task<DebugAddItem.Types.Response> DebugAddItem(
Item item,
int amount,
CancellationToken ct
)

Native address:

Code:
Meta.Online.Client$$DebugAddItem
RVA:     0x5B5DD30
Address: 0x7105B5DD30

The native function receives:

Code:
X0 = Client*
W1 = Item
W2 = amount
X3 = CancellationToken

Its beginning preserves those arguments:

Code:
MOV X19, X3
MOV W22, W2
MOV X23, X1
MOV X21, X0

It then creates a DebugAddItem request and stores the Item and amount:

Code:
STP W23, W22, [X0,#0x18]

The request fields are:

Code:
private int itemID_;  // 0x18
private int amount_;  // 0x1C

The function finally submits the request through the transaction service.

Using this method lets the game perform its own acquisition processing instead of manually changing only one inventory structure.

Calling DebugAddItem initially produced no item, but it did not crash.

The rejection was found inside:

Code:
Meta.DebugAddItem.Types.Response$$ApplyThis

Relevant native code:

Code:
0x7104CAE420    LDR   X8, [X19]
0x7104CAE424    CBZ   X8, failure
0x7104CAE428    LDR   X8, [X8,#0x20]
0x7104CAE42C    CBZ   X8, failure
0x7104CAE430    LDRB  W8, [X8,#0x40]
0x7104CAE434    CBZ   W8, 0x7104CAE46C

The destination of the final branch is:

Code:
0x7104CAE46C    MOV   W8, #1
0x7104CAE470    STR   W8, [X22,#0x18]

The Result enum contains:

Code:
Success       = 0
NotDeveloper  = 1
InvalidItem   = 2
InventoryFull = 3

The branch therefore sends the transaction to:

Code:
response.Result = NotDeveloper

The patch is:

Code:
Original:
0x7104CAE434    CBZ W8, 0x7104CAE46C

Patched:
0x7104CAE434    NOP

This does not change the original flag. It only prevents this transaction from branching to the NotDeveloper result path.

The goal was to obtain every clothing Item without maintaining a manual list of Item IDs.

The relevant class fields in dump.cs are:

Code:
public class ItemDatabase
{
private readonly Dictionary<Item, IItemData> allItems; // 0x10

```
private readonly Dictionary<
    ValueTuple<ItemType, Enum, Type>,
    Array
> cachedSearchs; // 0x38
```

}

The relevant method is:

Code:
public IEnumerable<IItemData> GetAllByType(ItemType itemType)

Native address:

Code:
Definitions.Items.ItemDatabase$$GetAllByType
RVA:     0x4A85F80
Address: 0x7104A85F80

The ItemType value used for clothing is:

Code:
ItemType.Clothing = 5

The class information already gives us two useful facts:

  • The source collection maps Item to IItemData.
  • Search results are cached as Array objects.

The native function confirms both.

It loads the field at ItemDatabase + 0x10:

Code:
0x7104A86134    ADRP  X8, System.Func<...bool>_TypeInfo
0x7104A86138    LDR   X21, [X19,#0x10]

From the class layout:

Code:
ItemDatabase + 0x10 = Dictionary<Item, IItemData> allItems

The result cache is also read through ItemDatabase + 0x38:

Code:
0x7104A860E0    LDR   X22, [X19,#0x38]

From the class layout:

Code:
ItemDatabase + 0x38 =
Dictionary<ValueTuple<ItemType, Enum, Type>, Array> cachedSearchs

The important part of GetAllByType is the LINQ chain.

First, the function constructs the predicate and calls Where:

Code:
0x7104A86144    ADRP  X8, Method$ItemDatabase.<GetAllByType>b__0
0x7104A86148    MOV   X1, X20              // display-class object
0x7104A8614C    LDR   X2, [X8,...]         // predicate method
0x7104A86154    MOV   X22, X0
0x7104A86158    BL    System.Func...ctor

0x7104A8615C    ADRP  X8, Method$Enumerable.Where<...>
0x7104A86160    MOV   X0, X21              // allItems
0x7104A86164    LDR   X2, [X8,...]
0x7104A86168    MOV   X1, X22              // predicate
0x7104A8616C    BL    Enumerable.Where

It then constructs the selector and calls Select:

Code:
0x7104A861CC    ADRP  X8, Method$ItemDatabase.<GetAllByType>b__15_1
0x7104A861D0    MOV   X1, X23              // closure object
0x7104A861D4    LDR   X2, [X8,...]         // selector method
0x7104A861DC    MOV   X22, X0
0x7104A861E0    BL    System.Func...ctor

0x7104A86230    ADRP  X8, Method$Enumerable.Select<
KeyValuePair<Item,IItemData>,
IItemData>
0x7104A86234    MOV   X0, X21              // filtered source
0x7104A86238    LDR   X2, [X8,...]
0x7104A8623C    MOV   X1, X22              // selector
0x7104A86240    BL    Enumerable.Select

Finally, it converts the selected sequence to an array:

Code:
0x7104A86244    ADRP  X8, Method$Enumerable.ToArray<IItemData>
0x7104A86248    LDR   X1, [X8,...]
0x7104A8624C    BL    Enumerable.ToArray<IItemData>

The generated array is then inserted into the Array-valued cache:

Code:
0x7104A8625C    LDR   X19, [X19,#0x38]     // cachedSearchs
...
0x7104A86280    LDP   X8, X2, [X29,...]    // key and value
...
0x7104A86294    ADRP  X8, Method$Dictionary<...,Array>.Add
0x7104A86298    LDR   X3, [X8,...]          // value
0x7104A862A0    BL    Dictionary<...,Array>.Add

The concrete result is therefore:

Code:
IItemData[]

even though the public return type is:

Code:
IEnumerable<IItemData>

The predicate function is:

Code:
ItemDatabase.<>c__DisplayClass15_0.<GetAllByType>b__0

Its input is:

Code:
KeyValuePair<Item, IItemData>

It first obtains the dictionary key through:

Code:
KeyValuePair<Item, IItemData>.get_Key()

After the generic getter has copied the Item value to the local stack area, the relevant comparison is:

Code:
0x7104AC0FD8    LDR   W20, [X29,...]       // dictionary Key: Item
...
0x7104AC1004    LDR   W9, [X19,#0x10]      // requested ItemType
0x7104AC1008    LDR   W8, [X8,#4]          // Item type divisor
0x7104AC100C    SDIV  W8, W20, W8           // derive ItemType from Item
0x7104AC1010    CMP   W8, W9
0x7104AC1014    B.NE  return_false

If the ItemType matches, it obtains the Value:

Code:
0x7104AC1018    ADRP  X8, Method$KeyValuePair<Item,IItemData>.get_Value
...
0x7104AC111C    BL    memcpy
0x7104AC1120    LDR   X8, [X29,...]         // returned IItemData*
0x7104AC1124    CMP   X8, #0
0x7104AC1128    CSET  W0, NE

The predicate is therefore equivalent to:

Code:
entry =>
GetItemType(entry.Key) == requestedItemType
&& entry.Value != null

For this routine:

Code:
requestedItemType = Clothing = 5

The selector is:

Code:
ItemDatabase.<>c.<GetAllByType>b__15_1

Its signature is:

Code:
IItemData* selector(
KeyValuePair<Item, IItemData> entry
)

The function resolves and calls:

Code:
KeyValuePair<Item, IItemData>.get_Value()

Relevant excerpt:

Code:
0x7104AC09FC    ADRP  X8, Method$KeyValuePair<Item,IItemData>.get_Value
0x7104AC0A00    LDR   X19, [X8,...]
...
0x7104AC0A8C    BL    memcpy
0x7104AC0A90    LDUR  X0, [X29,#s]
0x7104AC0A94    LDP   X20, X19, [...]
0x7104AC0AA0    RET

The returned X0 is the Value side of the dictionary entry.

The selector is therefore equivalent to:

Code:
entry => entry.Value

This proves that the final array contains:

Code:
IItemData object references

It does not contain raw Item values.

The complete data flow is:

Code:
Dictionary<Item, IItemData> allItems
|
| Where:
| - derive ItemType from entry.Key
| - compare it with Clothing
| - reject null Values
v
matching KeyValuePair<Item, IItemData> entries
|
| Select:
| - return entry.Value
v
IEnumerable<IItemData>
|
| ToArray<IItemData>()
v
IItemData[]

The custom code treats the returned object as a native IL2CPP array:

Code:
array + 0x18 = element count
array + 0x20 = element storage

This layout can be confirmed from the game’s own direct array access.

Inside DebugAddItem.ApplyThis, the game walks an ItemType array.

It reads the array length from +0x18:

Code:
0x7104CAE5A4    ADD    X28, X28, #1
0x7104CAE5A8    LDRSW  X8, [X25,#0x18]
0x7104CAE5AC    CMP    X28, X8
0x7104CAE5B0    B.GE   loop_end

It reads the current element from +0x20:

Code:
0x7104CAE5B4    ADD   X8, X25, X28, LSL #2
0x7104CAE5C0    LDR   W25, [X8,#0x20]

The effective address is:

Code:
array + 0x20 + index * 4

`ItemType` is a 32-bit value, so each element occupies four bytes:

Code:
LSL #2 = index * 4

The same header is used for an array of object references.

An `IItemData[]` element is a 64-bit pointer, so each element occupies eight bytes:

Code:
array + 0x20 + index * 8

Therefore the custom code uses:

Code:
ADD X20, X0, #0x20
LDR W21, [X0,#0x18]

After these instructions:

Code:
X20 = address of the first IItemData reference
W21 = number of IItemData references

The current element is loaded with:

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

Because:

Code:
LSL #3 = index * 8

this is equivalent to:

Code:
X0 = items[index]

The array contains pointers:

Code:
array + 0x20 -> IItemData* #0
array + 0x28 -> IItemData* #1
array + 0x30 -> IItemData* #2
array + 0x38 -> IItemData* #3

The `IItemData` interface contains:

Code:
public interface IItemData
{
int  get_ID();    // Slot 0
Item get_Item();  // Slot 1
}

The object returned from the array is therefore an item-data object that exposes an Item value.

The common item-data layout can be seen in `DefaultItemData`:

Code:
public sealed class DefaultItemData : ..., IItemData
{
private UnknownFieldSet _unknownFields; // 0x10

```
public const int IDFieldNumber = 1;
private int iD_;                        // 0x18

public Item Item { get; }

public Item get_Item();                 // Slot 16
```

}

The native getter reads the field at +0x18:

Code:
0x710435CBA4    MOV   X19, X0
...
0x710435CBB4    LDR   W19, [X19,#0x18]
...
0x710435CBC4    MOV   W0, W19
0x710435CBD4    RET

The fallback initialization path reads the same field:

Code:
0x710435CBF8    LDR   W19, [X19,#0x18]
...
0x710435CC0C    MOV   W0, W19
0x710435CC1C    RET

`ClothingItemData` follows the same layout:

Code:
private UnknownFieldSet *unknownFields; // 0x10
private int iD*;                        // 0x18
public Item Item { get; }

Its native getter also reads +0x18:

Code:
0x7104445014    MOV   X19, X0
...
0x7104445024    LDR   W19, [X19,#0x18]
...
0x7104445034    MOV   W0, W19
0x7104445044    RET

The direct load used by the custom routine is therefore:

Code:
LDR W1, [X0,#0x18]

At that point:

Code:
X0 = current IItemData object pointer
W1 = current Item

This does not call `get_Item`; it directly performs the field load used by the getter.

During development, I checked the item-data classes for every item category and confirmed that the Item/ID backing field is located at +0x18.

The same direct load was also tested with every item category handled by this GetAll pattern and worked correctly.

Therefore, in this game version, the shared rule is:

Code:
IItemData implementation + 0x18 = Item

This is not limited to ClothingItemData.

It should still be checked again after a game update because native object layouts are version-specific.

The game’s own bulk-unlock functions use the interface getter rather than directly reading +0x18.

For example, `UnlockAllTools` obtains an `IItemData` object from the enumerator and resolves interface slot 1.

The `IItemData` declaration tells us:

Code:
Slot 0 = get_ID
Slot 1 = get_Item

Relevant interface dispatch:

Code:
0x710568DFB4    LDR   X1, [X25,...]       // IItemData TypeInfo
...
0x710568DFE8    MOV   X0, X22             // current IItemData*
0x710568DFEC    MOV   W2, #1              // interface slot 1
0x710568DFF0    BL    interface_resolver
...
0x710568E010    LDP   X8, X1, [X0]
0x710568E014    MOV   X0, X22
0x710568E018    BLR   X8
0x710568E01C    MOV   W22, W0

The return value is then used as the tool Item:

Code:
0x710568DEB0    MOV   W0, W22             // toolItem
0x710568DEB4    MOV   X1, X21             // player
0x710568DEB8    MOV   X2, X20             // world
0x710568DEBC    MOV   X3, X19             // context
0x710568DEC4    BL    Meta.DebugTestMission$$UnlockTool

The game is effectively doing:

Code:
Item toolItem = currentItemData.Item;
UnlockTool(toolItem, player, world, context);

`DebugAddItem.ApplyThis` does the same thing.

After calling the `IItemData.Item` interface getter:

Code:
0x7104CAE89C    LDP   X8, X1, [X0]
0x7104CAE8A0    MOV   X0, X26             // current IItemData*
0x7104CAE8A4    BLR   X8                   // get_Item()

it passes the returned W0 as the Item argument:

Code:
0x7104CAE8B0    MOV   W1, W0              // item
0x7104CAE8BC    MOV   X0, X27             // Profile
0x7104CAE8C0    MOV   W2, #1              // amount
...
0x7104CAE8D0    BL    Meta.Profile$$AddItem

This confirms the complete relationship:

Code:
IItemData*
-> IItemData.get_Item()
-> Item in W0
-> Item argument for AddItem

The custom routine simply replaces the interface call with the verified direct field load:

Code:
LDR W1, [X0,#0x18]

The routine needs two game objects:

  • The active Meta.Online.Client
  • The ItemDatabase singleton

The Client is obtained through:

Code:
Mdl.Missions.MissionManager$$get_MetaClient
RVA:     0x35CC3B0
Address: 0x71035CC3B0

The result is returned in X0:

Code:
BL  0x71035CC3B0
MOV X19, X0

X19 is used because it is callee-saved and must survive the later calls.

The ItemDatabase singleton is obtained with:

Code:
Definitions.Items.ItemDatabase$$get_Instance
RVA:     0x4A8A200
Address: 0x7104A8A200

The call returns the ItemDatabase pointer in X0:

Code:
BL 0x7104A8A200

GetAllByType is then called with:

Code:
MOV W1, #5
MOV X2, XZR
BL  0x7104A85F80

Arguments:

Code:
X0 = ItemDatabase*
W1 = ItemType.Clothing
X2 = null MethodInfo*

Return value:

Code:
X0 = IItemData[] array object

The trigger function is:

Code:
Mdl.Ui.WardrobeMenu$$OnFocusIn

The Wardrobe was selected because this first code was specifically made for clothing.

It also provides a simple trigger that can be tested repeatedly without reloading the entire game.

The function was confirmed dynamically by placing a breakpoint and opening the Wardrobe.

The relevant original block is:

Code:
0x7107B15AD8    MOV X0, X19
0x7107B15ADC    MOV W1, WZR
0x7107B15AE0    BL  Mdl.Ui.WardrobeMenu$$RefreshContent

The hook replaces:

Code:
MOV X0, X19

with:

Code:
BL 0x7108CB4118

This position is suitable because:

  • The base Menu.OnFocusIn call has already completed.
  • It belongs to the Wardrobe initialization path.
  • It runs immediately before RefreshContent.
  • X19 still contains the WardrobeMenu pointer.
  • The overwritten instruction has no memory side effects.
  • The original MOV can be recreated before returning.

The code cave was found at the end of the executable `.text` section.

The final existing function ends at:

Code:
0x7108CB4114

Unused space begins at:

Code:
0x7108CB4118

The next section begins at:

Code:
0x7108CB5000    // .rodata

Available space:

Code:
0x7108CB5000 - 0x7108CB4118 = 0xEE8 bytes

The Get All Clothing routine occupies only:

Code:
0x7108CB4118 - 0x7108CB417B

The code cave must be found and checked again after every update.

The custom routine uses:

Code:
X19 = Client*
X20 = address of the first array element
W21 = array length
W22 = current array index

Temporary arguments and return values use:

Code:
X0 / W0
X1 / W1
X2 / W2
X3

X30 must also be saved because every BL instruction overwrites it.

The prologue is:

Code:
STP X19, X30, [SP,#-0x10]!
STP X19, X20, [SP,#-0x10]!
STP X21, X22, [SP,#-0x10]!

This reserves 48 bytes.

Since 48 is divisible by 16, the stack remains correctly aligned for function calls.

X19 is saved twice intentionally.

One copy restores the original X19 register.

The other is loaded into X0 at the end to recreate the overwritten:

Code:
MOV X0, X19

1. Install the hook

Code:
0x7107B15AD8    BL 0x7108CB4118

2. Disable the NotDeveloper branch

Code:
0x7104CAE434    NOP

3. Preserve the original state

Code:
STP X19, X30, [SP,#-0x10]!
STP X19, X20, [SP,#-0x10]!
STP X21, X22, [SP,#-0x10]!

4. Get the active Client

Code:
BL  0x71035CC3B0
MOV X19, X0

5. Get ItemDatabase.Instance

Code:
BL 0x7104A8A200

6. Get all Clothing item-data objects

Code:
MOV W1, #5
MOV X2, XZR
BL  0x7104A85F80

7. Read the array header

Code:
ADD X20, X0, #0x20
LDR W21, [X0,#0x18]
MOV W22, #0

State after preparation:

Code:
X20 = &items[0]
W21 = items.Length
W22 = 0

8. Load the current item-data pointer

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

Equivalent operation:

Code:
X0 = items[W22]

9. Read Item from +0x18

Code:
LDR W1, [X0,#0x18]

Equivalent operation:

Code:
W1 = items[W22].Item

10. Submit DebugAddItem

Code:
MOV X0, X19
MOV W2, #1
MOV X3, XZR
BL  0x7105B5DD30

Arguments:

Code:
X0 = Client*
W1 = Item
W2 = 1
X3 = default CancellationToken

11. Advance the loop

Code:
ADD W22, W22, #1
CMP W22, W21
B.LT 0x7108CB4148

The loop continues while:

Code:
index < array length

12. Restore the original state

Code:
LDP X21, X22, [SP],#0x10
LDP X19, X20, [SP],#0x10
LDP X0,  X30, [SP],#0x10
RET

The final LDP restores:

Code:
X0  = original X19
X30 = return address

This recreates the overwritten:

Code:
MOV X0, X19

The original Wardrobe function then continues at:

Code:
0x7107B15ADC

Code:
// ============================================================================
// Get All Items by Type (Clothing)
// Target: v1.23.0 [0100D39012C1A800][v3801088][UPD]
// Code Cave Address: 0x7108CB4118
// ============================================================================

// --- [Block A] Hook (Mdl.Ui.WardrobeMenu$$OnFocusIn) ------------------------
0x7107B15AD8    BL    0x7108CB4118                  // Jump to Code Cave

// --- [Block B] Dev-flag check bypass ----------------------------------------
// Address: 0x7104CAE434 (Meta.DebugAddItem.Types.Response$$ApplyThis)
// Original: CBZ W8, loc_7104CAE46C
0x7104CAE434    NOP                                 // Bypass NotDeveloper branch

// --- [Block C] Code Cave (Start: 0x7108CB4118) ------------------------------
0x7108CB4118    STP   X19, X30, [SP, #-0x10]!
0x7108CB411C    STP   X19, X20, [SP, #-0x10]!
0x7108CB4120    STP   X21, X22, [SP, #-0x10]!

// MissionManager.get_MetaClient
0x7108CB4124    BL    0x71035CC3B0
0x7108CB4128    MOV   X19, X0

// ItemDatabase.get_Instance
0x7108CB412C    BL    0x7104A8A200

// ItemDatabase.GetAllByType(Clothing = 5)
0x7108CB4130    MOV   W1,  #5
0x7108CB4134    MOV   X2,  XZR
0x7108CB4138    BL    0x7104A85F80

// Prepare direct array traversal
0x7108CB413C    ADD   X20, X0, #0x20
0x7108CB4140    LDR   W21, [X0, #0x18]
0x7108CB4144    MOV   W22, #0

// Load current IItemData* and read Item
0x7108CB4148    LDR   X0,  [X20, X22, LSL #3]
0x7108CB414C    LDR   W1,  [X0, #0x18]

// Client.DebugAddItem(item, 1, default)
0x7108CB4150    MOV   X0,  X19
0x7108CB4154    MOV   W2,  #1
0x7108CB4158    MOV   X3,  XZR
0x7108CB415C    BL    0x7105B5DD30

// Loop control
0x7108CB4160    ADD   W22, W22, #1
0x7108CB4164    CMP   W22, W21
0x7108CB4168    B.LT  0x7108CB4148

// Restore original state
0x7108CB416C    LDP   X21, X22, [SP], #0x10
0x7108CB4170    LDP   X19, X20, [SP], #0x10
0x7108CB4174    LDP   X0,  X30, [SP], #0x10
0x7108CB4178    RET

Assume GetAllByType returns three item-data references.

Array memory:

Code:
array + 0x18 = 3

array + 0x20 -> IItemData* A
array + 0x28 -> IItemData* B
array + 0x30 -> IItemData* C

Initial loop state:

Code:
W21 = 3
W22 = 0

First iteration:

Code:
LDR X0, [X20, 0 * 8] -> IItemData* A
LDR W1, [X0,#0x18]   -> Item A
DebugAddItem(Item A, 1)

Second iteration:

Code:
LDR X0, [X20, 1 * 8] -> IItemData* B
LDR W1, [X0,#0x18]   -> Item B
DebugAddItem(Item B, 1)

Third iteration:

Code:
LDR X0, [X20, 2 * 8] -> IItemData* C
LDR W1, [X0,#0x18]   -> Item C
DebugAddItem(Item C, 1)

After the third iteration:

Code:
W22 = 3
W21 = 3

The condition:

Code:
3 < 3

is false, so the loop ends.

DebugAddItem returns:

Code:
Task<DebugAddItem.Types.Response>

The routine does not await the returned Tasks.

It submits the requests quickly, while the game continues processing them afterward.

Large categories may continue showing loading activity for several minutes.

The routine also does not perform its own ownership check. Every item returned by GetAllByType is submitted to DebugAddItem.

The following must be checked after a game update:

  • WardrobeMenu.OnFocusIn
  • The exact hook instruction
  • The NotDeveloper branch
  • MissionManager.get_MetaClient
  • ItemDatabase.get_Instance
  • ItemDatabase.GetAllByType
  • Client.DebugAddItem
  • The array layout
  • The item-data +0x18 field
  • The available code-cave range

I confirmed `iD_` at +0x18 in every item-data category used by this pattern, and the direct load was tested with all item categories in this version.

That does not guarantee that the same offset will remain valid after an update.

Do not update the code by applying one global address difference. Locate and verify each function and field again.

This explains how the original Get All Clothing code was extended so that every furniture item with an inventory amount below 999 is raised to 999.

The addresses below are for:

Code:
Disney Dreamlight Valley v1.23.0
Title ID: 0100D39012C1A800
Build: v3801088

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 code-cave selection
  • The DebugAddItem developer-check bypass
  • MissionManager.get_MetaClient
  • ItemDatabase.get_Instance
  • How GetAllByType builds an IItemData array
  • The IL2CPP array layout
  • Reading Item from item-data object +0x18
  • The asynchronous behavior of DebugAddItem

This post covers only the furniture-specific additions.

The Clothing code submits every Item with an amount of one:

Code:
client.DebugAddItem(item, 1, default);

That is sufficient for clothing because clothing is mainly handled as an unlocked list entry.

Furniture is also stored in a ListInventory, but each furniture Item has an actual quantity.

The first furniture version simply added one copy of every furniture item. That was not very useful for decorating, since the same furniture item may be placed many times.

The code was therefore changed to:

Code:
currentAmount = player.GetItemAmount(item, null)
amountToAdd   = 999 - currentAmount

if amountToAdd > 0:
client.DebugAddItem(item, amountToAdd, default)

This does not directly overwrite the stored amount.

It asks the game for the current inventory amount and submits only the missing difference through DebugAddItem.

The target value of 999 was chosen because it is large enough for practical decoration use and remains easy to read in the user interface.

It should not be interpreted as a confirmed internal maximum.

The complete high-level logic is:

Code:
client = MissionManager.MetaClient
database = ItemDatabase.Instance
items = database.GetAllByType(ItemType.Furniture)

for each itemData in items:
item = itemData.Item

```
player = client.profile.player
currentAmount = player.GetItemAmount(item, null)

amountToAdd = 999 - currentAmount

if amountToAdd > 0:
    client.DebugAddItem(item, amountToAdd, default)
```

The differences from the Clothing routine are:

  • ItemType changes from Clothing = 5 to Furniture = 4.
  • The current item-data pointer is stored in X23.
  • ProfilePlayer is obtained from Client.
  • GetItemAmount is called for every furniture Item.
  • W2 is calculated as 999 minus the current amount.
  • Items already at or above 999 are skipped.

The ItemType value for furniture is:

Code:
public const ItemType Furniture = 4;

The GetAllByType argument therefore changes from:

Code:
MOV W1, #5    // Clothing

to:

Code:
MOV W1, #4    // Furniture

The actual call is:

Code:
0x7108CB412C    BL    0x7104A8A200

0x7108CB4130    MOV   W1, #4
0x7108CB4134    MOV   X2, XZR
0x7108CB4138    BL    0x7104A85F80

As explained in the Clothing post, the returned object is an array of IItemData references.

The array setup is unchanged:

Code:
0x7108CB413C    ADD   X20, X0, #0x20
0x7108CB4140    LDR   W21, [X0,#0x18]
0x7108CB4144    MOV   W22, #0

After this:

Code:
X20 = address of the first item-data reference
W21 = number of furniture entries
W22 = current index

The Clothing routine loaded the current item-data pointer into X0:

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

It immediately read the Item and called DebugAddItem.

The furniture routine must use the same Item both before and after calling GetItemAmount.

The current item-data pointer is therefore stored in X23:

Code:
0x7108CB4148    LDR X23, [X20, X22, LSL #3]

X0 through X18 are volatile registers. A called function may overwrite them.

X23 is callee-saved, so GetItemAmount must preserve it before returning.

The furniture routine can therefore use the same item-data object twice:

Code:
LDR X23, [X20, X22, LSL #3]

LDR W1, [X23,#0x18]
BL  ProfilePlayer.GetItemAmount

...

LDR W1, [X23,#0x18]
BL  Client.DebugAddItem

The Clothing code only needed the Client pointer.

The furniture code also needs ProfilePlayer because GetItemAmount is a ProfilePlayer method.

The Client class contains:

Code:
private string localUserId; // 0xB0
private Profile profile;    // 0xB8

The Profile class contains:

Code:
private ProfileGameInfo gameInfo_; // 0x18
private ProfileSettings settings_; // 0x20
private ProfilePlayer player_;     // 0x28
private ProfileWorld world_;       // 0x30

X19 contains the active Client pointer.

The following two loads obtain ProfilePlayer:

Code:
0x7108CB414C    LDR X0, [X19,#0xB8]
0x7108CB4150    LDR X0, [X0,#0x28]

The pointer chain is:

Code:
Client*
+0xB8
-> Profile*
+0x28
-> ProfilePlayer*

The Item is then read from the current item-data object:

Code:
0x7108CB4154    LDR W1, [X23,#0x18]

The ItemState argument is set to null:

Code:
0x7108CB4158    MOV X2, XZR

The final call is:

Code:
0x7108CB415C    BL 0x710549E740

The arguments are:

Code:
X0 = ProfilePlayer*
W1 = Furniture Item
X2 = null ItemState

The called method is:

Code:
public int GetItemAmount(
Item item,
ItemState state
);

Native address:

Code:
Meta.ProfilePlayer$$GetItemAmount
RVA:     0x549E740
Address: 0x710549E740

This overload is a short wrapper:

Code:
0x710549E740    AND X1, X1, #0xFFFFFFFF
0x710549E744    MOV W3, #1
0x710549E748    MOV W4, WZR
0x710549E74C    B   Meta.ProfilePlayer$$GetItemAmount_485420046928

Equivalent call:

Code:
return GetItemAmount(
item,
state,
includePantry: true,
includeBackpackOverflow: false
);

After the function returns:

Code:
W0 = current furniture inventory amount

For furniture, GetItemAmount obtains the compatible ListInventory:

Code:
0x71054A1E20    LDR   W1, [X20]      // item
0x71054A1E24    ADD   X2, SP, ...    // out ListInventory
0x71054A1E28    MOV   X0, X19        // ProfilePlayer*
0x71054A1E2C    BL    Meta.ProfilePlayer$$TryGetListInventoryFor
0x71054A1E30    TBZ   W0, #0, return_zero

It then retrieves the inventory entry for that Item:

Code:
0x71054A1E34    LDR   X0, [SP,...]   // ListInventory*
0x71054A1E3C    LDR   W1, [X20]      // item
0x71054A1E40    ADD   X2, X29, ...   // out Data
0x71054A1E48    BL    Meta.ListInventory$$TryGetInventoryData
0x71054A1E4C    TBZ   W0, #0, return_zero

If the entry exists, it reads:

Code:
0x71054A1E50    LDR X8, [X29,...]    // ListInventory.Types.Data*
0x71054A1E58    LDR W22, [X8,#0x18]

The corresponding field is:

Code:
public sealed class ListInventory.Types.Data
{
public const int AmountFieldNumber = 1;
private int amount_; // 0x18

```
public int Amount { get; set; }
```

}

Therefore:

Code:
LDR W22, [X8,#0x18]

reads:

Code:
data.Amount

The relevant behavior is:

Code:
if (!TryGetListInventoryFor(item, out inventory))
return 0;

if (!inventory.TryGetInventoryData(item, out data))
return 0;

return data.Amount;

This value is the number of copies currently stored in the furniture ListInventory.

Furniture already placed in the world is not included.

The code therefore raises the number of available, unplaced copies to 999 rather than setting the combined inventory and placed total to 999.

GetItemAmount returns the current inventory amount in W0.

The custom code calculates the difference:

Code:
0x7108CB4160    MOV  W2, #999
0x7108CB4164    SUBS W2, W2, W0

This is:

Code:
W2 = 999 - currentAmount

W2 is used because it is also the amount argument for DebugAddItem.

`SUBS` stores the result and updates the condition flags.

The next instruction is:

Code:
0x7108CB4168    B.LE 0x7108CB417C

This skips DebugAddItem when the result is zero or negative.

Examples:

Code:
currentAmount = 0
999 - 0 = 999
Add 999

currentAmount = 400
999 - 400 = 599
Add 599

currentAmount = 998
999 - 998 = 1
Add 1

currentAmount = 999
999 - 999 = 0
Skip

currentAmount = 1000
999 - 1000 = -1
Skip

The code does not reduce an amount above 999.

It only increases amounts below 999.

If the difference is positive, the code prepares DebugAddItem:

Code:
0x7108CB416C    MOV X0, X19
0x7108CB4170    LDR W1, [X23,#0x18]
0x7108CB4174    MOV X3, XZR
0x7108CB4178    BL  0x7105B5DD30

At this point:

Code:
X0 = Client*
W1 = current Furniture Item
W2 = 999 - currentAmount
X3 = default CancellationToken

Equivalent call:

Code:
client.DebugAddItem(
item,
999 - currentAmount,
default
);

W2 is not set again before the call because it already contains the calculated difference.

The Clothing routine used:

Code:
X19 = Client*
X20 = array data
W21 = array length
W22 = index

The furniture routine adds:

Code:
X23 = current furniture item-data pointer

The prologue is:

Code:
STP X19, X30, [SP,#-0x10]!
STP X20, X21, [SP,#-0x10]!
STP X22, X23, [SP,#-0x10]!

The routine reserves 48 bytes, so the stack remains 16-byte aligned.

The epilogue is:

Code:
LDP X22, X23, [SP],#0x10
LDP X20, X21, [SP],#0x10
LDP X19, X30, [SP],#0x10
MOV X0, X19
RET

The original X19 and X30 are restored normally.

The explicit:

Code:
MOV X0, X19

recreates the instruction overwritten at the hook address.

Code:
// ============================================================================
// Get All Furniture (up to 999)
// Target: v1.23.0 [0100D39012C1A800][v3801088][UPD]
// Code Cave Address: 0x7108CB4118
// ============================================================================

// --- [Block A] Hook (Mdl.Ui.WardrobeMenu$$OnFocusIn) ------------------------
0x7107B15AD8    BL    0x7108CB4118

// --- [Block B] Dev-flag check bypass ----------------------------------------
0x7104CAE434    NOP                                 // Bypass dev check

// --- [Block C] Code Cave (Start: 0x7108CB4118) ------------------------------
0x7108CB4118    STP   X19, X30, [SP, #-0x10]!
0x7108CB411C    STP   X20, X21, [SP, #-0x10]!
0x7108CB4120    STP   X22, X23, [SP, #-0x10]!

// MissionManager.get_MetaClient
0x7108CB4124    BL    0x71035CC3B0
0x7108CB4128    MOV   X19, X0

// ItemDatabase.get_Instance
0x7108CB412C    BL    0x7104A8A200

// ItemDatabase.GetAllByType(Furniture = 4)
0x7108CB4130    MOV   W1,  #4
0x7108CB4134    MOV   X2,  XZR
0x7108CB4138    BL    0x7104A85F80

// Prepare loop
0x7108CB413C    ADD   X20, X0, #0x20
0x7108CB4140    LDR   W21, [X0, #0x18]
0x7108CB4144    MOV   W22, #0

// Load current furniture item-data pointer
0x7108CB4148    LDR   X23, [X20, X22, LSL #3]

// Get ProfilePlayer
0x7108CB414C    LDR   X0,  [X19, #0xB8]
0x7108CB4150    LDR   X0,  [X0,  #0x28]

// Get current inventory amount
0x7108CB4154    LDR   W1,  [X23, #0x18]
0x7108CB4158    MOV   X2,  XZR
0x7108CB415C    BL    0x710549E740

// Calculate amountToAdd = 999 - currentAmount
0x7108CB4160    MOV   W2,  #999
0x7108CB4164    SUBS  W2,  W2, W0
0x7108CB4168    B.LE  0x7108CB417C

// Client.DebugAddItem(item, amountToAdd, default)
0x7108CB416C    MOV   X0,  X19
0x7108CB4170    LDR   W1,  [X23, #0x18]
0x7108CB4174    MOV   X3,  XZR
0x7108CB4178    BL    0x7105B5DD30

// Loop control
0x7108CB417C    ADD   W22, W22, #1
0x7108CB4180    CMP   W22, W21
0x7108CB4184    B.LT  0x7108CB4148

// Restore original state
0x7108CB4188    LDP   X22, X23, [SP], #0x10
0x7108CB418C    LDP   X20, X21, [SP], #0x10
0x7108CB4190    LDP   X19, X30, [SP], #0x10
0x7108CB4194    MOV   X0,  X19
0x7108CB4198    RET

The code raises each furniture Item’s current ListInventory amount to 999.

It does not:

  • Count furniture already placed in the world
  • Reduce amounts above 999
  • Directly overwrite ListInventory.Types.Data.Amount
  • Wait for every DebugAddItem Task to complete

Because DebugAddItem is asynchronous, the game may continue processing additions after the code-cave loop has finished.

Do not trigger the routine again while the previous requests are still being processed.

If it is triggered again too early, GetItemAmount may still return an older value and another difference may be submitted, allowing some amounts to exceed 999.

After processing is complete, running the routine again normally skips items already at or above 999.

The furniture-specific values that must be verified after an update are:

Code:
Client.profile                    +0xB8
Profile.player_                   +0x28
ListInventory.Types.Data.amount_  +0x18

ProfilePlayer.GetItemAmount       0x710549E740

The common hook, ItemDatabase, DebugAddItem and code-cave checks are the same as those described in the Clothing post.

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

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.

The original Clothing code uses:

Code:
ItemDatabase.GetAllByType(ItemType.Clothing)

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

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
}

The Companion ItemType also contains several different groups:

Code:
public enum CompanionItemType
{
    Pet     = 0,
    Critter = 1,
    Snippet = 2,
    Mount   = 3
}

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)

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

The original Clothing code uses:

Code:
public IEnumerable<IItemData>
    GetAllByType(ItemType itemType);

ItemDatabase also contains the following generic overload:

Code:
public IEnumerable<ItemDataType>
    GetAllByType<ItemDataType, SubItemEnumType>(
        ItemType itemType,
        SubItemEnumType subItemEnumType
    );

Il2CppDumper identifies its shared native implementation as:

Code:
RVA:     0x3677620
Address: 0x7103677620

ItemDatabase.GetAllByType<
    __Il2CppFullySharedGenericType,
    __Il2CppFullySharedGenericStructType
>

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

Examples:

Code:
BuildingItemData
PetItemData
MountItemData

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

Examples:

Code:
BuildingItemType
CompanionItemType

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

Code:
database.GetAllByType<
    BuildingItemData,
    BuildingItemType
>(
    ItemType.Building,
    BuildingItemType.PlayerHouse
);

Code:
database.GetAllByType<
    PetItemData,
    CompanionItemType
>(
    ItemType.Companion,
    CompanionItemType.Pet
);

Code:
database.GetAllByType<
    MountItemData,
    CompanionItemType
>(
    ItemType.Companion,
    CompanionItemType.Mount
);

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.

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
);

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>

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>

These calls establish the native argument layout:

Code:
X0 = ItemDatabase*
W1 = ItemType
X2 = pointer to the SubType value
X3 = concrete generic MethodInfo*

The custom code reproduces this same call pattern.

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:
0x710ABE7A40
Method$Definitions.Items.ItemDatabase.GetAllByType<
    PetItemData,
    CompanionItemType
>

Code:
0x710ABE7A28
Method$Definitions.Items.ItemDatabase.GetAllByType<
    MountItemData,
    CompanionItemType
>

All three entries are on the same page:

Code:
0x710ABE7000

Their page offsets are:

Code:
PlayerHouse: 0x990
Pet:         0xA40
Mount:       0xA28

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

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

Code:
ADRP X3, 0x710ABE7000
LDR  X3, [X3,#MethodSlotOffset]

These operations are different.

Code:
ADRP + ADD
    -> address of the Method$ slot

ADRP + LDR
    -> MethodInfo pointer stored in the slot

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.

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

The helper at:

Code:
0x7100B4C1B0

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

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

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

After the ADD:

Code:
X8 = 0x7100B4C1B0

`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.

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

The existing game code uses the same pattern:

Code:
MOV W8, #1
STR W8, [SP,#subTypeStorage]
ADD X2, SP,#subTypeStorage

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

This preserves:

Code:
X19 = MethodInfo*
X26 = pointer to SubType data
W20 = ItemType
X22 = ItemDatabase*

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

Conceptually:

Code:
subTypeSize = genericMetadata.SubTypeSize;
copy(localSubType, X2, subTypeSize);

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.

The original Clothing routine saved X21 and X22 with:

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

The SubType version changes this to:

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

This decreases SP by 32 bytes.

The first 16 bytes store X21 and X22:

Code:
SP + 0x00 = saved X21
SP + 0x08 = saved X22

The remaining 16 bytes are available as temporary storage:

Code:
SP + 0x10 = SubType value
SP + 0x14
SP + 0x18
SP + 0x1C

The code stores the enum at:

Code:
STR W8, [SP,#0x10]

and passes its address with:

Code:
ADD X2, SP,#0x10

The stack remains 16-byte aligned.

At the end of the routine:

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

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

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

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

The ItemDatabase cache uses the following key type:

Code:
ValueTuple<ItemType, Enum, Type>

and stores the result as:

Code:
Array

This allows different combinations such as:

Code:
Building + PlayerHouse + BuildingItemData
Companion + Pet + PetItemData
Companion + Mount + MountItemData

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

Conceptually:

Code:
baseItems = GetAllByType(itemType);

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>

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

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()

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.

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; }
}

PetItemData:

Code:
public sealed class PetItemData : ..., IItemData, ...
{
    private UnknownFieldSet _unknownFields; // 0x10

    public const int IDFieldNumber = 1;
    private int iD_;                        // 0x18

    public Item Item { get; }
}

MountItemData:

Code:
public sealed class MountItemData : ..., IItemData, ...
{
    private UnknownFieldSet _unknownFields; // 0x10

    public const int IDFieldNumber = 1;
    private int iD_;                        // 0x18

    public Item Item { get; }
}

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]

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

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

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

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
---------------------------------------------------------------

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

Code:
PlayerHouse:
GetAllByType<BuildingItemData, BuildingItemType>

Pet:
GetAllByType<PetItemData, CompanionItemType>

Mount:
GetAllByType<MountItemData, CompanionItemType>

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

This would not be a valid combination:

Code:
Method$:
    GetAllByType<BuildingItemData, BuildingItemType>

ItemType:
    Companion

SubType:
    CompanionItemType.Mount

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

This gives:

Code:
X0 = 0x710ABE7990

Method$ItemDatabase.GetAllByType<
    BuildingItemData,
    BuildingItemType
>

The metadata helper is called through X8:

Code:
0x7108CB4138    ADRP X8, 0x7100B4C000
0x7108CB413C    ADD  X8, X8, #0x1B0
0x7108CB4140    BLR  X8

ItemDatabase.Instance is then obtained:

Code:
0x7108CB4144    BL 0x7104A8A200

The broad ItemType is Building:

Code:
0x7108CB4148    MOV W1,#2

The SubType is PlayerHouse:

Code:
0x7108CB414C    MOV W8,#5
0x7108CB4150    STR W8,[SP,#0x10]
0x7108CB4154    ADD X2,SP,#0x10

The resolved concrete MethodInfo is loaded into X3:

Code:
0x7108CB4158    ADRP X3,0x710ABE7000
0x7108CB415C    LDR  X3,[X3,#0x990]

Immediately before the generic call, the register state is:

Code:
X0 = ItemDatabase*
W1 = ItemType.Building
X2 = &BuildingItemType.PlayerHouse
X3 = MethodInfo for
     GetAllByType<
         BuildingItemData,
         BuildingItemType
     >

The shared implementation is then called:

Code:
0x7108CB4160    BL 0x7103677620

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

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

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

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]

This represents:

Code:
GetAllByType<
    PetItemData,
    CompanionItemType
>(
    ItemType.Companion,
    CompanionItemType.Pet
)

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]

This represents:

Code:
GetAllByType<
    MountItemData,
    CompanionItemType
>(
    ItemType.Companion,
    CompanionItemType.Mount
)

No other part of the routine changes.

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

The current warm-up helper is:

Code:
0x7100B4C1B0

The current Method$ entries are:

Code:
BuildingItemData, BuildingItemType
    0x710ABE7990

PetItemData, CompanionItemType
    0x710ABE7A40

MountItemData, CompanionItemType
    0x710ABE7A28

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

To create another SubType configuration, identify:

  1. The broad ItemType.
  2. The required SubType enum and numeric value.
  3. The concrete ItemDataType.
  4. The Method$ entry for GetAllByType<ItemDataType, SubTypeEnum>.
  5. 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.

This explains how the original Get All code was extended to complete every MemoryShard entry in the game.

The addresses below are for:

Code:
Disney Dreamlight Valley v1.23.0
Title ID: 0100D39012C1A800
Build: v3801088

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 code-cave selection
  • The DebugAddItem developer-check bypass
  • MissionManager.get_MetaClient
  • ItemDatabase.get_Instance
  • How GetAllByType creates an IItemData array
  • The IL2CPP array layout and loop
  • Reading Item from item-data object +0x18
  • The asynchronous behavior of DebugAddItem
  • Restoring the overwritten Wardrobe instruction

This post covers the additional processing required specifically for memories.

The basic Get All routine can retrieve every MemoryShard item by changing the ItemType to:

Code:
ItemType.MemoryShard = 13

A simple implementation would therefore appear to be:

Code:
items = database.GetAllByType(ItemType.MemoryShard)

for each itemData in items:
client.DebugAddItem(itemData.Item, 1, default)

However, MemoryShard items are not ordinary unlockable list entries.

The normal DebugAddItem path does three things that prevent this simple version from completing every memory correctly:

  1. It creates an ItemState containing one randomly selected MemoryShardIndex.
  2. It attempts to wrap the MemoryShard into a consumable item.
  3. AddMemoryShard normally adds only the single selected shard bit and rejects the request if that bit was already collected.

The required solution is therefore:

Code:
Get every MemoryShard item
↓
Keep the generated MemoryShardIndex state
↓
Prevent the MemoryShard from being wrapped as a consumable
↓
Prevent an already-collected random shard from stopping the update
↓
Replace the single-shard mask with the complete memory mask

The final code combines the normal Get All loop with three function patches and an additional FULLMASK_STUB.

The relevant item-data class is:

Code:
public sealed class MemoryShardItemData :
...,
IItemData,
IItemStateProvider,
IItemConsummableOverride,
...
{
private UnknownFieldSet _unknownFields; // 0x10

```
public const int IDFieldNumber = 1;
private int iD_;                        // 0x18

...

public const int NumberOfShardsFieldNumber = 13;
private int numberOfShards_;            // 0x68

...

public int NumberOfShards { get; set; }
public int CompletedShardFlag { get; }
public Item Item { get; }
```

}

The two fields used by the code are:

Code:
MemoryShardItemData + 0x18 = Item
MemoryShardItemData + 0x68 = NumberOfShards

The main Get All loop uses ItemType 13:

Code:
MOV W1, #13
MOV X2, XZR
BL  ItemDatabase.GetAllByType

The returned array is processed exactly as explained in the Clothing post:

Code:
ADD X20, X0, #0x20
LDR W21, [X0,#0x18]
MOV W22, #0

Loop:
LDR X0, [X20,X22,LSL #3]
LDR W1, [X0,#0x18]

The difference is what happens after each Item is submitted to DebugAddItem.

`Meta.DebugAddItem.GetItemState` first derives the ItemType from the Item value.

Relevant excerpt:

Code:
0x7104CA9E84    LDR   W22, [X19]       // Item
...
0x7104CA9E90    LDR   X8, [X0,#0xB8]
0x7104CA9E94    LDR   W8, [X8,#4]
0x7104CA9E98    SDIV  W8, W22, W8
0x7104CA9E9C    CMP   W8, #0xD         // MemoryShard = 13
0x7104CA9EA4    CSET  W22, EQ

After this:

Code:
W22 = 1 if the Item is a MemoryShard
W22 = 0 otherwise

For a MemoryShard, the function retrieves the corresponding `MemoryShardItemData`:

Code:
0x7104CAA3D8    ADRP  X8,
Method$ItemDatabase.GetItemData<MemoryShardItemData>

0x7104CAA3DC    LDR   W1, [X19]        // item
0x7104CAA3E0    LDR   X2, [X8,...]     // MethodInfo
0x7104CAA3E4    BL    ItemDatabase.GetItemData<MemoryShardItemData>

It reads `NumberOfShards` from `+0x68` and passes it to the game’s random-number generator:

Code:
0x7104CAA3F4    MOV   W1, WZR          // minimum = 0
0x7104CAA3F8    LDR   W2, [X0,#0x68]   // maximum = NumberOfShards
0x7104CAA3FC    MOV   X0, X24          // Random*
0x7104CAA400    LDP   X9, X3, [X8,#0x198]
0x7104CAA404    BLR   X9

The result is in W0:

Code:
0 <= W0 < NumberOfShards

That value is stored as the `MemoryShardIndex` of a newly created ItemState:

Code:
0x7104CAA40C    MOV   W1, W0
0x7104CAA410    MOV   X0, X23
0x7104CAA414    MOV   X2, XZR
0x7104CAA418    BL    ItemState.set_MemoryShardIndex

0x7104CAA41C    STR   X23, [X20]

The effective logic is:

Code:
MemoryShardItemData data =
database.GetItemData<MemoryShardItemData>(item);

int randomIndex =
random.Next(0, data.NumberOfShards);

itemState = new ItemState();
itemState.MemoryShardIndex = randomIndex;

One DebugAddItem request therefore represents one randomly selected piece of the memory.

`ItemState` uses a protobuf `oneof` field:

Code:
public sealed class ItemState
{
public const int MealDataFieldNumber = 1;
public const int MemoryShardIndexFieldNumber = 2;
public const int ConsummableDataFieldNumber = 3;

```
...

private object state_;                        // 0x18
private ItemState.StateOneofCase stateCase_; // 0x20

public int MemoryShardIndex { get; set; }
public ItemState.StateOneofCase StateCase { get; }
```

}

The oneof enum is:

Code:
public enum ItemState.StateOneofCase
{
None             = 0,
MealData         = 1,
MemoryShardIndex = 2,
ConsummableData  = 3,
LootPresentData  = 4,
SceneRestriction = 5,
RewardCondition  = 6
}

Therefore:

Code:
ItemState + 0x18 = oneof payload
ItemState + 0x20 = active oneof case

For a memory shard:

Code:
stateCase_ = MemoryShardIndex = 2
state_     = boxed integer containing the shard index

`AddMemoryShard` later checks this exact case:

Code:
0x71054ABD60    LDR W8, [X22,#0x20]
0x71054ABD64    CMP W8, #2
0x71054ABD68    B.NE fallback_path

It then reads the integer payload:

Code:
0x71054ABD6C    LDR X0, [X22,#0x18]
...
0x71054ABD90    LDR W8, [X0,#0x10]

This is the randomly generated `MemoryShardIndex`.

After creating the MemoryShard ItemState, `GetItemState` reaches:

Code:
0x7104CAA488    ORR W8, W22, W21
0x7104CAA48C    TBZ W8, #0, 0x7104CAA560

The relevant values are:

Code:
W22 = isMemoryShard
W21 = tryConsummable

Conceptually:

Code:
if (!isMemoryShard && !tryConsummable)
return;

For a MemoryShard:

Code:
W22 = 1

so the function continues into the wrapping path even when:

Code:
tryConsummable = false

The wrapping call is:

Code:
0x7104CAA4B4    MOV W3, #0x1E0A6E0    // defaultConsummable
0x7104CAA4BC    MOV X0, X22            // itemToWrap
0x7104CAA4C0    MOV W1, #1             // amountToWrap
0x7104CAA4C4    MOV X2, X21            // stateToWrap
0x7104CAA4C8    MOV X4, XZR
0x7104CAA4CC    BL  ConsummableItemData.WrapIntoConsummableItem

If wrapping succeeds, the original Item and ItemState outputs are replaced with the wrapped values:

Code:
0x7104CAA4D4    LDR X8, [X0,#0x20]
0x7104CAA4D8    MOV X21, X0
0x7104CAA4DC    STR X8, [X20]
...
0x7104CAA548    LDR W20, [X21,#0x18]
0x7104CAA55C    STR W20, [X19]

This is why simply passing every MemoryShard to DebugAddItem can result in a consumable or activity item being added instead of updating memory progression.

The original instruction is:

Code:
0x7104CAA488    ORR W8, W22, W21

It is replaced with:

Code:
0x7104CAA488    MOV W8, WZR

The following instruction remains unchanged:

Code:
0x7104CAA48C    TBZ W8, #0, 0x7104CAA560

Because W8 is now always zero, bit zero is always clear and the branch always goes to:

Code:
0x7104CAA560

That location is the function epilogue:

Code:
0x7104CAA560    LDP X20, X19, [SP,...]
0x7104CAA564    LDP X22, X21, [SP,...]
...
0x7104CAA578    ADD SP, SP, #0xB0
0x7104CAA57C    RET

The patch therefore keeps:

  • The original MemoryShard Item
  • The generated ItemState
  • The randomly selected MemoryShardIndex

but skips the later consumable wrapping stage.

This patch does not stop the ItemState from being created. It only prevents the Item and state from being replaced by a wrapped consumable.

This is a global patch to GetItemState while enabled.

It disables this wrapping path for other calls to the same function as well, so the code should only be enabled for the memory-unlock operation.

After `GetItemState` returns, the generated state is passed through the normal item-addition process.

`Profile.<AddItem>g__AddItem|371_0` calculates the ItemType and uses a switch.

The MemoryShard case is case 13:

Code:
0x710555BD14    LDR X0, [X20,#0x28]   // ProfilePlayer*
0x710555BD18    CBZ X0, failure

0x710555BD1C    MOV X1, X25           // item
0x710555BD20    MOV X2, X19           // dispatcher
0x710555BD24    MOV X3, X24           // itemState
0x710555BD28    MOV X4, X21           // detail
0x710555BD2C    MOV X5, XZR
0x710555BD30    BL  Meta.ProfilePlayer.AddMemoryShard

The generated ItemState is passed unchanged in X3.

The relevant data flow is:

Code:
Client.DebugAddItem
↓
DebugAddItem.GetItemState
↓
ItemState.MemoryShardIndex
↓
Profile.AddItem
↓
ItemType.MemoryShard case
↓
ProfilePlayer.AddMemoryShard(
item,
dispatcher,
itemState,
detail
)

`AddMemoryShard` also validates the ItemType and state case:

Code:
0x71054ABCF4    LDR  X8, [X8,#0xB8]
0x71054ABCF8    LDR  W8, [X8,#4]
0x71054ABCFC    SDIV W8, W21, W8
0x71054ABD00    CMP  W8, #0xD
0x71054ABD04    B.NE return

0x71054ABD08    LDR  W8, [X22,#0x20]
0x71054ABD0C    CMP  W8, #2
0x71054ABD10    B.NE return

This confirms that the function expects:

Code:
ItemType.MemoryShard
ItemState.StateOneofCase.MemoryShardIndex

`ProfilePlayer` contains:

Code:
public const int MemoryShardsFieldNumber = 39;

private readonly MapField<int, int>
memoryShards_; // 0x108

The map can be represented as:

Code:
MemoryShard Item -> collected-shard bitmask

`AddMemoryShard` reads the current mask with:

Code:
0x71054ABD14    LDR X0, [X23,#0x108]
...
0x71054ABD24    STUR W21, [X29,...]    // key = Item
...
0x71054ABD30    BL   MapField<int,int>.TryGetValue

If the Item is not yet present, the function adds it with an initial value of zero:

Code:
0x71054ABD38    LDR X0, [X23,#0x108]
0x71054ABD3C    STR WZR, [SP,...]

...

0x71054ABD4C    STUR W21, [X29,...]    // key
...
0x71054ABD58    STR WZR, [SP,...]      // value = 0
0x71054ABD5C    BL  MapField<int,int>.Add

Each bit represents one memory piece.

For example:

Code:
00000001 = piece 0 collected
00000010 = piece 1 collected
00000100 = piece 2 collected
00001000 = piece 3 collected

A partially completed four-piece memory might contain:

Code:
00000101

which means:

Code:
piece 0 = collected
piece 1 = missing
piece 2 = collected
piece 3 = missing

When the ItemState contains `MemoryShardIndex`, `AddMemoryShard` reads the selected index and creates a single-bit mask:

Code:
0x71054ABD90    LDR W8, [X0,#0x10]
0x71054ABD94    AND W8, W8, #0x1F
0x71054ABD98    MOV W9, #1
0x71054ABD9C    LSL W24, W9, W8

Equivalent logic:

Code:
int index = itemState.MemoryShardIndex;

uint singleShardBit =
1u << (index & 31);

Examples:

Code:
index = 0 -> W24 = 00000001
index = 1 -> W24 = 00000010
index = 2 -> W24 = 00000100
index = 3 -> W24 = 00001000

The `AND #0x1F` limits the shift amount to the lower five bits.

The actual memories use between 1 and 31 pieces, so the 32-bit mask can represent every valid memory definition.

After creating the single-shard bit, the game compares it with the current stored mask:

Code:
0x71054ABDA0    LDR W8, [SP,...]     // current mask
0x71054ABDA4    TST W24, W8
0x71054ABDA8    B.NE 0x71054ABE64

`TST` performs a bitwise AND for condition flags:

Code:
currentMask & singleShardBit

If the selected bit is already present, execution branches to:

Code:
0x71054ABE64    MOV W0, #6
0x71054ABE68    B   function_exit

The result enum identifies value 6 as:

Code:
public enum AddRemoveItemResult
{
Success                     = 0,
InvalidItem                 = 1,
InventoryFull               = 2,
InvalidInventory            = 3,
NotInInventory              = 4,
InvalidCharacter            = 5,
MemoryShardAlreadyCollected = 6
}

The effective logic is:

Code:
if ((currentMask & singleShardBit) != 0)
return MemoryShardAlreadyCollected;

This is a problem for the Get All routine because the selected index is random.

A memory may still be incomplete, but if the one randomly selected piece was already collected, the entire request stops without updating that memory.

The main duplicate branch is changed from:

Code:
Original:
0x71054ABDA8    B.NE 0x71054ABE64

Patched:
0x71054ABDA8    NOP

The preceding shard-bit calculation is not modified:

Code:
0x71054ABD9C    LSL W24, W9, W8

The NOP only prevents the duplicate result branch from being taken.

`AddMemoryShard` also contains a fallback path used when the ItemState does not contain the expected MemoryShardIndex case.

That path uses bit zero:

Code:
0x71054ABE4C    MOV W8, WZR
0x71054ABE50    MOV W9, #1
0x71054ABE54    LSL W24, W9, WZR     // W24 = 1

0x71054ABE58    LDR W8, [SP,...]
0x71054ABE5C    TST W24, W8
0x71054ABE60    B.EQ 0x71054ABDAC

Originally:

Code:
if bit zero is not already collected:
continue to the update

otherwise:
fall through to MemoryShardAlreadyCollected

The conditional branch is replaced with an unconditional branch:

Code:
Original:
0x71054ABE60    B.EQ 0x71054ABDAC

Patched:
0x71054ABE60    B    0x71054ABDAC

The normal DebugAddItem route should provide a valid MemoryShardIndex state, but both rejection paths are patched so that neither route can stop at `MemoryShardAlreadyCollected`.

These patches solve the random duplicate problem, but they do not yet complete the whole memory.

The normal code still adds only one bit.

After passing the duplicate check, the game retrieves the current mask:

Code:
0x71054ABDAC    LDR X23, [X23,#0x108]

...

0x71054ABDC8    MOV X0, X23
0x71054ABDCC    BL  MapField<int,int>.get_Item

0x71054ABDD0    LDR W8, [SP,...]     // current mask

It prepares the key, value pointer and MethodInfo for `set_Item`:

Code:
0x71054ABDD4    ADRP X9, Method$MapField<int,int>.set_Item
0x71054ABDD8    SUB  X1, X29, ...    // key pointer
0x71054ABDDC    LDR  X3, [X9,...]    // MethodInfo
0x71054ABDE0    ADD  X2, SP, ...     // value pointer
0x71054ABDE4    MOV  X0, X23         // map
0x71054ABDE8    STUR W21, [X29,...]  // Item key

The original mask update is:

Code:
0x71054ABDEC    ORR W8, W8, W24

Equivalent logic:

Code:
newMask =
currentMask | singleShardBit;

It then stores the new mask and updates the map:

Code:
0x71054ABDF0    STR W8, [SP,...]
0x71054ABDF4    BL  MapField<int,int>.set_Item

Even after disabling the duplicate check, this operation would still add only one randomly selected piece.

A ten-piece memory would require up to ten separate successful requests.

The goal of this code is instead to write the complete mask in one request.

`MemoryShardItemData` exposes:

Code:
public int CompletedShardFlag { get; }

The native getter is:

Code:
0x7104398BA0    LDR W8, [X0,#0x68]    // NumberOfShards
0x7104398BA4    MOV W9, #0xFFFFFFFF
0x7104398BA8    LSL W8, W9, W8
0x7104398BAC    MVN W0, W8
0x7104398BB0    RET

Equivalent formula:

Code:
completedShardFlag =
~(0xFFFFFFFFu << NumberOfShards);

For shard counts from 1 through 31, this is also:

Code:
completedShardFlag =
(1u << NumberOfShards) - 1;

Examples:

Code:
NumberOfShards = 1
Completed mask = 0x00000001
Binary         = 00000001

NumberOfShards = 3
Completed mask = 0x00000007
Binary         = 00000111

NumberOfShards = 5
Completed mask = 0x0000001F
Binary         = 00011111

NumberOfShards = 10
Completed mask = 0x000003FF
Binary         = 1111111111

Every bit from zero through `NumberOfShards - 1` is set.

The actual memory definitions use `NumberOfShards` values within the supported range of 1 through 31.

`ProfilePlayer.IsMemoryShardCompleted` first reads the stored mask from:

Code:
ProfilePlayer.memoryShards_ +0x108

Relevant excerpt:

Code:
0x71054AB85C    LDR X0, [X20,#0x108]
...
0x71054AB870    STR W19, [SP,...]     // Item key
...
0x71054AB87C    BL  MapField<int,int>.TryGetValue

0x71054AB884    LDR W20, [X29,...]    // stored mask
0x71054AB888    CBZ W20, return_false

It retrieves the matching MemoryShardItemData and calculates the same full mask:

Code:
0x71054AB8C0    ADRP X8,
Method$ItemDatabase.GetItemData<MemoryShardItemData>

0x71054AB8C4    AND X1, X19, #0xFFFFFFFF
0x71054AB8C8    LDR X2, [X8,...]
0x71054AB8CC    BL  ItemDatabase.GetItemData<MemoryShardItemData>

0x71054AB8D4    LDR W8, [X0,#0x68]
0x71054AB8D8    MOV W9, #0xFFFFFFFF
0x71054AB8E8    LSL W8, W9, W8
0x71054AB8F4    MVN W8, W8

Near the end, it compares the stored mask with that calculated mask:

Code:
0x71054ABA14    LDR W19, [X29,...]    // completed mask
...
0x71054ABA54    CMP W20, W19
...
0x71054ABA60    CSET W0, NE

The surrounding nullable-value check makes the effective result:

Code:
return completedMaskExists
&& storedMask == completedMask;

Writing the full completion mask therefore creates the exact state that the game itself recognizes as a completed memory.

The original instruction is:

Code:
0x71054ABDEC    ORR W8, W8, W24

It is replaced with:

Code:
0x71054ABDEC    BL 0x7108CB417C

This sends execution to a second code-cave routine.

At this point in `AddMemoryShard`, the following arguments have already been prepared for the upcoming `MapField.set_Item` call:

Code:
X0 = memoryShards_ map
X1 = pointer to Item key
X2 = pointer to mask value
X3 = MethodInfo for MapField<int,int>.set_Item

The stub must call other functions to retrieve `NumberOfShards`.

Those function calls may overwrite X0 through X18, so the four prepared arguments are saved first:

Code:
0x7108CB417C    STP X0, X1, [SP,#-0x10]!
0x7108CB4180    STP X2, X3, [SP,#-0x10]!

The stack remains 16-byte aligned.

`AddMemoryShard` stores its Item argument in X21 near its entry:

Code:
MOV X21, X1

X21 is callee-saved, so it is still available when the stub is reached.

The stub obtains ItemDatabase.Instance:

Code:
0x7108CB4184    BL 0x7104A8A200

It then passes the current MemoryShard Item in X1:

Code:
0x7108CB4188    MOV X1, X21

and calls:

Code:
public IItemData GetItemData(Item item);

Native call:

Code:
0x7108CB418C    BL 0x7104A858D0

Although the declared return type is `IItemData`, this code runs inside `AddMemoryShard` after the ItemType has already been validated as MemoryShard.

The returned object is therefore a `MemoryShardItemData` instance.

The stub reads:

Code:
0x7108CB4190    LDR W9, [X0,#0x68]

which gives:

Code:
W9 = MemoryShardItemData.NumberOfShards

The stub calculates:

Code:
0x7108CB4194    MOV W8, #-1
0x7108CB4198    MOV W10, #32
0x7108CB419C    SUB W10, W10, W9
0x7108CB41A0    LSR W8, W8, W10

Equivalent formula:

Code:
fullMask =
0xFFFFFFFFu >>
(32 - NumberOfShards);

For `NumberOfShards` values from 1 through 31, this produces the same result as the game’s `CompletedShardFlag` getter:

Code:
0xFFFFFFFFu >> (32 - N)

=

~(0xFFFFFFFFu << N)

=

(1u << N) - 1

For example:

Code:
N = 5

# 0xFFFFFFFF >> 27

# 0x0000001F

00011111

W8 now contains the complete memory mask instead of:

Code:
currentMask | singleShardBit

The old mask does not need to be included because the full mask already contains every valid collected bit.

After calculating the mask, the stub restores the prepared arguments:

Code:
0x7108CB41A4    LDP X2, X3, [SP],#0x10
0x7108CB41A8    LDP X0, X1, [SP],#0x10

W8 is intentionally not restored.

It contains the new full mask.

The stub then branches directly back to:

Code:
0x71054ABDF0

using:

Code:
0x7108CB41AC    B 0x71054ABDF0

The original function continues with:

Code:
0x71054ABDF0    STR W8, [SP,...]
0x71054ABDF4    BL  MapField<int,int>.set_Item

The result is:

Code:
memoryShards_[currentItem] =
completedShardFlag;

The stub does not use `RET`.

The `BL` at `0x71054ABDEC` originally placed `0x71054ABDF0` in X30, but the stub’s internal BL calls overwrite X30.

That does not matter because the stub returns to the continuation point with an unconditional `B`, not through X30.

`AddMemoryShard` will later restore its own original X30 from its stack frame before returning.

The memory code contains five functional changes.

1. Request MemoryShard items

Code:
MOV W1, #13
BL  ItemDatabase.GetAllByType

2. Prevent consumable wrapping

Code:
Original:
0x7104CAA488    ORR W8, W22, W21

Patched:
0x7104CAA488    MOV W8, WZR

3. Disable the main already-collected branch

Code:
Original:
0x71054ABDA8    B.NE 0x71054ABE64

Patched:
0x71054ABDA8    NOP

4. Disable the fallback already-collected branch

Code:
Original:
0x71054ABE60    B.EQ 0x71054ABDAC

Patched:
0x71054ABE60    B 0x71054ABDAC

5. Replace the one-bit ORR with the full-mask stub

Code:
Original:
0x71054ABDEC    ORR W8, W8, W24

Patched:
0x71054ABDEC    BL 0x7108CB417C

All parts serve a separate purpose.

Removing one of them changes the result:

Code:
Without the wrap bypass:
MemoryShard may become a consumable item.

Without the duplicate bypass:
A partially completed memory may be skipped when the random
shard is already owned.

Without the full-mask stub:
Only one shard bit is added.

Without the Get All loop:
Only a single specified memory would be processed.

Code:
// ============================================================================
// Unlock All Memories + Bitmask Logic
// Target: v1.23.0 [0100D39012C1A800][v3801088][UPD]
// Code Cave Address: 0x7108CB4118 (Main) / 0x7108CB417C (Bitmask Stub)
// ============================================================================

// --- [Block A] Hook (Mdl.Ui.WardrobeMenu$$OnFocusIn) ------------------------
// Original: MOV X0, X19
0x7107B15AD8    BL    0x7108CB4118

// --- [Block B] DebugAddItem developer-check bypass --------------------------
// Address: Meta.DebugAddItem.Types.Response$$ApplyThis
// Original: CBZ W8, loc_7104CAE46C
0x7104CAE434    NOP

// --- [Block C] GetItemState consumable-wrap bypass --------------------------
// Address: Meta.DebugAddItem$$GetItemState
// Original: ORR W8, W22, W21
0x7104CAA488    MOV   W8, WZR

// --- [Block D] Disable MemoryShardAlreadyCollected exits --------------------

// Main MemoryShardIndex path
// Original: B.NE 0x71054ABE64
//
// The preceding instruction at 0x71054ABD9C:
//     LSL W24, W9, W8
// is not modified.
0x71054ABDA8    NOP

// Fallback path
// Original: B.EQ 0x71054ABDAC
0x71054ABE60    B     0x71054ABDAC

// --- [Block E] Replace single-bit ORR with FULLMASK_STUB --------------------
// Address: Meta.ProfilePlayer$$AddMemoryShard
// Original: ORR W8, W8, W24
0x71054ABDEC    BL    0x7108CB417C

// --- [Block F] Main Get All code cave ---------------------------------------

0x7108CB4118    STP   X19, X30, [SP, #-0x10]!
0x7108CB411C    STP   X19, X20, [SP, #-0x10]!
0x7108CB4120    STP   X21, X22, [SP, #-0x10]!

// Get active Client
0x7108CB4124    BL    0x71035CC3B0
0x7108CB4128    MOV   X19, X0

// Get ItemDatabase.Instance
0x7108CB412C    BL    0x7104A8A200

// Get every MemoryShard item
0x7108CB4130    MOV   W1,  #13
0x7108CB4134    MOV   X2,  XZR
0x7108CB4138    BL    0x7104A85F80

// Prepare array loop
0x7108CB413C    ADD   X20, X0, #0x20
0x7108CB4140    LDR   W21, [X0, #0x18]
0x7108CB4144    MOV   W22, #0

// Load current MemoryShardItemData* and Item
0x7108CB4148    LDR   X0, [X20, X22, LSL #3]
0x7108CB414C    LDR   W1, [X0, #0x18]

// Client.DebugAddItem(item, 1, default)
0x7108CB4150    MOV   X0, X19
0x7108CB4154    MOV   W2, #1
0x7108CB4158    MOV   X3, XZR
0x7108CB415C    BL    0x7105B5DD30

// Loop control
0x7108CB4160    ADD   W22, W22, #1
0x7108CB4164    CMP   W22, W21
0x7108CB4168    B.LT  0x7108CB4148

// Restore original Wardrobe state
0x7108CB416C    LDP   X21, X22, [SP], #0x10
0x7108CB4170    LDP   X19, X20, [SP], #0x10
0x7108CB4174    LDP   X0,  X30, [SP], #0x10
0x7108CB4178    RET

// --- [Block G] FULLMASK_STUB -------------------------------------------------

// Preserve the arguments already prepared for MapField.set_Item
0x7108CB417C    STP   X0, X1, [SP, #-0x10]!
0x7108CB4180    STP   X2, X3, [SP, #-0x10]!

// Get ItemDatabase.Instance
0x7108CB4184    BL    0x7104A8A200

// Get MemoryShardItemData for the current Item
0x7108CB4188    MOV   X1, X21
0x7108CB418C    BL    0x7104A858D0

// Calculate the full completion mask
0x7108CB4190    LDR   W9,  [X0, #0x68]
0x7108CB4194    MOV   W8,  #-1
0x7108CB4198    MOV   W10, #32
0x7108CB419C    SUB   W10, W10, W9
0x7108CB41A0    LSR   W8,  W8, W10

// Restore MapField.set_Item arguments
0x7108CB41A4    LDP   X2, X3, [SP], #0x10
0x7108CB41A8    LDP   X0, X1, [SP], #0x10

// Continue at:
//     STR W8, [value]
//     BL  MapField<int,int>.set_Item
0x7108CB41AC    B     0x71054ABDF0

The main Get All loop submits one asynchronous DebugAddItem request for every MemoryShard entry returned by ItemDatabase.

The routine does not wait for each request to finish.

The game may therefore continue processing memory updates after the code-cave loop has already returned.

Do not immediately trigger the routine again while the first set of requests is still being processed.

The routine does not check whether a memory is already complete before submitting it.

Every MemoryShard returned by GetAllByType is processed, and the corresponding stored mask is written to its complete value.

The code can complete:

  • Memories with no collected pieces
  • Partially completed memories
  • Memories whose randomly selected shard was already collected

The GetItemState wrap patch affects the shared function globally while enabled. Other item-addition operations should not be performed at the same time.

The two AddMemoryShard duplicate patches also change normal MemoryShard behavior while enabled.

Use the complete set of patches only for the memory-unlock operation and disable them afterward.

The following memory-specific locations must be verified after a game update:

Code:
Meta.DebugAddItem.GetItemState
wrap decision:
0x7104CAA488

Meta.ProfilePlayer.AddMemoryShard
main duplicate branch:
0x71054ABDA8

```
fallback duplicate branch:
0x71054ABE60

single-bit ORR:
0x71054ABDEC
```

ItemDatabase.GetItemData:
0x7104A858D0

MemoryShardItemData:
Item            +0x18
NumberOfShards  +0x68

The following common locations must also be updated as described in the Clothing post:

Code:
WardrobeMenu.OnFocusIn
DebugAddItem developer check
MissionManager.get_MetaClient
ItemDatabase.get_Instance
ItemDatabase.GetAllByType
Client.DebugAddItem
Main code cave
FULLMASK_STUB code cave

Do not update this code by applying one global address difference.

Each function, branch target, overwritten instruction and field offset must be verified in the new version.
 
  • Like
Reactions: weilai

Site & Scene News

Popular threads in this forum