Hooray--Sort Of
I was able to hack around inside my already
hacked-together turn-based strategy app so that it can load AI from custom
assemblies. It actually works in a pretty easy way now where you create a class
that derives from a base class (AIUser) in the main library assembly. After
implementing a few abstract methods you build it and drop the assembly
in the same folder as the main library assembly. Then, if you want one of the
game's armies to use your new AI, you point their "AI" property as defined in
the game's XML file, and run it. The change is pretty simple, such as
from
<
AI>TBSDefaultAI.TBSDefaultAI</AI>
to
<
AI>LandOnlyAI.LandOnlyAI</AI>
Unfortunately, I ran into a few things I'm not too sure how to handle
correctly. It seems like you can't cast a dynamically instantiated object
into a specific type. For example, I tried to do:
Assembly assembly = Assembly.LoadFile(assemblyPath);
m_AIUser aiUser = (AIUser)
assembly.CreateInstance(className, true);
where assemblyPath and className are strings passed into
the method and AIUser is the abstract base class of the object created in CreateInstance
(but from another assembly). I wanted to just be able to call the
abstract methods on the base class cast of the new object in the same
way I would call any other, and have them fulfilled by the overriden
implementations in the dynamic object. I couldn't seem to hack that in, so I
ended up using the Type object and invoking the methods and properties on the
object in a very formal way:
this.m_Type =
assembly.GetType(className);
this.m_Type.GetProperty("ActionedUnit").GetValue(this.m_AIUser, null);
Maybe there's an easy way to actually do this
cleanly that I've overlooked, but in the meantime I've built a simple proxy
class that derives from the AIUser class and does all of this assembly and type
work behind the scenes for the consuming portion of the game. I guess I could
have a method called "public AIUser GetMe()" that just does a "return this;" and
pretend like I was able to easily cast the object from the beginning. Then
again, I'm probably just not reading the documentation
properly.
I'll probably be able to get the code up by lunch
on Monday.