<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.fightorder.net/wiki/index.php?action=history&amp;feed=atom&amp;title=AI%3AHughs_global_AI_tutorial</id>
	<title>AI:Hughs global AI tutorial - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.fightorder.net/wiki/index.php?action=history&amp;feed=atom&amp;title=AI%3AHughs_global_AI_tutorial"/>
	<link rel="alternate" type="text/html" href="https://www.fightorder.net/wiki/index.php?title=AI:Hughs_global_AI_tutorial&amp;action=history"/>
	<updated>2026-04-21T05:43:47Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://www.fightorder.net/wiki/index.php?title=AI:Hughs_global_AI_tutorial&amp;diff=1568&amp;oldid=prev</id>
		<title>Qrow: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://www.fightorder.net/wiki/index.php?title=AI:Hughs_global_AI_tutorial&amp;diff=1568&amp;oldid=prev"/>
		<updated>2026-02-24T06:08:38Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 23:08, 23 February 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Qrow</name></author>
	</entry>
	<entry>
		<id>https://www.fightorder.net/wiki/index.php?title=AI:Hughs_global_AI_tutorial&amp;diff=1567&amp;oldid=prev</id>
		<title>interaidev&gt;Flozi: AI -&gt; AI Dev (dead image links :()</title>
		<link rel="alternate" type="text/html" href="https://www.fightorder.net/wiki/index.php?title=AI:Hughs_global_AI_tutorial&amp;diff=1567&amp;oldid=prev"/>
		<updated>2013-03-23T16:44:37Z</updated>

		<summary type="html">&lt;p&gt;AI -&amp;gt; AI Dev (dead image links :()&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;This page goes step by step through how to create your own global AI.&lt;br /&gt;
&lt;br /&gt;
We&amp;#039;ll be writing the AI in C#, because C# is powerful and easy to debug.  You&amp;#039;ll need a Windows platform with Visual C# Express 2005 installed.&lt;br /&gt;
&lt;br /&gt;
Note that the C++/C# interface is made available under the GPL licence, so your AI will need to be available under the GPL licence.&lt;br /&gt;
&lt;br /&gt;
= Setting up your own AI Project =&lt;br /&gt;
&lt;br /&gt;
We&amp;#039;re going to use the C# loader dlls from CSAI.  We&amp;#039;ll get these to run our own AI dll.&lt;br /&gt;
&lt;br /&gt;
*Download CSAI from [[AI:CSAI]], unzip it, and run setup.exe to install it.&lt;br /&gt;
&lt;br /&gt;
In what follows, TASpring in a directory path means the Spring application directory, the one that contains spring.exe.&lt;br /&gt;
&lt;br /&gt;
First, we need to create a loader dll &amp;quot;myailoader.dll&amp;quot;, that will load our AI dll.&lt;br /&gt;
*Copy TASpring\AI\Bot-libs\csailoader.dll to TASpring\AI\Bot-libs\myailoader.dll&lt;br /&gt;
*Copy TASpring\AI\Bot-libs\csailoader.xml to TASpring\AI\Bot-libs\myailoader.xml&lt;br /&gt;
*Open TASpring\AI\Bot-libs\myailoader.xml in notepad, and change the value csaidirectory to &amp;quot;AI/myai&amp;quot;, then save the file&lt;br /&gt;
*Create a new directory TASpring\AI\myai&lt;br /&gt;
*For now, copy TASpring\AI\CSAI\csai.dll and TASpring\AI\CSAI\csai.pdb into the TASpring\AI\myai directory.&lt;br /&gt;
&lt;br /&gt;
AI\myai is where we&amp;#039;ll be placing our own AI dll.  For now we&amp;#039;ve copied the csai dll into it to check that the loader xml is configured correctly.&lt;br /&gt;
&lt;br /&gt;
Check this is working ok:&lt;br /&gt;
*Create a new multiplayer game&lt;br /&gt;
*Do &amp;quot;add bot&amp;quot;.  Click &amp;quot;reload&amp;quot;.  You should see &amp;quot;myailoader.dll&amp;quot;&lt;br /&gt;
*Select &amp;quot;myaialoader.dll&amp;quot; and do ok&lt;br /&gt;
*Do &amp;quot;add bot&amp;quot; and add &amp;quot;emptyai.dll&amp;quot;.  This gives you a dummy opponent so you can spectate&lt;br /&gt;
*Click &amp;quot;Spectate&amp;quot; and launch the game&lt;br /&gt;
*Check that the game starts and that the commanders appear&lt;br /&gt;
&lt;br /&gt;
If the game started and the commander appeared, everything is working so far.  If you get an error message about a global AI exception, and spring shuts down, recheck the steps above.&lt;br /&gt;
&lt;br /&gt;
Now that we&amp;#039;ve set up the myailoader.dll , we can create our own AI project.&lt;br /&gt;
&lt;br /&gt;
*Download and unzip [http://manageddreams.com/csai/csaitemplate.zip csaitemplate.zip]&lt;br /&gt;
*Start Visual C# 2005 Express&lt;br /&gt;
*Create a new project of type &amp;quot;Class library&amp;quot;, called &amp;quot;csai&amp;quot; (note: the name is important)&lt;br /&gt;
*Delete the default file &amp;quot;Class1.cs&amp;quot;&lt;br /&gt;
*Add the file CSAI.cs and LogFile.cs from the csaitemplate.zip file&lt;br /&gt;
*In the solution explorer, open CSAI.cs&lt;br /&gt;
**Locate the string variable aidirectory at the top of the class&lt;br /&gt;
**Change its value to &amp;quot;myai&amp;quot;&lt;br /&gt;
*In the solution explorer, right-click &amp;quot;References&amp;quot;, do &amp;quot;Add Reference...&amp;quot;, select the &amp;quot;Browse&amp;quot; tab, and add TASpring\CSAIInterfaces.dll&lt;br /&gt;
*We want to build as Debug, because this gives better error messages.  By default it may build as Release, so:&lt;br /&gt;
**Go to &amp;quot;Tools&amp;quot; | &amp;quot;Options...&amp;quot;  Navigate to &amp;quot;Projects and Solutions&amp;quot;, &amp;quot;General&amp;quot;.  Select &amp;quot;Show Advanced build configurations&amp;quot;, then click &amp;quot;ok&amp;quot;&lt;br /&gt;
**Go to &amp;quot;Build&amp;quot; | &amp;quot;Configuration Manager...&amp;quot;&lt;br /&gt;
**Set Active solution configuration to &amp;quot;Release&amp;quot;, then close the dialog&lt;br /&gt;
*Build the solution.  It should build with no errors, otherwise check the last few steps&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ve created an empty AI dll.  We need to check that it build ok.&lt;br /&gt;
*Locate the bin\Debug directory in your project directory&lt;br /&gt;
*You should see csai.dll, csai.pdb, CSAIInterfaces.dll and CSAIInterfaces.pdb&lt;br /&gt;
*Copy csai.dll and csai.pdb into the TASpring\AI\myai directory, overwriting the existing csai.dll and csai.pdb&lt;br /&gt;
&lt;br /&gt;
Create a multiplayer game, add the myailoader.dll and emptyai.dll bots as before, click Spectate and Start&lt;br /&gt;
*The game should start and the commander should appear&lt;br /&gt;
&lt;br /&gt;
If the game starts and the commander appears, with no error messages about &amp;quot;Global AI Exception&amp;quot; then everything is working so far.  You&amp;#039;ve created a C# AI project.&lt;br /&gt;
&lt;br /&gt;
= Talking to the player =&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s make the AI say something to the player.  We use the SendTextMsg function to do this.  The SendTextMsg function is available from the aicallback object in the CSAI class.&lt;br /&gt;
&lt;br /&gt;
SendTextMsg takes two parameters.  The first is the text you want to say, and the second is the number zero.&lt;br /&gt;
&lt;br /&gt;
In the CSAI.cs file, locate the function &amp;quot;InitAI&amp;quot;&lt;br /&gt;
*You should see a comment &amp;quot;// your init code here&amp;quot;&lt;br /&gt;
*Add the line:&lt;br /&gt;
**aicallback.SendTextMsg( &amp;quot;Hello world!&amp;quot;, 0 );&lt;br /&gt;
&lt;br /&gt;
Test that this works:&lt;br /&gt;
*Rebuild the project&lt;br /&gt;
*Copy the csai.dll and csai.pdb files into TASpring/AI/myai , overwriting the old ones&lt;br /&gt;
*Restart the game, or just say &amp;quot;.reloadai&amp;quot; if the old game is still running&lt;br /&gt;
*The commander should appear, and the AI should say &amp;quot;Hello world!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If something went wrong, and the message didnt appear, the AI will almost certainly no longer crash.  &lt;br /&gt;
Instead you can find any error messages in the logfile at TASpring/AI/myai/csharpai_team0.log&lt;br /&gt;
&lt;br /&gt;
Just make any corrections, recompile, copy the new dlls over to TASpringAI/myai , and say &amp;quot;.reloadai&amp;quot; in the game to load the corrected AI dll.&lt;br /&gt;
= Building your first solar panel =&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s make the commander build a solar panel.&lt;br /&gt;
&lt;br /&gt;
To do this, we use aicallback.GiveOrder , passing in the commander&amp;#039;s id and an appropriately initialized Command object.&lt;br /&gt;
&lt;br /&gt;
The Command object has two parts: &lt;br /&gt;
*an id that specifies the command type, in this case it will be the typeid for a solar cell&lt;br /&gt;
*a double array which in this case specifies the position of the new solar cell.&lt;br /&gt;
&lt;br /&gt;
There are a couple of prerequisites:&lt;br /&gt;
*we need to know the commander&amp;#039;s id, to give to the GiveOrder function&lt;br /&gt;
*we need the typeid for a solar cell&lt;br /&gt;
*we need to find an appropriate location for the solar panel&lt;br /&gt;
&lt;br /&gt;
== Get Commander id ==&lt;br /&gt;
&lt;br /&gt;
First, let&amp;#039;s get the commander&amp;#039;s id.  An easy way to do this is using the UnitFinished method in the CSAI class.  This method is essentially an event that fires whenever a new friendly unit has finished building.&lt;br /&gt;
We&amp;#039;ll get a UnitFinished event for the commander right at the start of the game.&lt;br /&gt;
&lt;br /&gt;
In the UnitFinished function there should be a line &amp;quot;IUnitDef unitdef = aicallback.GetUnitDef( deployedunitid );&amp;quot;.&lt;br /&gt;
*this line obtains an IUnitDef object for the newly created unit&lt;br /&gt;
*An IUnitDef gives access to data about each unit type, such as its name, its human name, whether it is a commander&lt;br /&gt;
*You can browse through the properties available on an IUnitDef using Visual Studio Express:&lt;br /&gt;
**On the line just after IUnitDef def = aicallback.GetUnitDef( deployedunitid );, type:&lt;br /&gt;
**unitdef.&lt;br /&gt;
**Intelisense should automatically produce a list of all the unitdef properties you can read.&lt;br /&gt;
Instead of writing &amp;quot;unitdef.&amp;quot;, insert some new code to get the commander&amp;#039;s id, type:&lt;br /&gt;
&lt;br /&gt;
if( unitdef.isCommander )&lt;br /&gt;
{&lt;br /&gt;
   int commanderid = deployedunitid;&lt;br /&gt;
   aicallback.SendTextMsg( &amp;quot;Commander id is: &amp;quot; + commanderid, 0 );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
*Recompile, copy the dlls over to TASpring/AI/myai, and restart the game to test this modification&lt;br /&gt;
*The AI should say &amp;quot;Commander id is: &amp;quot; and the commander&amp;#039;s id&lt;br /&gt;
&lt;br /&gt;
Note that since the commander is created only once in each game, at the start, you&amp;#039;ll need to restart the game, .reloadai is not going to work with this code.&lt;br /&gt;
&lt;br /&gt;
If it works, good.  If there&amp;#039;s a problem, you can check the logfile at TASpring/AI/myai/csharpai_team0.log&lt;br /&gt;
&lt;br /&gt;
== Get solar cell typeid ==&lt;br /&gt;
&lt;br /&gt;
Next, let&amp;#039;s look at finding the typeid for solar cells.  &lt;br /&gt;
To do this, we can use the function aicallback.GetUnitDefList()&lt;br /&gt;
&lt;br /&gt;
IUnitDef[] GetUnitDefList()&lt;br /&gt;
&lt;br /&gt;
This returns an array containing an IUnitDef s for every available unit in the currently loaded mod.&lt;br /&gt;
&lt;br /&gt;
The function takes a while to run, 2-3 seconds, so you probably want to run this only once in your real AI, and store the results.&lt;br /&gt;
&lt;br /&gt;
We can get the solar cell&amp;#039;s typeid using the following code.  Add this inside your if, just after the aicallback.SendTextMsg line:&lt;br /&gt;
&lt;br /&gt;
 IUnitDef[] unitdeflist = aicallback.GetUnitDefList();&lt;br /&gt;
 IUnitDef solarcelldef = null;&lt;br /&gt;
 foreach(IUnitDef thisunitdef in unitdeflist )&lt;br /&gt;
 {&lt;br /&gt;
    if( thisunitdef.name == &amp;quot;ARMSOLAR&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
       solarcelldef = thisunitdef;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
 aicallback.SendTextMsg( &amp;quot;Found solar cell def: &amp;quot; + solarcelldef.id + &lt;br /&gt;
    &amp;quot; human name: &amp;quot; + solarcelldef.humanName, 0 );&lt;br /&gt;
&lt;br /&gt;
Recompile, copy the csai.dll and csai.pdb files over to TASpring/AI/myai and restart the game.&lt;br /&gt;
&lt;br /&gt;
Remember that .reloadai won&amp;#039;t work with this code, because we&amp;#039;re relying on the UnitFinished event to get the commmander&amp;#039;s id.&lt;br /&gt;
&lt;br /&gt;
== Get buildsite ==&lt;br /&gt;
&lt;br /&gt;
Next we need to find an appropriate location for the solar panel.  The function to do this is aicallback.ClosestBuildSite:&lt;br /&gt;
&lt;br /&gt;
aicallback.ClosestBuildSite( IUnitDef unitdef, Float3 targetpos, double searchRadius, int minDistance )&lt;br /&gt;
&lt;br /&gt;
*unitdef: the IUnitDef for the unit we want to build&lt;br /&gt;
*targetpos: roughly where we want to build it&lt;br /&gt;
*minDistance: not sure, but putting 2 here works&lt;br /&gt;
*searchRadius: how far to look for a build spot before giving up&lt;br /&gt;
&lt;br /&gt;
We already have the unitdef for a solar cell, so we just need an approximate location.  We can use the commander&amp;#039;s location for this.&lt;br /&gt;
We can get this by calling aicallback.GetUnitPos:&lt;br /&gt;
&lt;br /&gt;
Float3 GetUnitPos( int unitdeployedid )&lt;br /&gt;
&lt;br /&gt;
*unitdeployedid:  the unit&amp;#039;s deployedid, in this case we&amp;#039;ll use commanderid&lt;br /&gt;
*returns the position as a Float3&lt;br /&gt;
&lt;br /&gt;
Float3&amp;#039;s are used a lot.  They have three properties x, y, z, which typically represent the position of something.&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s get the commander&amp;#039;s position.  After the foreach(){} block above, you can add the following code:&lt;br /&gt;
&lt;br /&gt;
 Float3 commanderpos = aicallback.GetUnitPos( commanderid );&lt;br /&gt;
 aicallback.SendTextMsg( &amp;quot;The commander&amp;#039;s position is &amp;quot; +&lt;br /&gt;
    commanderpos.ToString(), 0 );&lt;br /&gt;
&lt;br /&gt;
Compile, copy the dlls, and restart the game.  You should see the AI say the position of the commander.&lt;br /&gt;
&lt;br /&gt;
Now, we can call ClosestBuildSite to get a good build site for the solar cell.  Add the following code beneath our last aicallback. SendTextMsg line:&lt;br /&gt;
&lt;br /&gt;
 Float3 buildsite = aicallback.ClosestBuildSite( &lt;br /&gt;
    solarcelldef, commanderpos, 1400, 2 );&lt;br /&gt;
 aicallback.SendTextMsg( &amp;quot;solar cell buildsite: &amp;quot; + buildsite.ToString(), 0 );&lt;br /&gt;
&lt;br /&gt;
Build, copy the dlls, restart the game&lt;br /&gt;
*You should see the ai giving the proposed solar cell position&lt;br /&gt;
*Check that it&amp;#039;s roughly near the commander&amp;#039;s position , otherwise double check the code above&lt;br /&gt;
&lt;br /&gt;
== Build solar cell ==&lt;br /&gt;
&lt;br /&gt;
We&amp;#039;ve got the information we need.  Now let&amp;#039;s build a solarcell.  We can use aicallback.GiveOrder.  The general format for a GiveOrder command is:&lt;br /&gt;
&lt;br /&gt;
aicallback.GiveOrder( targetid, new Command( commandid, new double[]{ x, y, z } ) );&lt;br /&gt;
&lt;br /&gt;
*The targetid in this case is the commander&amp;#039;s id, commanderid&lt;br /&gt;
*The commandid can take specific predefined values, such as CMD_MOVE or CMD_ATTACK&lt;br /&gt;
*For a build command, commandid is minus the type id of the unit to build&lt;br /&gt;
*Lastly, an array of doubles, which in this case is the position where we want to build the solar cell&lt;br /&gt;
&lt;br /&gt;
Just underneath the last aicallback.SendTextMsg line, add the following lines:&lt;br /&gt;
&lt;br /&gt;
aicallback.GiveOrder( commanderid, new Command( - solarcelldef.id, buildsite.ToDoubleArray() ) );&lt;br /&gt;
&lt;br /&gt;
The code you just wrote should look something like:&lt;br /&gt;
&lt;br /&gt;
 IUnitDef unitdef = aicallback.GetUnitDef( deployedunitid );&lt;br /&gt;
if (unitdef.isCommander)&lt;br /&gt;
{&lt;br /&gt;
    int commanderid = deployedunitid;&lt;br /&gt;
    IUnitDef[] unitdeflist = aicallback.GetUnitDefList();&lt;br /&gt;
    IUnitDef solarcelldef = null;&lt;br /&gt;
    foreach (IUnitDef thisunitdef in unitdeflist)&lt;br /&gt;
    {&lt;br /&gt;
        if (thisunitdef.name == &amp;quot;ARMSOLAR&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            solarcelldef = thisunitdef;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    aicallback.SendTextMsg(&amp;quot;Found solar cell def: &amp;quot; + solarcelldef.id + &lt;br /&gt;
      &amp;quot; human name: &amp;quot; + solarcelldef.humanName, 0 );&lt;br /&gt;
    Float3 commanderpos = aicallback.GetUnitPos(commanderid);&lt;br /&gt;
    aicallback.SendTextMsg(&amp;quot;The commander&amp;#039;s position is &amp;quot; + &lt;br /&gt;
       commanderpos.ToString(), 0 );&lt;br /&gt;
    Float3 buildsite = aicallback.ClosestBuildSite(&lt;br /&gt;
       solarcelldef, commanderpos, 1400, 2);&lt;br /&gt;
    aicallback.SendTextMsg( &amp;quot;solar cell buildsite: &amp;quot; + &lt;br /&gt;
       buildsite.ToString(), 0 );&lt;br /&gt;
    aicallback.GiveOrder(commanderid, new Command(-solarcelldef.id,&lt;br /&gt;
       buildsite.ToDoubleArray()));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Recompile, copy the dlls and restart the game to test.&lt;br /&gt;
&lt;br /&gt;
Important: we&amp;#039;re building an ARM solar panel, so the AI must be running as ARM for this to work.&lt;br /&gt;
&lt;br /&gt;
Hopefully you should see the commander build a solar panel.  Otherwise check the logfile for any error message, and try again.&lt;br /&gt;
&lt;br /&gt;
Remember that .reloadai won&amp;#039;t work with this code, because we&amp;#039;re relying on the UnitFinished event to get the commmander&amp;#039;s id, so you&amp;#039;ll need to restart the game.  There are ways around this, but that is for later :-) .&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s some pictures of the commander building a solar panel:&lt;br /&gt;
&lt;br /&gt;
http://manageddreams.com/csai/screenshots/tut_buildsolar1.JPG&lt;br /&gt;
&lt;br /&gt;
http://manageddreams.com/csai/screenshots/tut_buildsolar2.JPG&lt;br /&gt;
[[Category:AI Dev]]&lt;/div&gt;</summary>
		<author><name>interaidev&gt;Flozi</name></author>
	</entry>
</feed>