ModEnc is currently in Maintenance Mode: Changes could occur at any given moment, without advance warning.

Contributing to Ares: Difference between revisions

From ModEnc
Jump to navigation Jump to search
Updating for new procedure
 
(16 intermediate revisions by 12 users not shown)
Line 1: Line 1:
{{HorizontalBar|{{W}}This is relatively unpolished. As the wrapper library and the project matures, simpler ways to create custom code will be created. {{tt|Don't panic.}}}}
Contributing to Ares is relatively simple, if you know at least the basics of C++:
Contributing to Ares is relatively simple, if you know at least the basics of C++:


== What you'll need ==
== What you'll need ==
; A knowledge of C++ : Yes, you'll need this.
; A knowledge of C++ : Yes, you'll need this.
; A C++ compiler/IDE : Right now, only [http://en.wikipedia.org/wiki/Microsoft_Visual_Studio Microsoft Visual Studio] is supported. Due to [http://forums.renegadeprojects.com/showthread.php?tid=1043&pid=12314#pid12314 binary layout issues], gcc-based compilers/IDEs like [http://www.bloodshed.net/devcpp.html Dev-C++]/[http://wxdsgn.sourceforge.net/ WxDev-C++] can '''not''' be used to create useful DLLs.  If you want a free solution, try Microsoft Visual C++ 2008 Express Edition (highly recommended).
; Microsoft's C++ compiler : Right now, only [http://en.wikipedia.org/wiki/Microsoft_Visual_Studio Microsoft Visual Studio] is supported. Due to [http://forums.renegadeprojects.com/showthread.php?tid=1043&pid=12314#pid12314 binary layout issues], gcc-based compilers/IDEs like [http://www.bloodshed.net/devcpp.html Dev-C++]/[http://wxdsgn.sourceforge.net/ WxDev-C++] can '''not''' be used to create useful DLLs.  If you want a free solution, try Microsoft Visual C++ '''2013''' Express Edition (recently we started employing C++0x features like lambda and auto, so it won't compile with the earlier versions).
; The Microsoft Visual C++ 2008 Redistributables : You can't run Syringe without these...
; The Microsoft Visual C++ 2013 Redistributables : You can't run Syringe without these. Installing the compiler from the previous step should provide these.
; The Microsoft Windows SDK : The [http://en.wikipedia.org/wiki/Microsoft_Windows_SDK Microsoft Windows SDK] is required to contribute to and compile Ares. Microsoft Visual Studio (not Express Edition) comes with it, but if you don't have it, you can freely download it from Microsoft's site.
; The Microsoft Windows SDK : The [http://en.wikipedia.org/wiki/Microsoft_Windows_SDK Microsoft Windows SDK] is required to contribute to and compile Ares. Microsoft Visual Studio (Express Edition) comes with it, but if you don't have it, you can freely download it from Microsoft's site, provided you have a legit copy of Windows.
; A Subversion (SVN) client : [http://tortoisesvn.tigris.org/ TortoiseSVN] is recommended.
; A Git client : [http://code.google.com/p/gitextensions/ GitExtensions] is recommended.


== Getting the code ==
== Getting the code ==
Line 15: Line 13:
; Ares itself : the code for Ares itself, the functionality that is actually utilised
; Ares itself : the code for Ares itself, the functionality that is actually utilised


Each of them has its own SVN repository:
Each of them has its own Git repository:
*Create a folder on your hard drive where you'll be keeping the code, for example, {{Tt|C:\My Documents\Visual Studio Projects\Ares}} or {{Tt|F:\source\Ares}}, whatever suits you.  
*Create a folder on your hard drive where you'll be keeping the code, for example, {{Tt|C:\My Documents\Visual Studio Projects\Ares}} or {{Tt|F:\source\Ares}}, whatever suits you.  
*Create two subfolders in it, one for yrpp and one for Ares.
*Create two subfolders in it, one for yrpp and one for Ares.


; {{tt|yrpp}}
; {{tt|yrpp}}
::*Right click yrpp's folder, and (as of this point we are assuming that you have successfully installed TortoiseSVN) select {{Tt|SVN Checkout...}} from the context menu.
*Start up Git Extensions.
::**Enter {{Tt|svn://www.renegadeprojects.com/yrpp/trunk}} as the {{Tt|Repository}} address.
**Open up Clone Github repository.
::**Leave the other options as they are, and press {{Tt|OK}}.
**Search out YRpp on the Search for repositories tab, take the one which is owned by the Ares-Developers, and select your destination folder.
**Leave the other options as they are, and press Clone.


; Ares:
; Ares:
:*Right click Ares' folder, and select {{Tt|SVN Checkout...}} from the context menu.
*Start up Git Extensions.
:**Enter {{Tt|svn://www.renegadeprojects.com/Ares/trunk}} as the {{Tt|Repository}} address.
**Open up Clone Github repository.
:**Leave the other options as they are, and press {{Tt|OK}}.
**Search out Ares on the Search for repositories tab, take the one which is owned by the Ares-Developers, and select your destination folder.
**Leave the other options as they are, and press Clone.


{{HorizontalBar|{{I}}The source code in the repository is updated often with changes and bugfixes. Make sure to compile all your code against the latest version of the SVN code. <br>The {{Tt|SVN Update}} context menu option will update your local copy.}}
{{BigHorizontalBar|'''Git update'''|The source code in the repository is updated often with changes and bugfixes. Make sure to compile all your code against the latest version of the Git code. <br>Use the pull option to make updates visible and merge/fast-forward option to update your local copy.|image=Cc documentinfo.png|width=32px}}


== Code Layout ==
== Code Layout ==
The files in the {{tt|yrpp}} folder are parts of the wrapper library. The Ares code is in the {{Tt|Ares}} folder. There are other repositories for other DLLs using {{tt|yrpp}} - {{Tt|ExceptChecker}} contains the code for the current ExceptChecker DLL. The {{tt|yrpp}}/{{Tt|Examples}} folder contains some examples of using the more complex functionality in {{tt|yrpp}}.  
The files in the {{tt|yrpp}} folder are parts of the wrapper library. Ares' code is in the {{Tt|Ares}} folder. There are other repositories for other DLLs using {{tt|yrpp}} - {{Tt|ExceptChecker}} contains the code for the current YR Development Environment (formerly known as ExceptChecker) DLL. The {{tt|yrpp}}/{{Tt|Examples}} folder contains some examples of using the more complex functionality in {{tt|yrpp}}.  


Your new code should go in the {{Tt|Ares}} folder, the YRPP folder should not be modified without approval.
Your new code should go in the {{Tt|Ares}} folder, the YRPP folder should not be modified without approval.
Line 52: Line 52:
=== An Example ===
=== An Example ===


Here's a sample callback. It fixes a comparatively simple bug - that units firing {{TTL|Temporal|yes}} warheads get experience from erasing friendly units ([http://bugs.renegadeprojects.com/view.php?id=379 bug report], [http://svn.renegadeprojects.com/filedetails.php?repname=Ares&path=%2Ftrunk%2FBugfixes.cpp Actual code as used in Ares] (may differ from shown below)).
Here's a sample callback. It fixes a comparatively simple bug - that units firing {{f|Temporal|yes|link}} warheads get experience from erasing friendly units ([http://bugs.renegadeprojects.com/view.php?id=379 bug report], [http://svn.renegadeprojects.com/filedetails.php?repname=Ares&path=%2Ftrunk%2FMisc%2FBugfixes.cpp Actual code as used in Ares] (may differ from shown below)).


Bits marked with '''(ASM knowledge)''' you are not required to know, the asm hackers can explain that part.  
Bits marked with '''(ASM knowledge)''' you are not required to know, the ASM hackers can explain that part.  


  // ''bugfix #379: Temporal friendly kills give veterancy''
  // ''bugfix #379: Temporal friendly kills give veterancy''
Line 60: Line 60:
  DEFINE_HOOK(71A92A, _Temporal_AvoidFriendlies, 5)
  DEFINE_HOOK(71A92A, _Temporal_AvoidFriendlies, 5)
  {
  {
   ''// '''(ASM knowledge)''' the ESI register contains a pointer to an instance of TemporalClass, let's get it''
   ''// '''(ASM knowledge)''' the ESI register contains a pointer to an instance of TemporalClass, so let's get it''
   GET(TemporalClass *, Temp, ESI);  
   GET(TemporalClass *, Temp, ESI);  
   
   
   ''// House that owns the unit firing this weapon''
   ''// House that owns the unit firing this weapon''
   HouseClass *hv = Temp->get_Target()->get_Owner();
   HouseClass *hv = Temp->Target->Owner;
   ''// House that owns the unit being erased''
   ''// House that owns the unit being erased''
   HouseClass *ho = Temp->get_Owner()->get_Owner();
   HouseClass *ho = Temp->Owner->Owner;
   
   
   ''// proceed normally unless the two houses are allied with each other''
   ''// proceed normally unless the two houses are allied with each other''
   RET_UNLESS(ho->IsAlliedWith(hv));
   return ho->IsAlliedWith(hv) ? 0x71A97D : 0;
  return 0x71A97D;
  }
  }


Line 90: Line 88:
That's all. Now, running YR via Syringe will invoke that functionality and prevent units from gaining experience this way.
That's all. Now, running YR via Syringe will invoke that functionality and prevent units from gaining experience this way.


=== INJGEN ===
=== .inj generation ===
(If you paid attention, you will have noticed that that's the same address/length that was used in DEFINE_HOOK up above. We have a tool named INJGEN, coded up by one of our developers, to automatically generate this {{tt|.inj}} file from the .cpp records so you don't have to add it manually.
If you've paid attention, you will have noticed that we used same address/length that was specified in the {{tt|DEFINE_HOOK}} up above. This is done automatically by our custom build tool. See next paragraph.


== Appendix A: Setting up the Build Environment ==
== Appendix A: Setting up the Build Environment ==
The easiest way to set it up is to use Visual Studio's Project/Solution manager. But some of us prefer manual control over smaller details, so we have a [http://svn.renegadeprojects.com/filedetails.php?repname=Ares&path=%2Freleases%2Fares-msvc.win makefile] for GNU Make which can be used to compile Ares from the command line. This includes the INJGEN step, which you need to do differently if you're using Visual Studio, and the [http://svn.renegadeprojects.com/filedetails.php?repname=Ares&path=%2Freleases%2Fver.rc version resource file].
At the moment, the Visual Studio IDE cannot compile/link Ares correctly. This is due to the fact that it has no config option to generate a custom .obj name based on its relative path from the Ares source root folder. The project contains multiple files with the same name (Ext/WarheadType/Hooks.cpp and Ext/WeaponType/Hooks.cpp, for example) and Visual Studio either manages to overwrite the first one's .obj with the second one, or to muck up the paths completely and fail to link them.
 
To solve this, we use a custom application that invokes the MSVC compiler, resource compiler, linker and builds the .inj file as needed. This was originally coded by pd, and later improved on by DCoder and Alex. It's written in C# and is in the {{Tt|svn://www.renegadeprojects.com/aresbuilder}} repository, you'll need C# Express to build it.
 
Once it's ready, you'll need to set the paths. Most of those are self explanatory, except for the last one, "Output path". It should obviously point to the folder where you want the Ares dll and inj to appear, but there's a catch. The parent of this folder should contain a "debug" folder. (This is because I usually build in the releases/unstable/binary folder and copy it to the YR folder, and this way the debug symbols are created where they should be.)
 
=== Compiler options ===
/Ox /W4 %INCLUDES% /wd4100 /wd4731 /wd4740 /DWIN32 /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS /DNOMINMAX /EHsc /Gz /Zp8  /Gm /Zi /GS- /nologo /we4035 /we4715 /c %IN% /Fo%OUT%
 
''Note'': {{tt|/DNOMINMAX}} should only be applied when compiling Ares revisions >= 754. In earlier ones it will fail to compile.
 
=== Library manager options ===
%IN% /OUT:%OUT%
 
=== Resource compiler options ===
%INCLUDES% /v /fo %OUT% %IN%
 
=== Linker options ===
/MANIFEST:NO /DLL %LIBPATHS% %IN% /SUBSYSTEM:WINDOWS /DEFAULTLIB:"user32.lib" "dbghelp.lib" "ole32.lib" /IMPLIB:%YRPPLIB% /OUT:%OUT%
Add {{Tt|/DEBUG /PDB:"path"}} if you want the debug symbols to be generated as well.
 
If linking fails due to the unresolved external symbol _MiniDumpWriteDump@28, simply add DBGHELP.LIB to the list of linked files.
 
=== Building manually ===
{{Discussed|http://bit.ly/renprojchat}}
==== Workflow ====
* Compile YRPP's StaticInits.cpp as a static library.
* Compile all Ares's .cpp files into .obj.
* Compile all Ares's .rc files into .res.
* Link.
* Generate the .inj file somehow (grep is a good option. Syntax is explained above.)
 
[[Category:Ares]]

Latest revision as of 01:15, 25 October 2014

Contributing to Ares is relatively simple, if you know at least the basics of C++:

What you'll need

A knowledge of C++
Yes, you'll need this.
Microsoft's C++ compiler
Right now, only Microsoft Visual Studio is supported. Due to binary layout issues, gcc-based compilers/IDEs like Dev-C++/WxDev-C++ can not be used to create useful DLLs. If you want a free solution, try Microsoft Visual C++ 2013 Express Edition (recently we started employing C++0x features like lambda and auto, so it won't compile with the earlier versions).
The Microsoft Visual C++ 2013 Redistributables
You can't run Syringe without these. Installing the compiler from the previous step should provide these.
The Microsoft Windows SDK
The Microsoft Windows SDK is required to contribute to and compile Ares. Microsoft Visual Studio (Express Edition) comes with it, but if you don't have it, you can freely download it from Microsoft's site, provided you have a legit copy of Windows.
A Git client
GitExtensions is recommended.

Getting the code

The code consists of two parts:

yrpp
the wrapper library enabling the use of most ingame functionality through plain C++
Ares itself
the code for Ares itself, the functionality that is actually utilised

Each of them has its own Git repository:

  • Create a folder on your hard drive where you'll be keeping the code, for example, C:\My Documents\Visual Studio Projects\Ares or F:\source\Ares, whatever suits you.
  • Create two subfolders in it, one for yrpp and one for Ares.
yrpp
  • Start up Git Extensions.
    • Open up Clone Github repository.
    • Search out YRpp on the Search for repositories tab, take the one which is owned by the Ares-Developers, and select your destination folder.
    • Leave the other options as they are, and press Clone.
Ares
  • Start up Git Extensions.
    • Open up Clone Github repository.
    • Search out Ares on the Search for repositories tab, take the one which is owned by the Ares-Developers, and select your destination folder.
    • Leave the other options as they are, and press Clone.
Git update
The source code in the repository is updated often with changes and bugfixes. Make sure to compile all your code against the latest version of the Git code.
Use the pull option to make updates visible and merge/fast-forward option to update your local copy.


Code Layout

The files in the yrpp folder are parts of the wrapper library. Ares' code is in the Ares folder. There are other repositories for other DLLs using yrpp - ExceptChecker contains the code for the current YR Development Environment (formerly known as ExceptChecker) DLL. The yrpp/Examples folder contains some examples of using the more complex functionality in yrpp.

Your new code should go in the Ares folder, the YRPP folder should not be modified without approval.

Also, take the time to at least skim over the existing code, including the wrapper library - knowing what is possible already and how is always good.

Writing A Function

All functionality in Ares is implemented as callback functions - when the game hits a certain location in the original code, some Ares function is invoked. To make your function invokable at a certain point, you'll need to assign your function as one of the predefined callbacks or use the Syringe Injection Control File to define that.

Any serious modification will normally require more than one callback.

Currently, callback functions are usually declared like this:

DEFINE_HOOK(address, Functionality_FunctionName, length) {
 // actual code
}

What the actual code does is naturally up to you, but usually you'll need to pull a pointer to one of the game classes from one of the CPU registers. This sort of information is very location-/context-specific, and as such you'll need information from the people familiar with the reverse-engineered ASM view of the code (as it is now, pd, jonwil, VK, DCoder and TSHyper). What the actual game classes do is documented in the wrapper library, look at its header files and the existing code snippets.

An Example

Here's a sample callback. It fixes a comparatively simple bug - that units firing Temporal=yes warheads get experience from erasing friendly units (bug report, Actual code as used in Ares (may differ from shown below)).

Bits marked with (ASM knowledge) you are not required to know, the ASM hackers can explain that part.

// bugfix #379: Temporal friendly kills give veterancy
          //(ASM knowledge) - address and length
DEFINE_HOOK(71A92A, _Temporal_AvoidFriendlies, 5)
{
 // (ASM knowledge) the ESI register contains a pointer to an instance of TemporalClass, so let's get it
 GET(TemporalClass *, Temp, ESI); 

 // House that owns the unit firing this weapon
 HouseClass *hv = Temp->Target->Owner;
 // House that owns the unit being erased
 HouseClass *ho = Temp->Owner->Owner;

 // proceed normally unless the two houses are allied with each other
 return ho->IsAlliedWith(hv) ? 0x71A97D : 0;
}

Compiling that code to a DLL and placing it in the game directory will give you this functionality...

... almost, there's one more step to do.

Registering the DLL/function with Syringe

To tell Syringe when to invoke the "_Temporal_AvoidFriendlies" function, you just need to create one extra file:

Let's say you called the DLL with that function temporal.dll. Now you need to create a plain text file called temporal.dll.inj in the same directory as the DLL is, and place the following line into it:

71A92A = _Temporal_AvoidFriendlies, 5

That's all. Now, running YR via Syringe will invoke that functionality and prevent units from gaining experience this way.

.inj generation

If you've paid attention, you will have noticed that we used same address/length that was specified in the DEFINE_HOOK up above. This is done automatically by our custom build tool. See next paragraph.

Appendix A: Setting up the Build Environment

At the moment, the Visual Studio IDE cannot compile/link Ares correctly. This is due to the fact that it has no config option to generate a custom .obj name based on its relative path from the Ares source root folder. The project contains multiple files with the same name (Ext/WarheadType/Hooks.cpp and Ext/WeaponType/Hooks.cpp, for example) and Visual Studio either manages to overwrite the first one's .obj with the second one, or to muck up the paths completely and fail to link them.

To solve this, we use a custom application that invokes the MSVC compiler, resource compiler, linker and builds the .inj file as needed. This was originally coded by pd, and later improved on by DCoder and Alex. It's written in C# and is in the svn://www.renegadeprojects.com/aresbuilder repository, you'll need C# Express to build it.

Once it's ready, you'll need to set the paths. Most of those are self explanatory, except for the last one, "Output path". It should obviously point to the folder where you want the Ares dll and inj to appear, but there's a catch. The parent of this folder should contain a "debug" folder. (This is because I usually build in the releases/unstable/binary folder and copy it to the YR folder, and this way the debug symbols are created where they should be.)

Compiler options

/Ox /W4 %INCLUDES% /wd4100 /wd4731 /wd4740 /DWIN32 /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS /DNOMINMAX /EHsc /Gz /Zp8  /Gm /Zi /GS- /nologo /we4035 /we4715 /c %IN% /Fo%OUT%

Note: /DNOMINMAX should only be applied when compiling Ares revisions >= 754. In earlier ones it will fail to compile.

Library manager options

%IN% /OUT:%OUT%

Resource compiler options

%INCLUDES% /v /fo %OUT% %IN%

Linker options

/MANIFEST:NO /DLL %LIBPATHS% %IN% /SUBSYSTEM:WINDOWS /DEFAULTLIB:"user32.lib" "dbghelp.lib" "ole32.lib" /IMPLIB:%YRPPLIB% /OUT:%OUT%

Add /DEBUG /PDB:"path" if you want the debug symbols to be generated as well.

If linking fails due to the unresolved external symbol _MiniDumpWriteDump@28, simply add DBGHELP.LIB to the list of linked files.

Building manually

Work in Progress
This page is the result of a currently running discussion. The information on it is subject to change. If you wish to follow the discussion or want to know more about the history of this page, please follow this link.

Workflow

  • Compile YRPP's StaticInits.cpp as a static library.
  • Compile all Ares's .cpp files into .obj.
  • Compile all Ares's .rc files into .res.
  • Link.
  • Generate the .inj file somehow (grep is a good option. Syntax is explained above.)