I just hope that the development of TA::Spring never gets dependent on closed development.
It won't.
I am now completely dedicated to an open process, where anyone can learn from the code and send the maintainers code improvements.
I think Jounin feels (sort of) the same about..
If someone has usefull code to contribute, i'm sure the maintainers (whomever that may become) will take a look at it.
I will help, and certainly understand the code for an "unbeatable AI" in all it's detail, but I simply do not know how much time i'll have to actually write code that's good enough to end up in the public releases.
I'd like to add something about alfa males, and how it affects societies.
But I'll keep it short; there should be no throne to be had in this project, there should only be (a) round table(s).
Alantai, I think it's time you kicked me off your team. I've had some time to think it over, and your way is not mine, sorry.
I realize that those AI teams with simpler design are gonna release sooner probably than the 'unbeatable' AI teams.
In which case I bid you farewell from darkstars Renev, may your path be filled with promise and innovation.
As for competition, I look forward to seeing you all tremble infront of the AI's we release.
And simple AI, people, do us all good, the eyes and ears of the community will be watchign you if we at darkstars dotn beat you to it, or people with previous experience writting RTS AI's & lots of spare time take up the challenge
I have one more request that i would like to have in
the interface from start: std::string QueryMapPath().
So it is possible to have per-map settings for the AI
The goal, in the long run, would be to not need that,
but it would be nice to have for starters...
I just hope that the development of TA::Spring never gets dependent on closed development.
I wonder... with the GPL, don't you have to distribute the source code even of the modules you design for the game? Only the LGPL allows you to distribute closed-source modules. So you can do "closed development" as long as it is for your own private use, but if you want to release anything, the AI module has to be released under the GPL.
Joined: 26 Aug 2004, 07:11 Location: Virginia Tech
here's a tentative interface i whipped up...
Code:
#pragma once
#include "command.h" class IGlobalAICallback;
#define GLOBALAI_INTERFACE_VERSION 1
#include "float3.h"
class IGlobalAI { private: IGlobalAICallback* m_pCallback; int m_iTeam;
public: virtual void InitAI(IGlobalAICallback* callback, int team)=0; // unit id of the commander. let's the AI start action virtual void Start(int commanderid);
// this is handled as an installed callback on a specific "spotter" unit // *hint* i'd probably use this on a peeper, send it into an enemy base, and recon all hits // to store in memory virtual void EnemyEnterLOS(int spotter, int spotted)=0;
// not sure how this will be implemented yet... // im thinking along the lines of allies giving eachother commands or // notifications of their actions to coordinate attacks virtual void GiveMessage()=0;
// i guess this will be called every frame, to let the AI do as it will virtual void Update()=0; };
// typedef void (* ENTERLOSCALLBACK)(int spotter, int spotted);
class IGlobalAICallback { private: // this must be set to the AIs team number int m_iTeam; public: virtual void InitCallback(int team)=0; // not sure how this will work yet, as in IGlobalAI virtual void SendCommandMsg(int team)=0;
virtual int GiveOrder(int unitid, Command* c)=0; // this sends a group order to what the AI has "selected". // must have called SendSelection virtual int GiveGroupOrder(Command* c)=0;
// use this to sync up a selected group, if you want to send many mass orders // to the same group of units. most AIs probably won't use this virtual int SendSelection(const vector<int>* units)=0; virtual const vector<int>* GetSelection()=0;
// as per the Group AI, these return 0 if you don't have los to the unit in question virtual int GetUnitAiHint(int unitid)=0; virtual int GetUnitTeam(int unitid)=0; virtual float GetUnitHealth(int unitid)=0; //the units current health virtual float GetUnitMaxHealth(int unitid)=0; //the units max health virtual float GetUnitSpeed(int unitid)=0; //the units max speed virtual float GetUnitPower(int unitid)=0; //sort of the measure of the units overall power virtual float GetUnitExperience(int unitid)=0; //how experienced the unit is (0.0-1.0) virtual float GetUnitMaxRange(int unitid)=0; //the furthest any weapon of the unit can fire virtual const UnitDef* GetUnitDef(int unitid)=0; //this returns the units unitdef struct from which you can read all the statistics of the unit, dont try to change any values in it, dont use this if you dont have to risk of changes in it
//this will return a value even if you only have radar to it, but it might be wrong virtual float3 GetUnitPos(int unitid)=0; //note that x and z are the horizontal axises while y represent height
//the following functions allows the dll to use the built in pathfinder //call InitPath and you get a pathid back //use this to call GetNextWaypoint to get subsequent waypoints, the waypoints are centered on 8*8 squares //note that the pathfinder calculates the waypoints as needed so dont retrieve them until they are needed //the waypoints x and z coordinate is returned in x and z while y is used for error codes //>=0 =worked ok,-2=still thinking call again,-1= end of path reached or invalid path virtual int InitPath(float3 start,float3 end,int pathType)=0; virtual float3 GetNextWaypoint(int pathid)=0; virtual void FreePath(int pathid)=0;
//This function returns the approximate path cost between two points(note that it needs to calculate the complete path so its somewhat expansive) virtual float GetPathLength(float3 start,float3 end,int pathType)=0;
//the following function return the units into arrays that must be allocated by the dll //10000 is currently the max amount of units so that should be a safe size for the array //the return value indicates how many units was returned, the rest of the array is unchanged virtual int GetEnemyUnits(int *units)=0; //returns all known enemy units virtual int GetEnemyUnits(int *units,const float3& pos,float radius)=0; //returns all known enemy units within radius from pos virtual int GetFriendlyUnits(int *units)=0; //returns all friendly units virtual int GetFriendlyUnits(int *units,const float3& pos,float radius)=0; //returns all friendly units within radius from pos
//the following functions are used to get information about the map //dont modify or delete any of the pointers returned //the maps are stored from top left and each data position is 8*8 in size //to get info about a position x,y look at location //(int(y/8))*GetMapWidth()+(int(x/8)) //some of the maps are stored in a lower resolution than this though virtual int GetMapWidth()=0; virtual int GetMapHeight()=0; virtual const float* GetHeightMap()=0; //this is the height for the center of the squares, this differs slightly from the drawn map since it uses the height at the corners virtual const unsigned short* GetLosMap()=0; //a square with value zero means you dont have los to the square, this is half the resolution of the standard map virtual const unsigned short* GetRadarMap()=0; //a square with value zero means you dont have radar to the square, this is 1/8 the resolution of the standard map virtual const unsigned short* GetJammerMap()=0; //a square with value zero means you dont have radar jamming on the square, this is 1/8 the resolution of the standard map virtual const unsigned char* GetMetalMap()=0; //this map shows the metal density on the map, this is half the resolution of the standard map
virtual float GetElevation(float x,float z)=0; //Gets the elevation of the map at position x,z
virtual bool CanBuildAt(const UnitDef* unitDef,float3 pos)=0; //returns true if a given type of unit can be build at a pos (not blocked by other units etc)
virtual float GetMetal()=0; //stored metal for team virtual float GetEnergy()=0; //stored energy for team virtual float GetMetalStorage()=0; //metal storage for team virtual float GetEnergyStorage()=0; //energy storage for team };
I'm going to start implementing the stubs and giving this AI control over an actual player. input is welcome on this interface
Joined: 13 Nov 2004, 08:35 Location: Central Time Zone, USA
It looks good over all. I have just a few concerns.
1. No way to get command queues. This would allow the AI to detect idle units. Additionally, it would allow the AI to get a queue, rearrange, add to or subtract from and send a new group of orders back.
2. No way to easily get resource flow rate. One could get the rate by subtracting stockpiles between frames, but Spring probably already has an internal flow rate monitor. We don't want the AI to be nanostalling before it detects a massive negative flow. I.e. your fusion reactor was destroyed.
3. I assume a unit is "created" when its construction is started. A functions saying to the AI, unit "completed" or some such would probably be helpful.
And finally, I would like to know a little more about the program flow. As it is now, it seems that the AI would be in series with the rest of the program. Is this something we need to worry about, or is it already in an independent thread?
Joined: 26 Aug 2004, 07:11 Location: Virginia Tech
i think ill just have spring call update every frame, and the AI can do its work then, so have the bulk of the AI being done there. as far as your other points, i agree completely, ill add those in.
I just read the last couple pages of this thread and I must say it's amazing that someone would start a project for spring on the notion of complete closed source being they're working with an opensource engine.
Now I'm working on a massive project to better handle the needs of Spring. The Construction Set I'm working on is extensive. I've chosen the middle path. While the file format is wide open (see HPI diagram thread) and even the implimentation of that format will be open (via a dll and source) the work put into the core app itself may not be open. Aspects of the program will be open, the parts that ARE open, the zip libraries, for example. For the most part, the non-open parts of the system will just be massive internal functions that must be done to manage such a wide variety of files. These things are useless to someone interested in the format of the files, not how their managed in my specific program because they're program should differ in some way.
I'm not re-inventing the wheel, I'm just giving it better rims.
What do you think you would win by keeping part of the source closed buggi?
Jou: I think you should add an interface for AIs (group and global) to communicate via memory sharing. Something simple like
void* GetSharedMemoryArea(string name,int size);
Would be guaranteed to return an area of size size all 0 for the first caller. Would point to the same area when more AIs get the same named area. How to structure the memory would be up to the AIs.
Also it might not be so smart to use stl stuff in the interface since that will lock dll writers to use the same compiler as the main program is compiled with more or less (stl implementations being internally somewhat different between compilers). I just used them in the groupai as a stopgap thing but if you want to create something real you should implement some small versions of the needed classes yourself.
On a similar note you shouldnt have any variables in the interface just pure virtual functions.
Also, Juoninkomiko, you remember about
UnitUnderAttack function? (and damage dealt per second)
Could there be a function that tells if a projectile/missile/Nuke is flying in your LOS or Radar, and it's direction?
A function to tell whether the spot on a map is sea, or land and whether it has wreckage/DT on it? (Maybe there's a function for this already, I don't remember...)
Wonder if the CanBuildAt() function tells whether a place is blocked by reclaimable objects/your units(so you can still build there) or terrain?
Joined: 26 Aug 2004, 07:11 Location: Virginia Tech
i thought about and determined that global and group ai's should be totally separate entities... if anyone has a compelling argument to oppose that, now's the time :)
about memory sharing, i think that's a good way of coordinating attacks between ai allies, and group ai's communicating with one another, so i'm adding that in as well. however, as per the previous statement, i'm not going to let group ai's and global ai's share the same memory.
about stl - totally slipped my mind, i'm removing that in a heartbeat.
alik - right now, canbuildat is just a stub that returns true in the globalai callback. i'm not sure how i'll put that in yet. about the damage per second, i think that should be left to the AI, since it would require alot of bookkeeping by spring for something that an AI might not necessarily use.
as far as unit creation, it was my intent to have that message sent when the unit/building is completed... hopefully that can be done easily. i'll post the updated tentative interface soon to reflect these changes
typedef void (* ENTERLOSCALLBACK)(int spotter, int spotted);
class IGlobalAICallback { public: virtual void InitCallback(int team)=0; // not sure how this will work yet, as in IGlobalAI virtual void SendCommandMsg(int team)=0;
// returns the size of the created area virtual int CreateSharedArea(char* name, int size);
// if null is returned, no shared area exists // returns the size of the area through the size parameters virtual void* GetSharedArea(char* name, int* size);
virtual void AddEnterLosCallback(int unit, ENTERLOSCALLBACK cback); virtual void DeleteEnterLosCallback(int unit)=0;
virtual int GiveOrder(int unitid, Command* c)=0; // this sends a group order to what the AI has "selected". // must have called SendSelection virtual int GiveGroupOrder(Command* c)=0;
virtual Command* GetCurrentCommand(int unitid)=0; // returns the number of commands in the queue for a given unit virtual int GetCommandQueueLen(int unitid)=0; // returns the command queue for a particular unit. up to the AI to allocate sufficient // memory for the call, which is sent in the memsize parameter. returns -1 on fail due to insufficient memory virtual int GetCommandQueue(int unitid, Command* commands, int memsize)=0;
// use this to sync up a selected group, if you want to send many mass orders // to the same group of units. most AIs probably won't use this virtual int SendSelection(const int* units, int numunits)=0; virtual int GetSelection(int* units, int memsize)=0;
// as per the Group AI, these return 0 if you don't have los to the unit in question virtual int GetUnitAiHint(int unitid)=0; virtual int GetUnitTeam(int unitid)=0; virtual float GetUnitHealth(int unitid)=0; //the units current health virtual float GetUnitMaxHealth(int unitid)=0; //the units max health virtual float GetUnitSpeed(int unitid)=0; //the units max speed virtual float GetUnitPower(int unitid)=0; //sort of the measure of the units overall power virtual float GetUnitExperience(int unitid)=0; //how experienced the unit is (0.0-1.0) virtual float GetUnitMaxRange(int unitid)=0; //the furthest any weapon of the unit can fire virtual const UnitDef* GetUnitDef(int unitid)=0; //this returns the units unitdef struct from which you can read all the statistics of the unit, dont try to change any values in it, dont use this if you dont have to risk of changes in it
//this will return a value even if you only have radar to it, but it might be wrong virtual float3 GetUnitPos(int unitid)=0; //note that x and z are the horizontal axises while y represent height
//the following functions allows the dll to use the built in pathfinder //call InitPath and you get a pathid back //use this to call GetNextWaypoint to get subsequent waypoints, the waypoints are centered on 8*8 squares //note that the pathfinder calculates the waypoints as needed so dont retrieve them until they are needed //the waypoints x and z coordinate is returned in x and z while y is used for error codes //>=0 =worked ok,-2=still thinking call again,-1= end of path reached or invalid path virtual int InitPath(float3 start,float3 end,int pathType)=0; virtual float3 GetNextWaypoint(int pathid)=0; virtual void FreePath(int pathid)=0;
//This function returns the approximate path cost between two points(note that it needs to calculate the complete path so its somewhat expansive) virtual float GetPathLength(float3 start,float3 end,int pathType)=0;
//the following function return the units into arrays that must be allocated by the dll //10000 is currently the max amount of units so that should be a safe size for the array //the return value indicates how many units was returned, the rest of the array is unchanged virtual int GetEnemyUnits(int *units)=0; //returns all known enemy units virtual int GetEnemyUnits(int *units,const float3& pos,float radius)=0; //returns all known enemy units within radius from pos virtual int GetFriendlyUnits(int *units)=0; //returns all friendly units virtual int GetFriendlyUnits(int *units,const float3& pos,float radius)=0; //returns all friendly units within radius from pos
//the following functions are used to get information about the map //dont modify or delete any of the pointers returned //the maps are stored from top left and each data position is 8*8 in size //to get info about a position x,y look at location //(int(y/8))*GetMapWidth()+(int(x/8)) //some of the maps are stored in a lower resolution than this though virtual int GetMapWidth()=0; virtual int GetMapHeight()=0; virtual const float* GetHeightMap()=0; //this is the height for the center of the squares, this differs slightly from the drawn map since it uses the height at the corners virtual const unsigned short* GetLosMap()=0; //a square with value zero means you dont have los to the square, this is half the resolution of the standard map virtual const unsigned short* GetRadarMap()=0; //a square with value zero means you dont have radar to the square, this is 1/8 the resolution of the standard map virtual const unsigned short* GetJammerMap()=0; //a square with value zero means you dont have radar jamming on the square, this is 1/8 the resolution of the standard map virtual const unsigned char* GetMetalMap()=0; //this map shows the metal density on the map, this is half the resolution of the standard map
virtual float GetElevation(float x,float z)=0; //Gets the elevation of the map at position x,z
virtual bool CanBuildAt(const UnitDef* unitDef,float3 pos)=0; //returns true if a given type of unit can be build at a pos (not blocked by other units etc)
virtual float GetMetal()=0; //stored metal for team virtual float GetMetalRate()=0; // rate flow for metal virtual float GetEnergy()=0; //stored energy for team virtual float GetEnergyRate()=0; // rate flow for metal virtual float GetMetalStorage()=0; //metal storage for team virtual float GetEnergyStorage()=0; //energy storage for team };
i thought about and determined that global and group ai's should be totally separate entities... if anyone has a compelling argument to oppose that, now's the time :)
If some callback functions would be useful in the group AI, I hope you'll add them there as well.
Joined: 26 Aug 2004, 07:11 Location: Virginia Tech
im going to add a means for the global ai to assign group ai's to... well, groups. sooooooon (its late, and my payment for being home from school is that i get to mow the lawn in the morning!)
Actually I think that groupAI and Global AI should be mergable if the coder wishes in whatever form they wish. Such is the need for variety and flexibility.
And Buggi, interesting that you keeping half closed half open but it sorta defeats the point to an extent. Eitherway best nto to revive that particular topic of discussion
Joined: 26 Aug 2004, 07:11 Location: Virginia Tech
mergeable? like how? right now, the thing that makes sense is to enable a global ai to distribute commands to groups commanded by group ai's, and give them a means to share a memory space.
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum