D2Template

Threads that no longer serve a purpose. Read-only.
User avatar
whist
Team Member
634 | 557
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Legendary Contribution Badge
Median XL Team Member
D2Template
D2Template is a project that was developed in order to help modders getting started into advanced code editing on Diablo II. D2Template provides a basic and relatively simple C++ source code, ready to be injected in-game in order to achieve advanced edits using your own injected source code. The template itself does not achieve any edit. It only provides you a starter kit for you to make your own edits. That is, the template itself is version independent, until you add code to it of course.

This is a community project, and therefore, any improvement suggestion is welcome. Anything I consider to be a valuable addition/modification will be added to the distributed version, with credits given nonetheless.

** WARNING **

There is currently no documentation available for this project. I currently don't have any time for this, and likely never will in a near future. That is, you are free to use this template and mess around with it, but do not message me any question about it, I will not reply. I do hope some more advanced users, that use this template for their project will write the documentation, but meanwhile, you are on your own. What you do with this template is up to you and only concerns you, but any question should still follow the site's rules.

Download D2Template
(Last Update: March 1st 2015)

What does the template include exactly?

To start off, a patcher. This is pretty much the basic of basics, as you need to inject your code into the game at some point, right? You do not need to get into complicated memory patching coding, the template does it for you. Then you have some various utility files, for pointers importing from the game's library, variables declaration, etc.

What do I need to use this template?

The template was created and compiled with Visual Studio 2012, so it is better if you get Visual Studio 2012 (or just Visual C++ 2012). It is in theory possible to get the template to work with any other IDE but you will not get any support on this from me. Tutorials/Modified templates for other IDE are welcome.

What should I know before using this template?

First of all, get started with the basics of C/C++. Get used to the syntax, practice by creating basic programs, get at least a basic knowledge of the language. Next, get used with the IDE you're going to use to work with this template. And finally, basic ASM knowledge can also help you a lot.

Can I use this to create a hack for MXL?

Well, you surely can as this template has basically no specific purpose and can therefore be used to inject code that's meant for cheating. Although, you will not get any help from me on this, and you should refrain from asking any question about it on this board.
Edited by whist 8 years.
User avatar
whist
Team Member
634 | 557
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Legendary Contribution Badge
Median XL Team Member
Documentation

D2Template Core Documentation



User Submitted Tutorials



(currently none available)

Plugins/Utilities/Etc



(currently none available)
Edited by whist 8 years.
User avatar
whist
Team Member
634 | 557
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Legendary Contribution Badge
Median XL Team Member
Injection Methods

Here you will find various injection methods, that will allow you to load your compiled template in-game. You're welcome to post your own, and have it added to this post.

PlugY 10.00 By Yohann



Version: 1.09D to 1.13c
Type: External Plugin

For more information & downloading, see this thread
The source code for this plugin is also available. (see the previously linked thread)

Once you have PlugY installed, you can have it load your compiled code, via the configuration file, PlugY.ini.
See the setting named "DllToLoad" under the [GENERAL] section of the configuration file, and add your dll there:

Code: Select all

[GENERAL]
//...
DllToLoad=D2Template.dll
//...


D2Mod By SVR



Version: 1.10f
Type: External Plugin

To download D2Mod, click here
For information, installation instructions, see this thread

Once you have D2Mod installed and configured, all you have to do is add the following to your D2Mod.ini configuration file, under the [D2MOD] section

Code: Select all

[D2MOD]
//...
D2Template=D2Template.dll
//...


D2SE By SeltSamuel



Version: 1.09 to 1.13c
Type: Launcher Replacement

To download and get more information about D2SE, see this thread
Once you have installed D2SE and got your mod plugin ready to go, open up your mod's configuration file, D2SE.ini, and under the [Protected] section, add the following:

Code: Select all

[protected]
//...
ModDll1=D2Template.dll
//...


Modified D2Win By Whist



Version: 1.13c
Type: Game Library Replacement

Click here to download

This one replaces D2Win.dll with a modified one. This one has been patched to load D2Template.dll. The patch is done at the end of the MPQ loading routine, D2Win.#10086. This one is meant to be used on 1.13c only as it is a 1.13c D2Win.dll
Edited by whist 8 years.
User avatar
whist
Team Member
634 | 557
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Legendary Contribution Badge
Median XL Team Member
Overview of Core Files

D2Template comes with a few core files. This here is meant to explain what these files are meant to do, how and why they're meant to be used (or not used in some cases...).

DLLmain.cpp & DLLmain.h



These two files are the heart of the template. They contain the module entry point function (often referred to as DllMain), the patching code, the basic includes and definitions, etc. You shouldn't need to edit these two files at all, and shouldn't do so unless you know what you're doing. Chances are, if you get to a point where you need to edit these files, you will be at a point where you know what you're doing. (or at least I hope so).

D2Constants.h



This file is meant to declare all constants values you will be using in your code. Sometimes, using names instead of raw numbers is more convenient. This also has the advantage of making your code more flexible, as if this value needed to change for any reason, you would only have one place to edit, rather than having to edit every single places where you used this constant (that's what would happen if you used raw numbers)

The file already contains an example, probably some of the most used constants, the unit types

Code: Select all

enum D2C_UnitTypes
{
   UNIT_PLAYER,               //0x00 Players
   UNIT_MONSTER,               //0x01 Monsters
   UNIT_OBJECT,               //0x02 Objects
   UNIT_MISSILE,               //0x03 Missiles
   UNIT_ITEM,                  //0x04 Items
   UNIT_TILE                  //0x05 Tiles
};


With these constants declared, you could now replace the following code

Code: Select all

if (pUnit->dwUnitType == 0) // checks if unit is player type


Using your declared constant

Code: Select all

if (pUnit->dwUnitType == UNIT_PLAYER)


D2Structs.h, D2DataTables.h & D2PacketDef.h



As you add more and more code, you will get to see the game uses a various amount of structures, to represent various entities. Be it unit entities, game entities, they are all handled as structure pointers. You will need to declare these structures, in order to use them in your code. This file is meant to do so. The template ships with a few examples by default, although due to the fact structs often have their layout changed between versions, they were left empty.

D2DataTables and D2PacketDef are only an expansion to D2Structs.h, in order to keep your code a little more organized.

D2Ptrs.h



This file here allows you to import pointers from the original game's libraries. Be it function pointers to call within your own code, variable pointers to read data from the game within your code, or just address pointers for inline asm functions, this is all declared in this file.

D2Vars.h



This file is meant to declare your own global variables, not much more to say about it.

D2Patch.h & D2PatchConst.h



You should only be editing D2Patch.h here, unless you know what you're doing. D2PatchConst only defines a few constants for the patcher and you shouldn't need to edit it. D2Patch is where you will add your patches. This is how you actually implement your changes into the game. After all, we need to patch the game's code at some point to have our code executed, right?

TemplateIncludes.h



This is where you add any additional includes. As you add more source files to your code, you will likely need to include new headers. This is where it's done.
Edited by whist 8 years.
User avatar
whist
Team Member
634 | 557
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Legendary Contribution Badge
Median XL Team Member
Declaring code patches

Declaring code patches is the basic of the template. After all, we need to inject our code into the game code flow at some point if we want it to be executed, right? This is done by patching the executable's memory to change it's flow. The template does this for you, all you have to do is setup an array of patches declarations, which is done in D2Patch.h

Structure of the patch array



The structure of patch definitions should look like this:

Code: Select all

{ DLL, OFFSET, SIZE, PATCH DATA, RELATIVE (bool) }


Now let's take a closer look at what every part of the array defines.

DLL: This defines in which of the game's library this patch should be applied. This is needed so that the template's patcher can retrieve the said library's base address (as the patcher uses relative addresses patch definitions, to keep compatibility in case of reallocation). The dll name definitions are found in DLLmain.h. It is also possible to extend this in order to have it patch custom libraries that are not defined in the original template but you shouldn't attempt this unless you know what you're doing.

Code: Select all

enum D2TEMPLATE_DLL_FILES
{
   D2DLL_BINKW32,
   D2DLL_BNCLIENT,
   D2DLL_D2CLIENT,
   D2DLL_D2CMP,
   D2DLL_D2COMMON,
   D2DLL_D2DDRAW,
   D2DLL_D2DIRECT3D,
   D2DLL_D2GAME,
   D2DLL_D2GDI,
   D2DLL_D2GFX,
   D2DLL_D2GLIDE,
   D2DLL_D2LANG,
   D2DLL_D2LAUNCH,
   D2DLL_D2MCPCLIENT,
   D2DLL_D2MULTI,
   D2DLL_D2NET,
   D2DLL_D2SOUND,
   D2DLL_D2WIN,
   D2DLL_FOG,
   D2DLL_GLIDE3X,
   D2DLL_IJL11,
   D2DLL_SMACKW32,
   D2DLL_STORM,
   D2DLL_PLUGY,
   D2DLL_D2SERVER,
   D2DLL_INVALID
};


OFFSET: This is the relative address at which the patch should be applied. Example, you want to patch something at D2Game.0x6FC25000, assuming the base address is 0x6FC20000, you would then set this part of the array as 0x5000.

SIZE: This here defines the number of bytes to patch. Setting this to 0 will make it patch a DWORD. You should use non-zero values only when you want to make big repetitive patches, such as nop blocks. Example:

Code: Select all

{D2DLL_D2CLIENT, 0x9A6F1, 0x34, (DWORD)PATCH_NOPBLOCK, FALSE},


This patch would look like this once applied:

Code: Select all

6FB4A6F1    90              NOP
6FB4A6F2    90              NOP
6FB4A6F3    90              NOP
6FB4A6F4    90              NOP
6FB4A6F5    90              NOP
6FB4A6F6    90              NOP
6FB4A6F7    90              NOP
6FB4A6F8    90              NOP
6FB4A6F9    90              NOP
6FB4A6FA    90              NOP
6FB4A6FB    90              NOP
6FB4A6FC    90              NOP
6FB4A6FD    90              NOP
6FB4A6FE    90              NOP
6FB4A6FF    90              NOP
6FB4A700    90              NOP
6FB4A701    90              NOP
6FB4A702    90              NOP
6FB4A703    90              NOP
6FB4A704    90              NOP
6FB4A705    90              NOP
6FB4A706    90              NOP
6FB4A707    90              NOP
6FB4A708    90              NOP
6FB4A709    90              NOP
6FB4A70A    90              NOP
6FB4A70B    90              NOP
6FB4A70C    90              NOP
6FB4A70D    90              NOP
6FB4A70E    90              NOP
6FB4A70F    90              NOP
6FB4A710    90              NOP
6FB4A711    90              NOP
6FB4A712    90              NOP
6FB4A713    90              NOP
6FB4A714    90              NOP
6FB4A715    90              NOP
6FB4A716    90              NOP
6FB4A717    90              NOP
6FB4A718    90              NOP
6FB4A719    90              NOP
6FB4A71A    90              NOP
6FB4A71B    90              NOP
6FB4A71C    90              NOP
6FB4A71D    90              NOP
6FB4A71E    90              NOP
6FB4A71F    90              NOP
6FB4A720    90              NOP
6FB4A721    90              NOP
6FB4A722    90              NOP
6FB4A723    90              NOP
6FB4A724    90              NOP


PATCH DATA: This is the data you want to patch. This can be a function, some bytes, whatever you want. This is explained further later in this tutorial.

RELATIVE: This tells the patcher whether it should consider this patch as a relative address. If you look at how calls or jumps work in ASM, you will notice it doesn't point directly to an address

Code: Select all

6FB4A6CE    E8 DD28FFFF     CALL D2Client.6FB3CFB0


Setting this to true will make the patcher handle this stuff on it's own so that we don't need to worry about it. So when patching function adresses basically, you set this to true. (in most cases)

Patch Defintions Examples



There's plenty of different stuff you can patch using the patcher, but here goes the main ones you will be using.
You will likely find out what other types of patches there is to make by yourself as you get better at code injection with the template.

Patching a NOP block

The following patch would patch a block of 52 NOP's at D2Client.0x9A6F1

Code: Select all

{D2DLL_D2CLIENT, 0x9A6F1, 0x34, (DWORD)PATCH_NOPBLOCK, FALSE},


This patch would look like this once applied:

Code: Select all

6FB4A6F1    90              NOP
6FB4A6F2    90              NOP
6FB4A6F3    90              NOP
6FB4A6F4    90              NOP
6FB4A6F5    90              NOP
6FB4A6F6    90              NOP
6FB4A6F7    90              NOP
6FB4A6F8    90              NOP
6FB4A6F9    90              NOP
6FB4A6FA    90              NOP
6FB4A6FB    90              NOP
6FB4A6FC    90              NOP
6FB4A6FD    90              NOP
6FB4A6FE    90              NOP
6FB4A6FF    90              NOP
6FB4A700    90              NOP
6FB4A701    90              NOP
6FB4A702    90              NOP
6FB4A703    90              NOP
6FB4A704    90              NOP
6FB4A705    90              NOP
6FB4A706    90              NOP
6FB4A707    90              NOP
6FB4A708    90              NOP
6FB4A709    90              NOP
6FB4A70A    90              NOP
6FB4A70B    90              NOP
6FB4A70C    90              NOP
6FB4A70D    90              NOP
6FB4A70E    90              NOP
6FB4A70F    90              NOP
6FB4A710    90              NOP
6FB4A711    90              NOP
6FB4A712    90              NOP
6FB4A713    90              NOP
6FB4A714    90              NOP
6FB4A715    90              NOP
6FB4A716    90              NOP
6FB4A717    90              NOP
6FB4A718    90              NOP
6FB4A719    90              NOP
6FB4A71A    90              NOP
6FB4A71B    90              NOP
6FB4A71C    90              NOP
6FB4A71D    90              NOP
6FB4A71E    90              NOP
6FB4A71F    90              NOP
6FB4A720    90              NOP
6FB4A721    90              NOP
6FB4A722    90              NOP
6FB4A723    90              NOP
6FB4A724    90              NOP


Patching a function call (to call our own function instead)

The following patch would replace the call to D2Client.0xC39E0 with our own function. Notice we don't patch D2Client.0x4437B here, but rather one byte later as we do not want to overwrite the CALL instruction. An ASM CALL instruction looks like this 0xE8 ########. The 0xE8 is the CALL instruction, the ######## is the part we want to patch.

Code: Select all

{D2DLL_D2CLIENT, 0x4437C, 0x00, (DWORD)D2UI_Main, TRUE},


The patch would look like this once applied:

Code: Select all

6FAF437B    E8 ########     CALL D2Template.########


Patching a function call (where there is no call instruction originally)

Similar to the previous patch, except that we're patching a location where there is no call instruction originally, so we need to patch it ourself.

Code: Select all

{D2DLL_D2CLIENT, 0x8B1DE, 0x00, (DWORD)PATCH_CALL, FALSE},            // needs to be declared first
{D2DLL_D2CLIENT, 0x8B1DF, 0x00, (DWORD)DRLGUI_LevelBackground, TRUE},


The patch would look like this once applied:

Code: Select all

6FB3B1DE    E8 ########     CALL D2Template.########


You can do the same thing with a jump if you want:

Code: Select all

{D2DLL_FOG, 0x17F60, 0x00, (DWORD)PATCH_JMP, FALSE},
{D2DLL_FOG, 0x17F61, 0x00, (DWORD)SAVEFILE_GetSavePath, TRUE},
Edited by whist 8 years.
User avatar
whist
Team Member
634 | 557
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Legendary Contribution Badge
Median XL Team Member
[reserved]
User avatar
whist
Team Member
634 | 557
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Legendary Contribution Badge
Median XL Team Member
[reserved]
User avatar
Marco
Team Member
1952 | 1347
Common Posting Badge
Posted over 1.000 messages
Legendary Popularity Badge
Has a thread with over 250.000 views
Legendary Love Badge
Earned over 500 cookies
Common Supporter Badge
Donated 1 time
Common Multiplayer Badge
Has won a multiplayer contest
Legendary Contribution Badge
Median XL Team Member
Common Auction Badge
Won 50 auctions
Cool layout :thumb:
User avatar
GregMXL
Team Member
10590 | 180
Legendary Posting Badge
Posted over 10.000 messages
Legendary Popularity Badge
Has a thread with over 250.000 views
Great Love Badge
Earned over 100 cookies
Great Supporter Badge
Donated 5 times
Legendary Contribution Badge
Median XL Team Member
Great Special Badge
Legend.
Holy poop this looks...Scary.
I don't mean to dwell...but I can't help myself.
Food
Core Lord
360 | 32
Great Popularity Badge
Has a thread with over 50.000 views
Common Love Badge
Earned over 20 cookies
Great Patron Badge
Patreon Contributor
Common Contribution Badge
Has collaborated to our forums, realms or mod
I wish I could help you with Sigma code editing but I know nothing about ASM. Do you think I could learn fast enough to lend a hand or is it a lost cause? I am a programmer by the way, it's not like I want to try something completely out of my league (not that's anything wrong with that).

If you think it's possible to reach the necessary expertise in a sufficiently small time frame and you need or want help then I'll try my best to learn, otherwise I'll just concentrate on something else.

Great job by the way.