/*================================================================= File created by Yohann NICOLAS. Add support 1.13d by L'Autour. Add support 1.14d by haxifix. Adding custom data. Save and load infinity & shared Stash =================================================================*/ #include "updateClient.h" #include "infinityStash.h" #include "savePlayerData.h" //Install_SavePlayerData() #include "loadPlayerData.h" //Install_LoadPlayerData() #include "common.h" bool active_PlayerCustomData = false; bool openSharedStashOnLoading = false; /*********************************** UPDATING ***********************************/ Stash* getStashFromItem(Unit* ptChar, Unit* ptItem) { Stash* curStash = PCPY->selfStash; Unit* curItem; while (curStash) { if (curStash == PCPY->currentStash) curItem = D2InventoryGetFirstItem(PCInventory); else curItem = curStash->ptListItem; while (curItem) { if (D2GetRealItem(curItem) == ptItem) return curStash; curItem = D2UnitGetNextItem(curItem); } curStash = curStash->nextStash; } curStash = PCPY->sharedStash; while (curStash) { if (curStash == PCPY->currentStash) curItem = D2InventoryGetFirstItem(PCInventory); else curItem = curStash->ptListItem; while (curItem) { if (D2GetRealItem(curItem) == ptItem) return curStash; curItem = D2UnitGetNextItem(curItem); } curStash = curStash->nextStash; } return NULL; } Unit* FASTCALL updateItem(Game* ptGame, DWORD type, DWORD itemNum, Unit* ptChar) { Unit* ptItem = D2GameGetObject(ptGame, type, itemNum); if (ptGame->isLODGame && (D2ItemGetPage(ptItem) == 4)) { Stash* ptStash = getStashFromItem(ptChar, ptItem); //log_msg("- updateItem PCPY->currentStash->id : %d // ptStash->id : %d\n", PCPY->currentStash?PCPY->currentStash->id:-1, ptStash?ptStash->id:-1); if (!ptStash) return NULL; selectStash(ptChar, ptStash, ptStash->id == 0); } return ptItem; } void FASTCALL updateItem_111(Unit* ptItem, Unit* ptChar) { if (PCGame->isLODGame && (D2ItemGetPage(ptItem) == 4)) { Stash* ptStash = getStashFromItem(ptChar, ptItem); if (ptStash) selectStash(ptChar, ptStash, ptStash->id == 0); } } void STDCALL updateClientPlayerOnLoading(Unit* ptChar) { log_msg("--- Start updateClientPlayerOnLoading ---\n"); if (PCGame->isLODGame) { PCPY->showSharedStash = openSharedStashOnLoading && active_sharedStash; selectStash(ptChar, PCPY->showSharedStash ? PCPY->sharedStash : PCPY->selfStash, true); } updateClient(ptChar, UC_SHARED_GOLD, PCPY->sharedGold, 0, 0); log_msg("End update client on loading.\n\n"); } /**************************** INIT CUSTOM DATA ****************************/ PlayerData* FASTCALL init_PlayerCustomData(DWORD p1, DWORD size, LPCSTR file, DWORD line, DWORD p5) { log_msg("init_PlayerCustomData\n"); PlayerData* playerData = (PlayerData*)D2AllocMem(p1,size+sizeof(PYPlayerData),file,line,p5); ZeroMemory((BYTE*)playerData + shifting.ptPYPlayerData, sizeof(PYPlayerData)); return playerData; } /**************************** FREE CUSTOM DATA ****************************/ void freeStash(Stash* ptStash) { if (!ptStash) return; freeStash(ptStash->nextStash); free(ptStash->nextStash);// D2FogMemDeAlloc(ptStash->nextStash,__FILE__,__LINE__,0); if(ptStash->name) { free(ptStash->name);//D2FogMemDeAlloc(ptStash->name,__FILE__,__LINE__,0); ptStash->name = NULL; } ptStash->nextStash = NULL; } void FASTCALL free_PlayerCustomData(DWORD p1, PlayerData* playerData, LPCSTR file, DWORD line, DWORD p5) { log_msg("free_PlayerCustomData\n"); PYPlayerData* ptPYPlayerData = (PYPlayerData*)((DWORD)playerData + shifting.ptPYPlayerData); freeStash(ptPYPlayerData->selfStash); free(ptPYPlayerData->selfStash);//D2FogMemDeAlloc(ptPYPlayerData->selfStash,__FILE__,__LINE__,0); ptPYPlayerData->selfStash = NULL; freeStash(ptPYPlayerData->sharedStash); free(ptPYPlayerData->sharedStash);//D2FogMemDeAlloc(ptPYPlayerData->sharedStash,__FILE__,__LINE__,0); ptPYPlayerData->sharedStash = NULL; D2FreeMem(p1,playerData,file,line,p5); } Unit* STDCALL getNextItemToFree(Unit* ptChar, Unit* ptItem) { Unit* item = D2UnitGetNextItem(ptItem); if (item) return item; if (ptChar->nUnitType != UNIT_PLAYER) return NULL; if (!PCPlayerData) return NULL; if (!PCPY) return NULL; Stash* curStash = PCPY->selfStash; while ( curStash ) { if (curStash->ptListItem) { item = curStash->ptListItem; curStash->ptListItem = NULL; return item;//->nUnitType == 4 ? item : NULL; } curStash = curStash->nextStash; } curStash = PCPY->sharedStash; while ( curStash ) { if (curStash->ptListItem) { item = curStash->ptListItem; curStash->ptListItem = NULL; return item->nUnitType == 4 ? item : NULL; } curStash = curStash->nextStash; } return NULL; } /************************ INSTALL PLAYER CUSTOM DATA ****************************/ FCT_ASM ( caller_updateItem_114 ) PUSH EDI PUSH DWORD PTR SS:[ESP+0x8] CALL updateItem RETN 4 }} FCT_ASM ( caller_updateItem_111 ) MOV ECX,ESI MOV EDX,EBP CALL updateItem_111 POP EAX MOV EDX,DWORD PTR SS:[ESP+0x18] PUSH EDX JMP EAX }} FCT_ASM ( caller_updateItemB_111 ) MOV EDX,EBP CALL updateItem_111 POP EAX MOV EDX,DWORD PTR SS:[ESP+0x18] PUSH EDX JMP EAX }} FCT_ASM ( caller_updateItem ) PUSH EBP PUSH DWORD PTR SS:[ESP+0x8] CALL updateItem RETN 4 }} FCT_ASM ( caller_updateItem_9 ) PUSH EBX PUSH DWORD PTR SS:[ESP+0x8] CALL updateItem RETN 4 }} FCT_ASM ( caller_updateClientPlayerOnLoading_114 ) PUSH DWORD PTR SS:[ESP+0x14] CALL updateClientPlayerOnLoading POP ECX POP EDI POP ESI XOR EAX,EAX POP EBX JMP ECX }} FCT_ASM ( caller_updateClientPlayerOnLoading ) PUSH DWORD PTR SS:[ESP+0x14] CALL updateClientPlayerOnLoading POP ECX POP EDI POP ESI POP EBP XOR EAX,EAX JMP ECX }} FCT_ASM ( callerServer_getNextItemToFree_114 ) PUSH DWORD PTR SS:[ESP+4] PUSH DWORD PTR SS:[EBP-8] CALL getNextItemToFree RETN 4 }} FCT_ASM ( callerServer_getNextItemToFree_111 ) PUSH DWORD PTR SS:[ESP+4] PUSH DWORD PTR SS:[ESP+0x30] CALL getNextItemToFree RETN 4 }} FCT_ASM ( callerServer_getNextItemToFree ) PUSH DWORD PTR SS:[ESP+4] PUSH DWORD PTR SS:[ESP+0x28] CALL getNextItemToFree RETN 4 }} FCT_ASM ( callerServer_getNextItemToFree_9 ) PUSH DWORD PTR SS:[ESP+4] PUSH DWORD PTR SS:[ESP+0x1C] CALL getNextItemToFree RETN 4 }} FCT_ASM ( callerClient_getNextItemToFree_114 ) PUSH DWORD PTR SS:[ESP+4] PUSH DWORD PTR SS:[EBP-4] CALL getNextItemToFree RETN 4 }} FCT_ASM ( callerClient_getNextItemToFree_111 ) PUSH DWORD PTR SS:[ESP+4] PUSH EBX CALL getNextItemToFree RETN 4 }} FCT_ASM ( callerClient_getNextItemToFree ) PUSH DWORD PTR SS:[ESP+4] PUSH DWORD PTR SS:[ESP+0x24] CALL getNextItemToFree RETN 4 }} FCT_ASM ( callerClient_getNextItemToFree_9 ) PUSH DWORD PTR SS:[ESP+4] PUSH DWORD PTR SS:[ESP+0x28] CALL getNextItemToFree RETN 4 }} void Install_PlayerCustomData() { static int isInstalled = false; if (isInstalled) return; Install_SavePlayerData(); Install_LoadPlayerData(); Install_UpdateClient(); log_msg("Patch D2Game & D2Client & D2Common for Player's custom data. (PlayerCustomData)\n"); // Initialize custom data. mem_seek(version_D2Client == V114d ? offset_D2Common + 0x221FDD : version_D2Client == V113d ? offset_D2Common + 0x170DE : version_D2Client == V113c ? offset_D2Common + 0x309BE : version_D2Client == V112 ? offset_D2Common + 0x585EE : version_D2Client == V111b ? offset_D2Common + 0x5BFCE : version_D2Common == V111 ? offset_D2Common + 0x4ED5E :(DWORD)D2InitPlayerData + 0x62 ); MEMJ_REF4( D2AllocMem, init_PlayerCustomData); //01BD0381 |. E8 C03F0000 CALL //6FD9ED5D |. E8 94A4FBFF CALL //6FDABFCD |. E8 34D2FAFF CALL //6FDA85ED |. E8 240CFBFF CALL //6FD809BD |. E8 6088FDFF CALL //6FD670DD |. E8 0C3EFFFF CALL //00621FDC |. E8 4F94DEFF CALL Game.0040B430 ; \Game.0040B430 if ( version_D2Game >= V111 && version_D2Game <= V113d) { // update item mem_seek R8(D2Game, 10933, 10C03, 1100D, 8BC71, C3C51, 5F2A1, 9BB91, 75C81, 0000); memt_byte( 0x8B ,0xE8); // CALL MEMT_REF4( 0x52182454, caller_updateItem_111); //0200BC71 |> 8B5424 18 |MOV EDX,DWORD PTR SS:[ESP+18] //0200BC75 |. 52 |PUSH EDX ; /Arg1 //02023C51 |> 8B5424 18 |MOV EDX,DWORD PTR SS:[ESP+18] //02023C55 |. 52 |PUSH EDX ; /Arg1 //6FC7F2A1 |> 8B5424 18 |MOV EDX,DWORD PTR SS:[ESP+18] //6FC7F2A5 |. 52 |PUSH EDX ; /Arg1 //6FCBBB91 |> 8B5424 18 |MOV EDX,DWORD PTR SS:[ESP+18] //6FCBBB95 |. 52 |PUSH EDX //6FC95C81 |> 8B5424 18 |MOV EDX,DWORD PTR SS:[ESP+18] //6FC95C85 |. 52 |PUSH EDX mem_seek R8(D2Game, 1097B, 10C4B, 11058, 8BCD1, C3CB1, 5F301, 9BBF1, 75CE1, 0000); memt_byte( 0x8B ,0xE8); // CALL MEMT_REF4( 0x52182454, caller_updateItemB_111); //0200BCD1 |> 8B5424 18 ||MOV EDX,DWORD PTR SS:[ESP+18] //0200BCD5 |. 52 ||PUSH EDX ; /Arg1 //02023CB1 |> 8B5424 18 ||MOV EDX,DWORD PTR SS:[ESP+18] //02023CB5 |. 52 ||PUSH EDX ; /Arg1 //6FC7F301 |> 8B5424 18 ||MOV EDX,DWORD PTR SS:[ESP+18] //6FC7F305 |. 52 ||PUSH EDX ; /Arg1 //6FCBBBF1 |> 8B5424 18 ||MOV EDX,DWORD PTR SS:[ESP+18] //6FCBBBF5 |. 52 ||PUSH EDX //6FC95CE1 |> 8B5424 18 ||MOV EDX,DWORD PTR SS:[ESP+18] //6FC95CE5 |. 52 ||PUSH EDX } else { // update item mem_seek R8(D2Game, 10933, 10C03, 1100D, 8BC71, C3C51, 5F2A1, 0000, 0000, 1978F3); MEMC_REF4( D2GameGetObject, version_D2Game >= V114a ? caller_updateItem_114 : version_D2Game >= V110 ? caller_updateItem : caller_updateItem_9); //6FC4100C |. E8 EFAA0700 |CALL D2Game.6FCBBB00 //005978F2 |. E8 69B6FBFF |CALL Game.00552F60 ; \Game.00552F60 mem_seek R8(D2Game, 1097B, 10C4B, 11058, 8BCD1, C3CB1, 5F301, 0000, 0000, 197943); MEMC_REF4( D2GameGetObject, version_D2Game >= V114a ? caller_updateItem_114 : version_D2Game >= V110 ? caller_updateItem : caller_updateItem_9); //6FC41057 |. E8 A4AA0700 ||CALL D2Game.6FCBBB00 //00597942 |. E8 19B6FBFF |CALL Game.00552F60 ; \Game.00552F60 //005978F2 |. E8 69B6FBFF |CALL Game.00552F60 ; \Game.00552F60 } // Update client on loading mem_seek R8(D2Game, 23EB, 2426, 25D4, 53482, C6A32, ED502, 4BF12, E7548, 139A20);//6FC325D4-6FC30000 memt_byte( 0x5F ,0xE8); // CALL MEMT_REF4( version_D2Game >= V114d ? 0x5BC0335E : 0xC0335D5E , version_D2Game >= V114d ? caller_updateClientPlayerOnLoading_114 : caller_updateClientPlayerOnLoading); //6FC325D4 |> 5F POP EDI //6FC325D5 |. 5E POP ESI //6FC325D6 |. 5D POP EBP //6FC325D7 |. 33C0 XOR EAX,EAX //01FD3482 |> 5F POP EDI //01FD3483 |. 5E POP ESI //01FD3484 |. 5D POP EBP //01FD3485 |. 33C0 XOR EAX,EAX //02026A32 |> 5F POP EDI //02026A33 |. 5E POP ESI //02026A34 |. 5D POP EBP //02026A35 |. 33C0 XOR EAX,EAX //6FD0D502 |> 5F POP EDI //6FD0D503 |. 5E POP ESI //6FD0D504 |. 5D POP EBP //6FD0D505 |. 33C0 XOR EAX,EAX //6FC6BF12 |> 5F POP EDI //6FC6BF13 |. 5E POP ESI //6FC6BF14 |. 5D POP EBP //6FC6BF15 |. 33C0 XOR EAX,EAX //6FD07548 |> 5F POP EDI //6FD07549 |. 5E POP ESI //6FD0754A |. 5D POP EBP //6FD0754B |. 33C0 XOR EAX,EAX //00539A20 |> 5F POP EDI //00539A21 |. 5E POP ESI //00539A22 |. 33C0 XOR EAX,EAX //00539A24 |. 5B POP EBX // Free custom data. mem_seek R8(D2Common, 7055C, 7065C, 80483, 4F82D, 5C9CD, 5856D, 3093D, 1705D, 2220DD); MEMJ_REF4( D2FreeMem, free_PlayerCustomData); //01BD0482 |. E8 C53E0000 CALL //6FD9F82C |. E8 E399FBFF CALL //6FDAC9CC |. E8 3BC8FAFF CALL //6FDA856C |. E8 E70CFBFF CALL //6FD8093C |. E8 E788FDFF CALL //6FD6705C |. E8 CF3EFFFF CALL //006220DC |. E8 9F93DEFF CALL Game.0040B480 ; \Game.0040B480 // Free item in Stash (Server-side) mem_seek R8(D2Game, 7D12B, 7D62B, 8D5A4, 99112, BFDB2, 94242, E1162, 6F7C2, 155B34); MEMJ_REF4( D2UnitGetNextItem, version_D2Game >= V114a ? callerServer_getNextItemToFree_114 : version_D2Game >= V111 ? callerServer_getNextItemToFree_111 : version_D2Game == V110 ? callerServer_getNextItemToFree : callerServer_getNextItemToFree_9);//0x0005E204 //6FCBD5A3 . E8 04E20500 CALL //02019111 |. E8 5016F7FF |CALL //0202FDB1 |. E8 30AAF4FF |CALL //6FCB4241 |. E8 8862F7FF |CALL //6FD01161 |. E8 6693F2FF |CALL //6FC8F7C1 |. E8 44AEF9FF |CALL //00555B33 |. E8 68840E00 |CALL Game.0063DFA0 ; \Game.0063DFA0 // Free item in Stash (Client-side) mem_seek R8(D2Client, 8EF8F, 8E30F, 89B32, 26404, 4C264, 1F2D4, A5C94, 621E4, 66D02);//6FB29B31-6FAA0000 MEMJ_REF4( D2UnitGetNextItem, version_D2Game >= V114d ? callerClient_getNextItemToFree_114 : version_D2Game >= V111 ? callerClient_getNextItemToFree_111 : version_D2Game == V110 ? callerClient_getNextItemToFree : callerClient_getNextItemToFree_9);//0x00040F34 //6FB29B31 E8 340F0400 CALL //6FAD6403 |. E8 925DFEFF |CALL //6FAFC263 |. E8 38FFFBFF |CALL //6FACF2D3 |. E8 4CD1FEFF |CALL //6FB55C93 |. E8 D068F6FF |CALL //6FB121E3 |. E8 7AA1FAFF |CALL //00466D01 E8 9A721D00 |CALL Game.0063DFA0 if ( version_D2Common >= V110 ) { // Test if it's already removed from inventory mem_seek R8(D2Common, 0000, 0000, 4E689, 26E33, 42133, 6AE93, 21B23, 3B393, 23ADB5); memt_byte( version_D2Common == V114d ? 0x0E : 0x0D , 0x07); //01D2E688 75 0D JNZ SHORT D2Common.01D2E697 //6FD76E32 |. 74 0D JE SHORT D2Common.6FD76E41 //6FD92132 |. 74 0D JE SHORT D2Common.6FD92141 //6FDBAE92 |. 74 0D JE SHORT D2Common.6FDBAEA1 //6FD71B22 |. 74 0D JE SHORT D2Common.6FD71B31 //6FD8B392 |. 74 0D JE SHORT D2Common.6FD8B3A1 //0063ADB4 |. 74 0E JE SHORT Game.0063ADC4 } else { mem_seek R8(D2Game, 7D176, 7D676, 0000, 0000, 0000, 0000, 0000, 0000, 0000); memt_byte( 0x74 , 0x90);//MOV EAX,EDI memt_byte( 0x35 , 0x90);//NOP //6FCAD176 |. 74 35 |JE SHORT D2Game.6FCAD1AD mem_seek R8(D2Client, 8F0CA, 8E44A, 0000, 0000, 0000, 0000, 0000, 0000, 0000); memt_byte( 0x0F , 0x90);//MOV EAX,EDI memt_byte( 0x84 , 0x90);//NOP memt_dword( 0x000000BF , 0x90909090);//NOP //6FB2F0CA |. 0F84 BF000000 |JE D2Client.6FB2F18F mem_seek R8(D2Client, 8F13C, 8E4BC, 0000, 0000, 0000, 0000, 0000, 0000, 0000); memt_byte( 0x74 , 0x90);//MOV EAX,EDI memt_byte( 0x6F , 0x90);//NOP //6FB2F13C |. 74 6F |JE SHORT D2Client.6FB2F1AD } log_msg("\n"); isInstalled = true; } /*================================= END OF FILE =================================*/