Development
AI Programming
- API Documentation
- Introduction
- info.nut file
- main.nut file
- Basics
- Using the road pathfinder
- Using the rail pathfinder
- Saving / Loading data
- Things you need to know
- Squirrel
- Lists
- Coping with OTTD errors
- Trams
- AI Libraries
- Forum
- Forum FAQ
- AI Behavior
- ShortNames in use
AIs
All articles in NoAI category
Contents |
Libraries
To avoid code-duplication, and every AI creator doing the same work over and over, there is the library system. There are, of course, two sides on this: creating a library, and using a library.
Using Existing Libraries
To use an existing library, you just have to load it into your AI. Doing this is very simple. The layout of the library directory (bin/ai/library/):
graph/ aystar/ pathfinder/ road/ rail/ queue/ binary_heap/ priority_queue/ fibonacci_heap/
Say you want to use the Priority Queue, you simply do:
import("queue.priority_queue", "PriorityQueue", 2);
The first parameter is the category and the implementation, divided with a dot ('.'). The next parameter is the name the library you import will have, in this case PriorityQueue
. It can be anything you like, as long as it doesn't exist yet. The last parameter is the version you expect the library to be. To get the current version of a library, open library.nut from the corresponding directory.
The version check is very important. If you expect version 1, but on some users computer the library is in version 2, your AI will refuse to load. This is a good thing, as a new version means something changed with the existing functions, and your AI will most likely act up if you would use it. This early problem detection system should avoid many conflicts in the future.
Now how to use the library? Simple:
local pq = PriorityQueue(); pq.Insert(2);
Of course it depends on the library which parameters should be given to the constructor, and which functions exist. You'll have to open queue/priority_queue/main.nut
to see all the documentation.
Creating a library
Creating a library is like creating an AI. You create a directory in a category in bin/ai/library
, and you put in it a file called 'library.nut
'. Now this is almost identical with 'info.nut
', as you put in your AI directory, but instead of extending AIInfo
, it extends AILibrary
, and instead of calling RegisterAI
, you need to call RegisterLibrary
. All makes sense, not? An example:
class PriorityQueue extends AILibrary { function GetAuthor() { return "OpenTTD NoAI Developers Team"; } function GetName() { return "Priority Queue"; } function GetShortName() { return "QUPQ"; } function GetDescription() { return "An implementation of a Priority Queue"; } function GetVersion() { return 2; } function GetDate() { return "2008-06-10"; } function CreateInstance() { return "PriorityQueue"; } function GetCategory() { return "Queue"; } } RegisterLibrary(PriorityQueue());
Now what you need to do is to create a file called 'main.nut
'. It should contain a class you named at CreateInstance()
, like in your AI. Then the same rules apply as an AI. require()
works as you expect, and you can define your class how ever you like.
There are some things you can not do:
-
Register 2 libraries in one
library.nut
-
Define more than 1 class in the
main.nut
(or any required file). However, you can define sub-classes. Say you need an extra class inPriorityQueue
. You can name itPriorityQueue.Subclass
. To access it from within your main class, usethis.Subclass
. Seegraph.AyStar
for an example how it's done.
Multiple libraries of different versions
It will happen to all of us that you have one AI using version 1 of a library, and an other using version 2. For example we take pathfinder.road. Now version 2 will be in ai/library/pathfinder/road, but where should you put version 1? For that we created a method:
In the directory-name of the library, everything behind any '.' (dot) is ignored. So you can call 'road' 'road.blabla', or 'road.2', it doesn't matter for the internals. Now this also allows multiple libraries of the same name, and different versions. For example, if you put version 1 of the pathfinder.road in 'pathfinder/road.1', and keep version 2 in 'pathfinder/road'. The system will load both, and based on your import line, pick one of them (or throws an error if the version you requested doesn't exist ;)).
The collision system still works. So if you put version 2 in both 'pathfinder/road' and 'pathfinder/road.2', it will complain it found two equal libraries.
Standard libraries
There are several libraries for common tasks bundled together with NoAI. These have been prepared by 'OpenTTD NoAI Developers Team'.
Category: Graph
AyStar
This is an implementation of AyStar pathfinding algorithm. It solves graphs by finding the fastest route from one point to the other.
Required libraries: queue.binary_heap
Version History:
- aystar.1: r13461
- aystar.2: r13463
- aystar.3: r13496
- aystar.4: current
Category: Pathfinder
Road
This is an implementation of a basic road pathfinder. You can use it to find the length of existing routes and / or to build new routes. Since version 3 building of tunnels / bridges is supported. For more information, see RoadPathfinder
Required libraries: graph.aystar
Version History:
- road.1: r13500
- road.2: r13570
- road.3: current
Rail
This is an implementation of a basic rail pathfinder. You can use it to find a path for new railways. For more information, see RailPathfinder
Required libraries: graph.aystar
Version History:
- rail.1: r14382
Category: Queue
Binary Heap
This is an implementation of binary heap data structure.
Version History:
- binary_heap.1: current
Priority Queue
This is an implementation of priority queue data structure.
Version History:
- priority_queue.1: r13440
- priority_queue.2: r13447
Fibonacci Heap
This is an implementation of fibonacci heap data structure.
Version History:
- Fibonacci_heap.1: 14380