Page 6 of 11

Posted: 12 May 2005, 12:39
by ReneV
PauloMorfeo wrote: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.

Good hunting, and may the best AI win ;-)

Posted: 12 May 2005, 13:09
by AF
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

Posted: 12 May 2005, 13:47
by Triaxx2
Besides, we can probably steal something useful from the Simple AI's that get out before us.

request

Posted: 14 May 2005, 08:04
by sp2danny72
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...

Posted: 14 May 2005, 23:27
by Gabba
PauloMorfeo wrote: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.

Posted: 15 May 2005, 00:07
by jouninkomiko
to my knowledge, that is not the case. plugins/modules can be closed source so long as they do not use the gpl-ed code internally

Posted: 15 May 2005, 00:30
by Triaxx2
He didn't say we weren't going to release the source, just that we weren't going to release it until we were finished. Now, can we drop the subject?

Posted: 17 May 2005, 06:27
by jouninkomiko
here's a tentative interface i whipped up...

Code: Select all

#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);

	virtual void UnitCreated(int unit)=0;
	virtual void UnitDestroyed(int unit)=0;

	// 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;
};
and

Code: Select all

#pragma once

#include "float3.h"
#include "command.h"
struct UnitDef;

// 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;

	// taunting :-D
	virtual void SendTextMsg(int player, const char* text, int priority)=0;
	
	virtual int GetCurrentFrame()=0;

	virtual void AddEnterLosCallback(int unit)=0;  //, 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;

	// 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

	virtual const UnitDef* GetUnitDef(const char* unitName)=0;

	//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

Posted: 17 May 2005, 08:16
by ILMTitan
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?

Posted: 17 May 2005, 09:22
by jouninkomiko
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.

Posted: 17 May 2005, 09:35
by Buggi
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.

-Buggi

Posted: 17 May 2005, 10:35
by SJ
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.

Just reminding

Posted: 17 May 2005, 11:38
by alik83
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?

Alik

Posted: 17 May 2005, 19:20
by Buggi
Nothing SJ...

They could always reflect my code if they wanted the source :)

I'm not saying it would be closed, if something is interested in knowing how I did "this" or "that" then I'd share.

-Buggi

Posted: 17 May 2005, 22:04
by jouninkomiko
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

Posted: 17 May 2005, 22:17
by jouninkomiko
Only the callback interface was updated, here it is:

Code: Select all

#pragma once

#include "float3.h"
#include "command.h"
struct UnitDef;

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);

	// taunting :-D
	virtual void SendTextMsg(int player, const char* text, int priority)=0;
	
	virtual int GetCurrentFrame()=0;

	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

	virtual const UnitDef* GetUnitDef(const char* unitName)=0;

	//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
};

Posted: 18 May 2005, 05:31
by Gabba
jouninkomiko wrote: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.

Posted: 18 May 2005, 08:34
by jouninkomiko
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!)

Posted: 19 May 2005, 11:11
by AF
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

Posted: 20 May 2005, 04:03
by jouninkomiko
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.