C# AI Interface, and Proof of concept C# AI - Page 2

C# AI Interface, and Proof of concept C# AI

Here is where ideas can be collected for the skirmish AI in development

Moderators: hoijui, Moderators

User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Post by jcnossen »

I wrote an example to demonstrate mono_delegate_to_ftnptr:

http://user.supradigital.org/jcnossen/M ... edTest.zip

Test.exe inside passes "d:/sdks/mono-1.1.18/lib" to mono_set_dirs by default. You can pass the correct path to it through the commandline like:

Code: Select all

test c:/Mono-1.1.18/lib
bamb
Posts: 350
Joined: 04 Apr 2006, 14:20

Post by bamb »

So, I have to download this 23 meg package from microsoft to run it? Seems rather big.
User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Post by jcnossen »

You have to download that sometime anyway... microsoft itself will probably start using it as well for other apps.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

jcnossen wrote:I wrote an example to demonstrate mono_delegate_to_ftnptr:

http://user.supradigital.org/jcnossen/M ... edTest.zip

Test.exe inside passes "d:/sdks/mono-1.1.18/lib" to mono_set_dirs by default. You can pass the correct path to it through the commandline like:

Code: Select all

test c:/Mono-1.1.18/lib
Ok, interesting.

Running that on this computer gives a message "mono-1.dll not found".

test.exe is being run as:

Code: Select all

test H:\bin\Mono-1.1.18\lib
User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Post by jcnossen »

I accidentally had multiple mono versions on my pc, one of which had a mono-1.dll

I discovered again how to build .lib files from a dll:

- Run impdef to create a .def file from the dll

Code: Select all

impdef.exe mono.dll
- Make sure visual studio tools are in PATH (lib.exe is part of visual studio), and run

Code: Select all

lib /out:mono.lib /def:mono.def
http://user.supradigital.org/jcnossen/M ... edTest.zip contains updated files now...
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Ok, that works.

Question: do you know how to marshall a string from Mono into C++?

Example:

From Mono ,sending "Hello world". In C++, either in text file output or via Spring, the output is "?m"

In C++:

Code: Select all

void SendTextMsg( const char *message, int priority )
{
   WriteStringToFile( message );
   aicallback->SendTextMsg( message, priority );
}
In Mono,

Code: Select all

[MethodImpl(MethodImplOptions.InternalCall )]
 public extern static void SendTextMsg( [MarshalAs(UnmanagedType.LPStr)]string message, int priority );

Code: Select all

SendTextMsg( "Hello world", 0 );
Compiler options used: /EHsc /GR /D_WIN32_WINNT=0x0500 /D "WIN32" /D "_WINDOWS" /MD (basically nothing special, nothing about unicode)
User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Post by jcnossen »

Marshalling isn't used on internal calls, this is what mono uses internally so you get MonoObject* parameters for everything that is an object. (MonoObject maps to System.Object)

mono_string_to_utf8 comment in metadata/object.c:

Code: Select all

/**
 * mono_string_to_utf8:
 * @s: a System.String
 *
 * Return the UTF8 representation for @s.
 * the resulting buffer nedds to be freed with g_free().
 */
So that results in:

Code: Select all

void SendTextMsg( MonoString* strobj, int priority ) 
{ 
  char *msg = mono_string_to_utf8(strobj);
   WriteStringToFile( msg ); 
   aicallback->SendTextMsg(msg, priority ); 
  g_free(msg);
}
however for g_free you will need to link to mono/lib/glib-2.0.lib,fortunately they provided a .lib for that already.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Post by AF »

So, I have to download this 23 meg package from microsoft to run it? Seems rather big.
Vista has it integrated, its also on the supcom CD/beta download (The supcom autorun program is C#/VB.Net, possibly the GPG Net client too), you'll also need it for OSRTS.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

jcnossen wrote:Marshalling isn't used on internal calls, this is what mono uses internally so you get MonoObject* parameters for everything that is an object. (MonoObject maps to System.Object)

mono_string_to_utf8 comment in metadata/object.c:

Code: Select all

/**
 * mono_string_to_utf8:
 * @s: a System.String
 *
 * Return the UTF8 representation for @s.
 * the resulting buffer nedds to be freed with g_free().
 */
So that results in:

Code: Select all

void SendTextMsg( MonoString* strobj, int priority ) 
{ 
  char *msg = mono_string_to_utf8(strobj);
   WriteStringToFile( msg ); 
   aicallback->SendTextMsg(msg, priority ); 
  g_free(msg);
}
however for g_free you will need to link to mono/lib/glib-2.0.lib,fortunately they provided a .lib for that already.
Good thing I asked; I'd have taken weeks to figure that out by myself.

Started looking at passing objects to and fro, by value. This is probably needed for Commands and Float3s?

Passing from cs to cpp works ok, but cpp to cs isn't quite right at the moment.

TestClass:

Code: Select all

namespace AILauncher
{
    class TestClass
    {
        public:
            int x;
            int y;
    };
};
using namespace AILauncher;
cs to cpp, cpp code (works)

Code: Select all

TestClass *MonoObjectToTestClass( MonoObject *incomingobject )
{
    TestClass *myobject = new TestClass();
    
    MonoClass*thisclass = mono_object_get_class(incomingobject);
    mono_field_get_value (incomingobject, mono_class_get_field_from_name (thisclass, "x"), &(myobject->x ) );
    mono_field_get_value (incomingobject, mono_class_get_field_from_name (thisclass, "y"), &(myobject->y ) );
    
    return myobject;
}

// called from cs to send a TestClass object to cpp
void SendObject( MonoObject *incomingobject )
{
    TestClass *myobject = MonoObjectToTestClass( incomingobject );
    cout << "x: " << myobject->x << " y " << myobject->y << endl;
    delete myobject;
}
cpp to cs, cpp code (doesnt work)

Code: Select all

MonoObject *TestClassToMonoObject( TestClass *testobject )
{
	MonoClass *monoclass = mono_class_from_name( image, "AILauncher", "TestClass" );
	MonoObject *monoobject = mono_object_new ( domain, monoclass );
	mono_runtime_object_init( monoobject );
    
    mono_field_set_value (monoobject, mono_class_get_field_from_name (monoclass, "x"), &(testobject->x) );
    mono_field_set_value (monoobject, mono_class_get_field_from_name (monoclass, "y"), &(testobject->y) );
    
    return monoobject;
}

// called from cs to obtain a TestClass object with x = 12; y = 235
MonoObject *GetTestClass()
{
    TestClass *someobject = new TestClass();
    someobject->x = 12; someobject->y = 235;
    MonoObject *monoobject = TestClassToMonoObject( someobject );
    delete someobject;
    return monoobject;
}
Any ideas?
User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Post by jcnossen »

I'm not sure why this doesn't work, it might be that the TestClass is initialized but not constructed...

If it's just for Command and float3, it's probably easier to pass these unpacked through the parameters, so you don't have to deal with all the structures. For Command, float[] can be handled with the mono unmanaged api as well (see array functions in object.h I think).
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Ok, your saying it looked ok gave me the confidence to check other things and realize that actually the issue was elsewhere.
User avatar
MadRat
Posts: 532
Joined: 24 Oct 2006, 13:45

Post by MadRat »

I hate to interupt your development, but I noticed that this ai dll crashes alot on maps with a central obstacle, like plains and passes and the painted desert remake. The ai didn't last more than three minutes on either map.
Chojin
Posts: 141
Joined: 04 Oct 2006, 11:22

Post by Chojin »

What error did you get?
User avatar
MadRat
Posts: 532
Joined: 24 Oct 2006, 13:45

Post by MadRat »

Something about a global ai.dll caused an exception.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

Introduction
========

Creating the mono bindings is non-trivial and I'm going to concentrate on building the AI itself. For the case that someone else would like to take over writing bindings for Mono, here are some thoughts and code.

To create bindings for Mono, we almost certainly need a generator. The hardest part of writing a generator is parsing the input files. In the case of the Mono bindings, we can use Reflection on the existing CSAIInterfaces.dll. This could save a lot of time.

Download
======

Code written so far:
*prototyping code and generator: modified MonoEmbeddedTest at http://manageddreams.com/csai/MonoEmbeddedTest.zip
*C# AI "Hello World" for Mono: http://manageddreams.com/csai/CSharpAIMono.zip Note that you will need to ensure that Mono-1.1.18/bin is in Spring.exe's path.

A generator has been started in the file "GenerateCode.cs" in the MonoEmbeddedTest.zip zipfile. You can build it by doing:

csc /debug GenerateCode.cs /reference:CSAIInterfaces.dll

Architecture
========

There are three types of classes we need to deal with:
*data classes, pass-by-value. This includes: Command, Float3
*proxied method calls from C++ to C#. This includes: IGlobalAI
*proxied method calls from C# to C++. This includes: IUnitDef, IAICallback

Pass-by-value
=========

We create a class in C++ for each pass-by-value class, with static methods "Marshall_MyType_to_MonoObject" and "Marshall_MonoObject_to_MyType"

The generator does this already, although it needs tweaking to cope with the double array in Command.

Two files are created for each type: MyTypeMarshaller.cpp and MyTypeMarshaller.h

We include the include file for the original Spring native type from MyTypeMarshaller.h, eg Float3Marshaller.h includes Float3.h.

Proxied method calls from C++ to C#
========================

There is only one class that this applies to, IGlobalAI.

We create a C# class GlobalAIProxyLoader, which contains delegate definitions for each method in IGlobalAI, and which calls SetUnitCreatedHandler etc on the C++ proxy class

We create a C++ class GlobalAIProxyCppToCs , which contains a function to receive each delegate from the C# ProxyLoader. It implements each function in IGlobalAI, redirecting to a user-provided GlobalAI C# class.

We strip the leading "I" from the interface name to get the underlying type name.

Proxied method calls from C# to C++
========================

This applies to: IUnitDef, and IAICallback.

The native instances of these classes are always created by Spring itself, then passed back to the AI. We need to provide a C# proxy to wrap calls to a C++ proxy, which forwards the calls to the native instance.

Two classes called MyTypeCallbackProxyCsToCpp are created, one in C# one in C++.

The MyTypeCallbackProxyCsToCpp class in C# contains instance methods, such as SendTextMsg, which redirect to static methods, such as _SendTextMsg. The static methods are extern'd internal calls to methods with the same name in the MyTypeCallbackProxyCsToCpp class in C++.

In the general case, there can be many instances of each of these proxied classes, so we create a map of reference number to instance in the C++ proxy. The reference number is an arbitrary number starting from 1.

Each time a function on the Spring side returns a class that needs to be proxied into C#, we create a new reference number and add it to the map. The reference number is returned into the C#-side proxy, and will be used as a handle for method calls in the future.

The C#-side proxy that called the spring function that returned the new proxied class will receive the new handle from the C++-side proxy, and create a new instance of the appropriate proxy class, passing in the new handle in the constructor. It can then pass the new proxy class instance onto the C# AI.

The method calls from C# into C++ contain an additional first parameter, which is the reference number , which allows the C++-side proxy to select the appropriate native object and forward the call, eg to a UnitDef object. The instance methods in the C#-side proxy class will add the additional handle parameter when they call the corresponding static method.

The method calls in the C++ proxy are static, so they can be internal-called from C#, and in a class, to avoid namespace collisions.

Generator main block
==============

The generator main block can add each of the types to be generated into an arraylist TypesByVal, ProxiesCppToCs or ProxiesCsToCpp, as appropriate. Then when we call generate:
*it goes through each arraylist and generates the appropriate classes
*when a class undergoing generation uses one of the other classes, the generator can handle this accordingly by checking which arraylist the other classes are in

Use of attributes
==========

It's possible to add custom attributes to parameters and methods in the interface classes in CSAIInterfaces.dll . These can be read by the generator and used to tweak the generation.

For example, we could have [MarshallAsCNullTerminatedString] vs [MarshallAsCppStdString].

An attribute is just an empty class that derives from Attribute, eg:

Code: Select all

[AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = true)]
public class MarshallAsCNullTerminatedString: Attribute
{
   // nothing needed here, empty class
}
Use of attributes should probably be kept to a minimum, to avoid modifying CSAIInterfaces.dll, but the possibility exists where necessary.

Hand-Tweaked Code
=============

It will almost certainly be necessary to add hand-tweaked code to the proxies. For example, GetMetalMap() cannot be easily guessed, because there is no info on the size of the array, and it's not constant either.

Hand-tweaked code could be added by creating a derived class, in C++, from the proxy class one wishes to tweak. This keeps generated code separate from human-written code, so it is easy to regenerate the files as the interfaces change.

The generator will need to know the name of any derived classes so that it can use this in any "new" statements it generates for that proxy.

Overall
=====

A plan exists that should probably work. Some code has been written. The devil is in the details.

Writing the Mono bindings will need someone with a good knowledge of the Mono API, Spring AIs, C, C++ and C#.
Last edited by hughperkins on 28 Oct 2006, 10:27, edited 1 time in total.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

MadRat wrote:I hate to interupt your development, but I noticed that this ai dll crashes alot on maps with a central obstacle, like plains and passes and the painted desert remake. The ai didn't last more than three minutes on either map.
MadRat,

There is a memory corruption issue that applies to all current released versions of the C++/C# interface. Could you download a new version of csailoader.dll from http://manageddreams.com/utils/csailoader.dll , overwrite the version currently in AI/Bot-libs, and see if the problem still exists?

Also, if it crashes again, could you send the logfile from the AI/CSAI directory to me at hughperkins@gmail.com ?

How many units exist roughly at the time of the crash?

Are there any other AIs running at the same time?
silv
Posts: 30
Joined: 25 May 2006, 07:24

Post by silv »

csai (newsest and 25th of october version, also the new loader dll) crashes for me instantly on 73b1 / aa 2.23 after the 3 sec countdown on smalldivide and core_faf (didnt try other maps). it doesn't create any logs, the error is an unhandled exception in globalai dll or something like that. i installed .net 1.1 (on win 2k) (didn't reboot after, but it didnt require that) and i think i installed the 6 files in the correct directories and also made a copy in the old aidll dir to play with the old ta-singleplayer exe. any ideas / information you need?
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

silp wrote:csai (newsest and 25th of october version, also the new loader dll) crashes for me instantly on 73b1 / aa 2.23 after the 3 sec countdown on smalldivide and core_faf (didnt try other maps). it doesn't create any logs, the error is an unhandled exception in globalai dll or something like that. i installed .net 1.1 (on win 2k) (didn't reboot after, but it didnt require that) and i think i installed the 6 files in the correct directories and also made a copy in the old aidll dir to play with the old ta-singleplayer exe. any ideas / information you need?
silp,

Could you download http://manageddreams.com/csai/CSharpAI-20061028.zip , unzip it, and run setup.exe then try running spring again?
User avatar
MadRat
Posts: 532
Joined: 24 Oct 2006, 13:45

Post by MadRat »

hughperkins wrote: MadRat,
...Could you download a new version of csailoader.dll from http://manageddreams.com/utils/csailoader.dll , overwrite the version currently in AI/Bot-libs, and see if the problem still exists?
Check.
hughperkins wrote: Also, if it crashes again, could you send the logfile from the AI/CSAI directory to me at hughperkins@gmail.com ?
Ditto on the last check. Didn't see that folder there, but I created one for it now.
hughperkins wrote: Are there any other AIs running at the same time?
I've been testing it with two plain jane AA and two CSAI bots, one each running ARM and the other CORE. All are in their own seperate groups. I've tried it in both AA 2.23 and XTA v7 and got the same results.
User avatar
hughperkins
AI Developer
Posts: 836
Joined: 17 Oct 2006, 04:14

Post by hughperkins »

MadRat,

Could you download http://manageddreams.com/csai/CSharpAI-20061028.zip , unzip, run the setup.exe inside, then try again?

> I've been testing it with two plain jane AA and two CSAI bots, one each running ARM and the other CORE. All are in their own seperate groups. I've tried it in both AA 2.23 and XTA v7 and got the same results.

Ok. Could you try it playing CSAI against other CSAIs, and see if it still crashes? Is there any indication of which AI is crashing?

Note that CSAI needs to run as ARM.

On the dev platform, Painted Desert is very laggy, but the AIs, both CSAI and AAI, seem to work ok.
Post Reply

Return to “AI”