Some API extension ideas

Discuss the new AI features ("NoAI") introduced into OpenTTD 0.7, allowing you to implement custom AIs, and the new Game Scripts available in OpenTTD 1.2 and higher.

Moderator: OpenTTD Developers

Chruker
Engineer
Engineer
Posts: 49
Joined: 01 Jun 2009 20:13

Re: Some API extension ideas

Post by Chruker »

Rubidium wrote:
Chruker wrote:Your 600 figure will ONLY be correct for games without NewGRFs that change base costs and with the construction cost set to medium.

For 'low' the base cost is 450, for high 675. So you will then always be off by 25 or 12,5% even though you assume the number is correct. When base costs are changed can even more off than that.
Are you sure? I dont think my settings have changed since I tested it and the construction costs are set to high.

But you are right about the newgrf's from hell, and also the non-rectangular airports _IF_ they come.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Blustuff wrote:I don't know if it has already been mentionned but it seems there is some problem to handle engines which can transport more than one cargo. These two functions does not provide enough information about it :

static CargoID AIEngine::GetCargoType (EngineID engine_id)
static int32 AIEngine::GetCapacity (EngineID engine_id)

Maybe the API can be extended with some of these :

class AICargoList_EngineTransporting
static bool AIEngine::CanTransportCargo (EngineID engine_id, CargoID cargo_id)
static int32 AIEngine::GetCapacity (EngineID engine_id, CargoID cargo_id) // Would need a fresh function name
Valid problem, I'll see what I can come up with as solution.
AICompany::GetPresidentGender()
AICompany::SetPresidentGender()

would allow to have a firstname matching with the gender
Not sure why this is necesary, but then, we already support changing the president name, so why not.
Chruker wrote:Chruker: AIEngine::GetDesignYear
Wouldn't you also need a AIEngine::GetModelLife for this to be useful?
Chruker: Ability to output line number for errors
Noted.
Zuu: AIStation::GetConstructionDate(station_id) Chruker: or perhaps a generic construction date function that works on tilebasis.
Is AIStation::GetConstructionDate(tile) ok?
The sorting constants, mentioned here: http://wiki.openttd.org/AI:APISuggestions
AIAbstractList.SORT_ASCENDING <- true;
AIAbstractList.SORT_DESCENDING <- false;
Noted.
Rubidium
OpenTTD Developer
OpenTTD Developer
Posts: 3815
Joined: 09 Feb 2006 19:15

Re: Some API extension ideas

Post by Rubidium »

Blustuff wrote:static bool AIEngine::CanTransportCargo (EngineID engine_id, CargoID cargo_id)
What's wrong with AIEngine::CanRefitCargo(EngineID, CargoID)?
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Rubidium wrote:
Blustuff wrote:static bool AIEngine::CanTransportCargo (EngineID engine_id, CargoID cargo_id)
What's wrong with AIEngine::CanRefitCargo(EngineID, CargoID)?
Support for planes (which can transport both passengers and mail), and also for articulated engines that can transport multiple cargo types (I think that's possible, but not 100% sure).
Blustuff
Engineer
Engineer
Posts: 112
Joined: 21 Aug 2008 09:37
Location: France

Re: Some API extension ideas

Post by Blustuff »

Chruker wrote:Chruker: Ability to output line number for errors
Even if it would be usefull to output line numbers (and file !) I think that a basic support for exceptions would be great. I created a base class for exceptions, but when thrown, this outputs an "unknown error". Maybe an AIException base class which users can extends would be handy. I wanted to use exceptions for defensive programming, e.g. when you use a switch statement on an Enum type and if the enum type get extended you don't want to continue as nothing happend but to throw an error which will help updating the AI. I'm sure I could find many cases where exceptions are useful. However, having "unknown error" printed on the debug console is not a real problem since with the line and file where the exception have been thrown you will have enough information to debug.

some issues with very low priority :
  • delegate settings and labels table for AIInfo seems to be rejected by OpenTTD as it doesn't find every fields. delegate settings and labels could be usefull to define common type of settings.
  • I couldn't use a child class of AIInfo which had a constructor with arguments, I don't know why.
  • Class members initialized on class definition can not use referecences to the API. I wanted to initialize a static variable with AIVehicle.VT_ROAD, but this isn't possible. In some cases it would be interesting to have an environnement with the API at the loading time, especially to AILog. I don't know what problems it would cause.
Chruker
Engineer
Engineer
Posts: 49
Joined: 01 Jun 2009 20:13

Re: Some API extension ideas

Post by Chruker »

Yexo wrote:
Chruker wrote:Chruker: AIEngine::GetDesignYear
Wouldn't you also need a AIEngine::GetModelLife for this to be useful?
The intended usage of the design year would be to predict the max. reliability an engine would reach. Ex. if an engine design is less than 2 years old and have just 70% reliability I could could then treat it like it has 75-80% reliability.

BTW, this is all assuming that the max. reliability of a vehicle follows the engine's max. reliability. Ex. if an engine is designed in 1940 and a vehicle is build the same year. Another vehicle is then build in 1944 (at this point the engine max. reliabilty have risen from when it was introduced). Will both vehicles at that point get the same max. reliability?
User avatar
Dustin
Transport Coordinator
Transport Coordinator
Posts: 272
Joined: 07 Dec 2005 19:22

Re: Some API extension ideas

Post by Dustin »

Chruker wrote:
Yexo wrote:Summary of currently requested but not yet implemented nor denied functions:
*::GetCost()
AIVehicle::ChangeServicingInterval (FS#2853)
Functions to check the vehicles / stations of other companies (FS#2776)
Possible AIVehicle.GetWagonLength, if Michiel can explain a use case for it.

Did I miss anything in this list?
Yes:
Chruker: AIEngine::GetDesignYear
Chruker: Ability to output line number for errors
Zuu: AIStation::GetConstructionDate(station_id) Chruker: or perhaps a generic construction date function that works on tilebasis.

The sorting constants, mentioned here: http://wiki.openttd.org/AI:APISuggestions
AIAbstractList.SORT_ASCENDING <- true;
AIAbstractList.SORT_DESCENDING <- false;

Blustuff: AICompany::GetPresidentGender()
Blustuff: AICompany::SetPresidentGender()
I would really like a hook into the vehicle in game pathfinder to predict if vehicles will get lost.

bool AITrainRoute.RouteExists(startTile, destinationTile); // would simulate a train attempting to make it from the start tile to the end tile (considering signals but not other trains and reservations)
bool AITrainRoute.RouteToDepotExists(tile); //would simulate a train looking for a depot (considering signals, but not traffic)

bool AIRoadVehicleRoute.RouteExists(startTile, destinationTile);
bool AIRoadVehicleRoute.RouteToDepotExists(tile);
Rubidium
OpenTTD Developer
OpenTTD Developer
Posts: 3815
Joined: 09 Feb 2006 19:15

Re: Some API extension ideas

Post by Rubidium »

For trains you probably need a track bit you want to start from/reach; if the begin/final tile is a RAILTRACK_NE_SW + RAILTRACK_NW_SE tile you might end up on the wrong/an unwanted track bit.

For road vehicles there is a difference between trams and non-trams, so that needs some parameter for that too (I think).

Furthermore depending on the pathfinder your results may/will vary; the simplest pathfinders do not find a path till the destination; they only look X tiles ahead. As a result you might get unreliable results.
User avatar
Dustin
Transport Coordinator
Transport Coordinator
Posts: 272
Joined: 07 Dec 2005 19:22

Re: Some API extension ideas

Post by Dustin »

Rubidium wrote:For trains you probably need a track bit you want to start from/reach; if the begin/final tile is a RAILTRACK_NE_SW + RAILTRACK_NW_SE tile you might end up on the wrong/an unwanted track bit.

For road vehicles there is a difference between trams and non-trams, so that needs some parameter for that too (I think).

Furthermore depending on the pathfinder your results may/will vary; the simplest pathfinders do not find a path till the destination; they only look X tiles ahead. As a result you might get unreliable results.
It might be useful then to have it always use YAPF for these functions since it seems check the entire route right off the bat.

Or maybe we could just build an AI library to examine networks for "leaks". If AIRail.AreTilesConnected does what I think it does and confims a track connects two tiles, then such a library should be reasonably easy to create.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Dustin wrote:Or maybe we could just build an AI library to examine networks for "leaks". If AIRail.AreTilesConnected does what I think it does and confims a track connects two tiles, then such a library should be reasonably easy to create.
It does do that, so such a library is indeed very easy. You can find such a pathfinder for road in AdmiralAI. For rail just copy that, but use the AIRail functions instead of the AIRoad equivalents.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Blustuff wrote:
Chruker wrote:Chruker: Ability to output line number for errors
Even if it would be usefull to output line numbers (and file !) I think that a basic support for exceptions would be great. I created a base class for exceptions, but when thrown, this outputs an "unknown error". Maybe an AIException base class which users can extends would be handy. I wanted to use exceptions for defensive programming, e.g. when you use a switch statement on an Enum type and if the enum type get extended you don't want to continue as nothing happend but to throw an error which will help updating the AI. I'm sure I could find many cases where exceptions are useful. However, having "unknown error" printed on the debug console is not a real problem since with the line and file where the exception have been thrown you will have enough information to debug.
Isn't the line number already printed?
For the other issue: only throwing strings is 'supported', is this a real problem? How to print a string when you throw a class object? If you say, just call a tostring fuctions, then what if your script crashes again in that handler?
some issues with very low priority :
  • delegate settings and labels table for AIInfo seems to be rejected by OpenTTD as it doesn't find every fields. delegate settings and labels could be usefull to define common type of settings.
Can you provide a sample info.nut that fails?
[*]I couldn't use a child class of AIInfo which had a constructor with arguments, I don't know why.
This works fine here:

Code: Select all

class mytestai extends AIInfo {
	
	constructor(arg1) {
		::AIInfo.constructor();
	}
.....

RegisterAI(mytestai (3));
The trick is to call the AIInfo constructor. Without that call your class won't be recognized as AIInfo subclass.
[*]Class members initialized on class definition can not use referecences to the API. I wanted to initialize a static variable with AIVehicle.VT_ROAD, but this isn't possible. In some cases it would be interesting to have an environnement with the API at the loading time, especially to AILog. I don't know what problems it would cause.[/list]
I can confirm the problem, it's due to the order of initialization. First your script is compiled, then the API is added to the vm.
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Some API extension ideas

Post by Zuu »

Yexo wrote:
Zuu: AIStation::GetConstructionDate(station_id) Chruker: or perhaps a generic construction date function that works on tilebasis.
Is AIStation::GetConstructionDate(tile) ok?

That should be fine. Currently it seams that the entire station have the same construction date. So tile/station_id shouldn't matter. But sure tile is ok.


Another thing I've been thinking of which I don't claim as my idea because a similar idea has been mentioned before. The idea is that that by default when a game is loaded, skip the step "use the exact same version of AI if possible". There could be an advanced setting that is by default set so that it loads last version of same AI that loads the saved game, but users can change to the current behaviour.

Using MinVersiontToLoad function AIs can refuse to load previously saved games if it want. And if you accept to load old saves you should be able to handle them and therefore I don't see a problem if the AI is "upgraded" by default. Otherwise we will have to keep educating users on how to upgrade the AI in a currently running game.
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Zuu wrote:Another thing I've been thinking of which I don't claim as my idea because a similar idea has been mentioned before. The idea is that that by default when a game is loaded, skip the step "use the exact same version of AI if possible". There could be an advanced setting that is by default set so that it loads last version of same AI that loads the saved game, but users can change to the current behaviour.

Using MinVersiontToLoad function AIs can refuse to load previously saved games if it want. And if you accept to load old saves you should be able to handle them and therefore I don't see a problem if the AI is "upgraded" by default. Otherwise we will have to keep educating users on how to upgrade the AI in a currently running game.
This is on my todo list, but requires some code rewriting.
Blustuff
Engineer
Engineer
Posts: 112
Joined: 21 Aug 2008 09:37
Location: France

Re: Some API extension ideas

Post by Blustuff »

Yexo wrote:How to print a string when you throw a class object? If you say, just call a tostring fuctions, then what if your script crashes again in that handler?
If you catch an exception in Squirrel, you would probably like to print it and the rule in squirrel is that whenever an object is printed or used in a string expression call the delegate method _tostring. The problem of having another error/exception in the _tostring method is well known and scripting langages which use this pattern raises a fatal error which can't be customized by the user.

However, there is no such problem in the case where a standard (and included in API) AIException class is used since the message is generated before raising the exception and passed to the constructor of AIException which set a field with it.

Can you provide a sample info.nut that fails?
I can.

The trick is to call the AIInfo constructor. Without that call your class won't be recognized as AIInfo subclass.
Thanks.
Attachments
info.nut
(1.12 KiB) Downloaded 153 times
User avatar
Zuu
OpenTTD Developer
OpenTTD Developer
Posts: 4553
Joined: 09 Jun 2003 18:21
Location: /home/sweden

Re: Some API extension ideas

Post by Zuu »

Yexo wrote:This is on my todo list, but requires some code rewriting.
Thank you, that is nice to hear. But I guess your todo list is quite long, but probably it will eventually happen. :-)
My OpenTTD contributions (AIs, Game Scripts, patches, OpenTTD Auto Updater, and some sprites)
Junctioneer (a traffic intersection simulator)
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Blustuff wrote:delegate settings and labels table for AIInfo seems to be rejected by OpenTTD as it doesn't find every fields. delegate settings and labels could be usefull to define common type of settings.
Thanks for the info.nut. I think the problem is that OpenTTD iterates over all items of the table. While doing so, it won't find the parent items, because they're not part of the table, but of the parent of the table. When getting the value of an index, if it can't be found in the table, the parent table is checked. But OpenTTD never asks for the value of an index, it just loops over all item/value pairs.

To work around this, you could ues a squirrel function like this:

Code: Select all

function CombineTables(parent, child)
{
  local result = {};
  foreach (a, b in parent) result[a] = b;
  foreach (a, b in child) result[a] = b;
  return result;
}
Not that I haven't tested this code at all.
Blustuff wrote:
Yexo wrote:How to print a string when you throw a class object? If you say, just call a tostring fuctions, then what if your script crashes again in that handler?
If you catch an exception in Squirrel, you would probably like to print it and the rule in squirrel is that whenever an object is printed or used in a string expression call the delegate method _tostring. The problem of having another error/exception in the _tostring method is well known and scripting langages which use this pattern raises a fatal error which can't be customized by the user.
This requires changing squirrel code, which we tend to avoid if possible.
However, there is no such problem in the case where a standard (and included in API) AIException class is used since the message is generated before raising the exception and passed to the constructor of AIException which set a field with it.
This too requires changing squirrel code, but also makes squirrel depend on an API class, which would break all abstraction layers we currently have.
Blustuff
Engineer
Engineer
Posts: 112
Joined: 21 Aug 2008 09:37
Location: France

Re: Some API extension ideas

Post by Blustuff »

Yexo wrote:Not that I haven't tested this code at all.
Actually you can access the parent(s) table of any table so you would only one parameter. In this precise case, a change of design would also do well: use functions to generate tables instead of delegating tables.
This requires changing squirrel code, which we tend to avoid if possible.
This too requires changing squirrel code, but also makes squirrel depend on an API class, which would break all abstraction layers we currently have.
I don't really understand. Squirrel doesn't provide the objet which was raised would it be a string or an instance ?
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Blustuff wrote:
This requires changing squirrel code, which we tend to avoid if possible.
This too requires changing squirrel code, but also makes squirrel depend on an API class, which would break all abstraction layers we currently have.
I don't really understand. Squirrel doesn't provide the objet which was raised would it be a string or an instance ?
The 'exception object' never leaves squirrel code at all. It's squirrel code that prints a stacktrace and then returns to OpenTTD that an error has occured.
Yexo
Tycoon
Tycoon
Posts: 3663
Joined: 20 Dec 2007 12:49

Re: Some API extension ideas

Post by Yexo »

Several of the suggestions have been added (see http://www.tt-forums.net/viewtopic.php?f=65&t=44571).

Current list of functions to implement (again, if I miss anything, please let me know):
  • AIVehicle::ChangeServicingInterval (FS#2853)
  • Functions to check the vehicles / stations of other companies (FS#2776)
  • Load latest version of AI that can load the data, don't load exact same version first.
  • *::GetCost()
  • AICargoList_EngineTransporting / AIEngine::CanTransportCargo(EngineID, CargoID) / AIEngine::GetCapacity(EngineID, CargoID)
Blustuff
Engineer
Engineer
Posts: 112
Joined: 21 Aug 2008 09:37
Location: France

Re: Some API extension ideas

Post by Blustuff »

Yexo wrote:Functions to check the vehicles / stations of other companies (FS#2776)
As stated in the wiki an AI should be parametrized to not compete with other players. Shouldn't it be with other human players ? In this case, I didn't find API calls which can tell if a company is owned by a human player or by an AI. This would be another low priority request.
Post Reply

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 36 guests