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

Difference between revisions of "Contributing to Ares"

From ModEnc
Jump to: navigation, search
m (Correcting SVN repos URL)
(Updating again)
Line 7: Line 7:
 
== 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, [http://en.wikipedia.org/wiki/Microsoft_Visual_Studio Microsoft Visual Studio] and [http://www.bloodshed.net/devcpp.html Dev-C++]/[http://wxdsgn.sourceforge.net/ WxDev-C++] (gcc-based) are supported.
+
; A C++ compiler/IDE : Right now, [http://en.wikipedia.org/wiki/Microsoft_Visual_Studio Microsoft Visual Studio] <span style="text-decoration: line-through;">and [http://www.bloodshed.net/devcpp.html Dev-C++]/[http://wxdsgn.sourceforge.net/ WxDev-C++] (gcc-based) are</span> is supported.
 
; A Subversion (SVN) client : [http://tortoisesvn.tigris.org/ TortoiseSVN] is recommended.
 
; A Subversion (SVN) client : [http://tortoisesvn.tigris.org/ TortoiseSVN] is recommended.
  
Line 15: Line 15:
 
; 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
  
At the time of writing, they're both bundled in the same SVN repository:
+
Each of them has its own SVN 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.  
*Right click said folder, and select {{Tt|SVN Checkout...}} from the context menu.
+
*Create two subfolders in it, one for yrpp and one for Ares.
**Enter {{Tt|svn://www.renegadeprojects.com/yrpp/trunk}} as the {{Tt|Repository}} address.
+
 
**Leave the other options as they are, and press {{Tt|OK}}.
+
; {{tt|yrpp}}
 +
::*Right click yrpp's folder, and select {{Tt|SVN Checkout...}} from the context menu.
 +
::**Enter {{Tt|svn://www.renegadeprojects.com/yrpp/trunk}} as the {{Tt|Repository}} address.
 +
::**Leave the other options as they are, and press {{Tt|OK}}.
 +
 
 +
; Ares:
 +
:*Right click Ares's folder, and select {{Tt|SVN Checkout...}} from the context menu.
 +
:**Enter {{Tt|svn://www.renegadeprojects.com/Ares/trunk}} as the {{Tt|Repository}} address.
 +
:**Leave the other options as they are, and press {{Tt|OK}}.
  
 
{{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.}}
 
{{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.}}
  
 
== Code Layout ==
 
== Code Layout ==
The files directly in the folder are parts of the wrapper library. The Ares code is in the {{Tt|Ares}} subfolder. There are also other folders in the hierarchy, {{Tt|ExceptChecker}} contains the code for the current ExceptChecker DLL , and {{Tt|Examples}} 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. 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}}.  
  
Assuming you're familiar with C++, you should create a new {{tt|.cpp}} file in the {{Tt|Ares}} folder (copy the source code from {{Tt|fix_temporal/fix_temporal.cpp}} until a proper skeleton is set up).
+
Assuming you're familiar with C++, you should create a new {{tt|.cpp}} file in the {{Tt|Ares}} folder.
  
 
Also, take the time to at least gloss over the existing code, including the wrapper library - knowing what is possible already and how is always good.
 
Also, take the time to at least gloss over the existing code, including the wrapper library - knowing what is possible already and how is always good.
Line 37: Line 45:
 
Currently, callback functions are usually declared like this:
 
Currently, callback functions are usually declared like this:
 
  ''//hook at 0xDEADBEEF''
 
  ''//hook at 0xDEADBEEF''
  EXPORT Functionality_FunctionName(REGISTERS *R) {
+
  EXPORT_FUNC(Functionality_FunctionName) {
 
   ''// actual code''
 
   ''// actual code''
 
  }
 
  }
Line 45: Line 53:
 
=== 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.
+
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)).
  
 
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.  
Line 56: Line 64:
 
  #define _CRT_NON_CONFORMING_SWPRINTFS
 
  #define _CRT_NON_CONFORMING_SWPRINTFS
 
  #endif
 
  #endif
#pragma warning(disable: 4035) //"no return value" - there is one, just not in our code ;)
 
 
''// standard C++ headers''
 
#include <stdio.h>
 
 
   
 
   
 
  ''// YR++ library''
 
  ''// YR++ library''
Line 67: Line 71:
 
   
 
   
 
  //hook at 0x71A92A
 
  //hook at 0x71A92A
  EXPORT _Temporal_AvoidFriendlies(REGISTERS *R) {
+
  EXPORT_FUNC(_Temporal_AvoidFriendlies) {
 
  ''// '''(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, let's get it''
 
  TemporalClass *m = (TemporalClass *)R->GetESI();  
 
  TemporalClass *m = (TemporalClass *)R->GetESI();  
Line 77: Line 81:
 
  HouseClass *ho = m->get_OwningUnit()->get_Owner();
 
  HouseClass *ho = m->get_OwningUnit()->get_Owner();
 
   
 
   
  ''// if the two houses aren't allied with each other, there's nothing to fix''
+
  ''// if the two houses are allied with each other,''
  if(!ho->IsAlliedWith(hv)) {
+
''// '''(ASM knowledge)''' force the game to jump over the experience-granting code''
  return 0;
+
  if(ho->IsAlliedWith(hv)) {
 +
  return 0x71A97D;
 
  }
 
  }
 
   
 
   
  ''// '''(ASM knowledge)''' force the game to jump over the experience-granting code''
+
  ''// '''(ASM knowledge)''' else there's nothing to fix''
  return 0x71A97D;
+
  return 0;
 
  }
 
  }
  
Line 101: Line 106:
  
 
That's all. Now, running YR via Syringe will invoke that functionality and prevent the units from gaining experience this way.
 
That's all. Now, running YR via Syringe will invoke that functionality and prevent the units from gaining experience this way.
 
== Compiler Specifics ==
 
=== gcc/MinGW (Dev-C++ and wxDev-C++) ===
 
If you're using gcc, you'll need to add an extra option to the C++ Compiler Options (Project Options -> Parameters -> C++ Compiler):
 
-masm=intel
 
 
Otherwise the compiler will spit out error messages and compilation will stop.
 

Revision as of 18:32, 21 August 2008

Warning small.pngThis is relatively unpolished. As the wrapper library and the project matures, simpler ways to create custom code will be created. Don't panic.

Warning small.pngAt this moment, you will not be able to run the DLLs you compiled - the sources in SVN have been updated to work with a more recent, development-version of Syringe which is not publicly vailable just yet. Don't try runnning them on the old public version.

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.
A C++ compiler/IDE 
Right now, Microsoft Visual Studio and Dev-C++/WxDev-C++ (gcc-based) are is supported.
A Subversion (SVN) client 
TortoiseSVN 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 SVN 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
Ares
Cc documentinfo.pngThe 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.
The SVN Update context menu option will update your local copy.

Code Layout

The files in the yrpp folder are parts of the wrapper library. The Ares code is in the Ares folder. There are other repositories for other DLLs using yrpp - ExceptChecker contains the code for the current ExceptChecker DLL. The yrpp/Examples folder contains some examples of using the more complex functionality in yrpp.

Assuming you're familiar with C++, you should create a new .cpp file in the Ares folder.

Also, take the time to at least gloss 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, for now multiple callbacks cannot be registered at one location.

Currently, callback functions are usually declared like this:

//hook at 0xDEADBEEF
EXPORT_FUNC(Functionality_FunctionName) {
 // 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 Template:TTL 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.

// keep this part in
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NON_CONFORMING_SWPRINTFS
#define _CRT_NON_CONFORMING_SWPRINTFS
#endif

// YR++ library
#include <YRPP.h>

// the actual function 

//hook at 0x71A92A
EXPORT_FUNC(_Temporal_AvoidFriendlies) {
	// (ASM knowledge) the ESI register contains a pointer to an instance of TemporalClass, let's get it
	TemporalClass *m = (TemporalClass *)R->GetESI(); 

	// House that owns the unit firing this weapon
	HouseClass *hv = m->get_TargetUnit()->get_Owner();

	// House that owns the unit being erased
	HouseClass *ho = m->get_OwningUnit()->get_Owner();

	// if the two houses are allied with each other,
	// (ASM knowledge) force the game to jump over the experience-granting code
	if(ho->IsAlliedWith(hv)) {
		return 0x71A97D;
	}

	// (ASM knowledge) else there's nothing to fix
	return 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 the units from gaining experience this way.