AGS Plugin API for C#

Started by smiley, Thu 22/07/2010 15:29:20

Previous topic - Next topic

smiley

Purely proof-of-concept at the moment. Barely anything besides registering new script functions has been tested.

Website

The 'AGSPlugin' class contains the callback methods as described here.

RegisterScriptFunction example:
Declare a method:
Code: ags

private static int AddNumbers(int a, int b)
{
   return a + b;
}

and a matching delegate:
Code: ags

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int AddNumbersDel(int a, int b);

The delegate has to use the UnmanagedFunctionPointer attribute with CallingConvention.Cdecl.

Register the script header in EditorStartup:
Code: ags

public int EditorStartup(IAGSEditor editor)
{
   editor.RegisterScriptHeader("import int AddNumbers(int, int);
");
   return 0;
}

Register the script function in EngineStartup:
Code: ags

private AddNumbersDel del;
public void EngineStartup(IAGSEngine engine)
{
   del = new AddNumbersDel(AddNumbers);
   IntPtr address = Marshal.GetFunctionPointerForDelegate(del);
   engine.RegisterScriptFunction("AddNumbers", address);
}




Calin Leafshade

AGS plugins in C#?

you are a fucking beautiful man and I offer kisses and snuggles in payment.

tzachs

This is brilliant, I wanted to do the same thing but you beat me to it, and I'm happy you did!  :D

As a c# lover and c++ hater, I thank you!

GarageGothic

Wow, that's pretty damn interesting. Still not sure it would be a good idea for me to use XNA because of the iffy licensing, but at least this makes it possible. Would there be any considerable slowdowns in using the wrapper compared to straight C++?

Calin Leafshade

i dont think the XNA library is used.. its just C#

GarageGothic

#5
No, I meant now that C# can be used by plugins, linking to XNA is suddenly an option - one I had previously discarded while searching for appropriate libraries and engines. (Not sure there would be much to gain by using it as an AGS plugin rather than building the entire game in XNA, but I was impressed with some of the 2D capabilities of the framework - including totally neat realtime lighting).

Calin Leafshade

ahh that makes sense.. I didnt think you were that stupid :P

Wonkyth

"But with a ninja on your face, you live longer!"

smiley

New version is up.
-Fixed 'AGS_EditorSaveGame' and wrongly marshalled char pointers.
-Most constants are now enums.
-Most properties are now PascalCased.

Quote from: GarageGothic on Thu 22/07/2010 16:01:19
Would there be any considerable slowdowns in using the wrapper compared to straight C++?
There's a significant overhead involved in calling the AGS API methods.
However, I haven't made any performance tests yet.

Calin Leafshade

this doesn't seem to compile in c# express.

its requests ilasm.exe which i believe is part of the vs tools and so is not part of the express edition.

is there any way to make it compile in express?


Calin Leafshade

ok now i can get it to compile but AGS throws an unresolved import error and i can't see my error.

I pretty much copied your example verbatim so it must be something pretty basic.

smiley

Please try the updated example.
The error might be caused by the delegate getting GCed.

Calin Leafshade

nope same problem,

heres my code for clarity:

Code: ags

namespace AGSPluginSharp
{
    using System;
    using System.Runtime.InteropServices;

    public class AGSPlugin
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate int AddNumbersDel(int a, int b);

        #region Constructors

        public AGSPlugin()
        {
        }

        #endregion Constructors

        #region Properties

        #region Public Properties

        public string Name
        {
            get
            {
                return "C# AGS Plugin";
            }
        }

        #endregion Public Properties

        #endregion Properties

        #region Methods

        #region Public Methods

        public void EditorLoadGame(byte[] buffer)
        {
        }

        public void EditorProperties(IntPtr parentHandle)
        {
        }

        public byte[] EditorSaveGame(int maxBufferSize)
        {
            return new byte[0];
        }

        public void EditorShutdown()
        {
        }

        public int EditorStartup(IAGSEditor editor)
        {
            editor.RegisterScriptHeader("import int AddNumbers(int, int);\r\n");
            return 0;
        }

        public int EngineDebugHook(string scriptName, int lineNum, int reserved)
        {
            return 0;
        }

        public void EngineInitGfx(string driverID, System.IntPtr data)
        {
        }

        public int EngineOnEvent(EventType evnt, int data)
        {
            return 0;
        }

        public void EngineShutdown()
        {
        }

        private AddNumbersDel del;
        public void EngineStartup(IAGSEngine engine)
        {
            del = new AddNumbersDel(AddNumbers);
            IntPtr address = Marshal.GetFunctionPointerForDelegate(del);
            engine.RegisterScriptFunction("AddNumbers", address);
        }

        private static int AddNumbers(int a, int b)
        {
            return a + b;
        }

        #endregion Public Methods

        #endregion Methods

 




    }
}

smiley

Do you have the VC++ 2010 redist installed?
http://www.microsoft.com/downloads/details.aspx?FamilyID=a7b7a05e-6de6-4d3a-a423-37bf0912db84&displaylang=en

Also copy PluginAPIWrapper.dll to the game's "_Debug" folder, or include the AGS editor folder in PATH.

Calin Leafshade

yep i have the redist package and i'd already copied the wrapper over.

smiley

I've uploaded a new version which might fix the problem.

Monsieur OUXX

Calin, did that eventually work?
 

Calin Leafshade

I havent got around to testing it yet.

The plugin i'm working on is coded in C++ since i need it to be fast.

Monsieur OUXX

 

Pumaman

Interesting!

Of course, you need to bear in mind that if you make a game that uses a C# plugin, then the player will need to have the .NET Framework installed in order to play your game.

Wonkyth

Not much of an issue for windows users.
"But with a ninja on your face, you live longer!"

tzachs

Quote from: Monsieur OUXX on Tue 03/08/2010 15:32:38
Calin, did that eventually work?

Works super for me (eventually)   :D
Expect a small demonstration plugin soon...

Yuri Patrick

Alright, back in the original post for this topic is the following:

"Register the script function in EngineStartup:
Code: ags

private AddNumbersDel del;
public void EngineStartup(IAGSEngine engine)
{
   del = new AddNumbersDel(AddNumbers);
   IntPtr address = Marshal.GetFunctionPointerForDelegate(del);
   engine.RegisterScriptFunction("AddNumbers", address);
}



Where in the world is IAGSEngine?! I have AGS Types but IAGSEngine is not in there. Is my AGS broken?

Calin Leafshade

i'm not sure what you mean...

in the code you posted 'engine' is an instance of the IAGSEngine class which is passed from the wrapper.

Yuri Patrick

Yes. I know that, but it is not accepting it. I have VS C# 2008 and am "using AGS.Types;" but when I try to compile with IAGSEngine anywhere in my code, it crashes and says I am missing a directive.

tzachs

Did you use the given template?
It's under Wrapper\Swig\IAGSEngine.cs

smiley

Small update:
The C++ glue code is included in the zip file.
PluginAPIWrapper.dll is compiled with MinGW, so you don't need the VC++ 2010 redist anymore.

goodohman


Hi there,

I'm trying to return a String from a function.

First I just tried to return a C# string - kaboom... it crashed
Then I thought wait.. return a CreateScriptString(mystring) - kaboom...
Then I thought wait... the IAGSEngine and agspluginPINVOKE might be wrong with the return type,
so I've changed them from "string" to "IntPtr" and still - kaboom...
I thought maybe "IntPtr" is not "real" enough as a const char*, so I've changed all to "void*" (in usafe context),
and guess what? yeah... - kaboom

so.. smiley or anybody else.. PLEAAAASSSEEEE does someone knows how to return a string from c# ?

Thanks!!!!!!!!!!!!!!

tzachs

You can take a look at the code I wrote for c# runner (the source code is in that thread), there are some functions there that return a string.

goodohman


Thanks Tzachs!

The C# Runner link appears to be dead, could you repost?
Alternatively, could you give me the short version answer?

Thanks!!

p.s.
any idea on how to access the new ags features from the plugin? (i.e. new audio stuff and attributes)

tzachs

Thanks for the heads up, I re-uploaded it to here.

As for the short version answer, I don't have something special to offer here, cause I don't remember doing anything different for strings that I didn't do for the other types, if was pretty straight forward.
You're probably missing something simple, so I would compare my code to yours and see what's different...

Also, regarding the new audio, my guess is that the API doesn't have that functionality, so no way to access it. However since the source code of the editor is available (and in c#), you can possibly modify it to access the audio somehow, though I'm not sure how much work it will take.

goodohman


tzachs, sorry for the long delay!

Your example is working alright, but the return type is actually derived from using the:

private static TOut CSRun<TIn, TOut>(TIn value, string className)

method (CSRunStringToString...)

Could you PLEASE verify a pure in-code string return type and let me know?

BIG THANKS!

tzachs

The CSRun is only a generic method to run delegates, it's an inner implementation and have no effect of the API, I could have easily replaced that call with a simple:
return "hello world";

This would have worked all the same (guaranteed, this was the first thing I tried when I started playing with smiley's api).

Yuri Patrick

Does anyone still have the C# wrapper? I tried all three of the links that I saw going to the file and they are all dead links. Please someone still have this. :)

Khris

Just send smiley a PM.
He was last active in July, he's still around it seems.

smiley


SMF spam blocked by CleanTalk