Changes between Version 5 and Version 6 of AIEngineAPI


Ignore:
Timestamp:
Jan 30, 2022, 2:39:29 PM (2 years ago)
Author:
wraitii
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AIEngineAPI

    v5 v6  
    1 > A nice first reading is given in a 2012 interview with Jonathan Waller (quantumstate) on aigamedev: [http://aigamedev.com/open/interview/ai-in-0ad/]. The paragraph on the AI Architecture is still an up-to-date description of the AI interface.
     1== Current design ==
     2The AI design was reworked in r26274. The AI can now directly access simulation data via SimEngine.[wiki:QueryInterface](), as the regular components can.
     3
     4The legacy AIInterface data still exists, though the idea is to reduce its scope over time.
     5
     6== Legacy Design ==
     7
     8> A nice first reading is given in a 2012 interview with Jonathan Waller (quantumstate) on aigamedev: [http://aigamedev.com/open/interview/ai-in-0ad/] . The paragraph on the AI Architecture is still an up-to-date description of the AI interface.
    29
    310AI scripts receive data from the engine about the current simulation state, once per simulation turn. This is a fairly low-level mechanism - it is expected that AI scripts will use a wrapper to provide more convenient access to the data. Currently this wrapper is implemented in `common-ai/base.js`.
     
    714When the AI is initialised the constructor is called with one parameter:
    815
    9 {{{#!js
    10 settings = {
    11   "player": 1, // The player id.  Gaia is 0, players are number sequentially 1,...,n.
    12   "templates": ..., // An object which gives access to the template data from .../simulation/templates/
     16{{{#!js settings = {
     17
     18  "player": 1, // The player id.  Gaia is 0, players are number sequentially 1,...,n. "templates": ..., // An object which gives access to the template data from .../simulation/templates/
     19
    1320}}}
    1421
    1522Every AI turn (currently happens every simulation update which is 5 times a second) the AI's `HandleMessage` method is called with one argument:
    1623
    17 {{{#!js
    18 state = {
    19   "entities": ...,
    20   "events": ...,
    21   "players": [...],
    22   "timeElapsed": ..., // seconds since the start of the match
    23   "territoryMap": ..., // map of player territories
    24   "passabilityMap": ..., // Map showing where obstructions are
    25   "passabilityClasses": ...
     24{{{#!js state = {
     25
     26  "entities": ..., "events": ..., "players": [... ...] , "timeElapsed": ..., // seconds since the start of the match "territoryMap": ..., // map of player territories "passabilityMap": ..., // Map showing where obstructions are "passabilityClasses": ...
     27
    2628}}}
     29
    2730== `entities` ==
    2831Each entity has a set of dynamic properties which are kept up to date.  The AI can also access the template data for all entities.
     
    3033An entity will have the form
    3134
    32 {{{#!js
    33 var ret = {
    34   "id": 172, // This id is unique and permanent
    35   "template": "unit/hele_spearman",
    36   "position": [102.2, 34.7], // The unit position is undefined in some cases (e.g. garrisoned)
    37   "hitpoints": 80,
    38   "owner": 4, // Player who owns this unit
    39   "idle": true,
    40   "unitAIState": "UNIT/INDIVIDUAL/GATHERING",
    41   "unitAIOrderData": cmpUnitAI.GetOrderData(),
    42   "trainingQueue": [{
    43                       "id": 7,
    44                       "unitTemplate": "spearman", // If this is a unit being trained
    45                       "technologyTemplate": "phase_city", // If this is a technology being researched
    46                       "count": 5, // number of units being trained
    47                       "progress": 0.78, // Proportion of training completed (range 0.0 to 1.0)
    48                       "metadata": {"role": "worker"}, // The AI can set metadata when adding a unit to the queue
    49                     }, ... ], // Array of items currently in the training queue
    50   "foundationProgress": 78, // Percentage complete for construction
    51   "resourceSupplyAmount": 195, // Current resources in a resource deposit (tree, mine, ...)
    52   "resourceCarrying": [{
    53                          "type": "wood", // Resource type
    54                          "amount": 8, // Amount currently being carried
    55                          "max": 20 // Maximum amout of this resource which can be carried
    56                        }, ... ], // array of resources being carried by a gathering unit
    57   "garrisoned": [167, 377, 345] // array of entity id's for the garrisoned entities
    58 }
    59 }}}
     35{{{#!js var ret = {
     36
     37  "id": 172, // This id is unique and permanent "template": "unit/hele_spearman", "position": [102.2, 34.7], // The unit position is undefined in some cases (e.g. garrisoned) "hitpoints": 80, "owner": 4, // Player who owns this unit "idle": true,  "unitAIState": "UNIT/INDIVIDUAL/GATHERING", "unitAIOrderData": cmpUnitAI.[wiki:GetOrderData] (), "trainingQueue": [{
     38    "id": 7, "unitTemplate": "spearman", // If this is a unit being trained "technologyTemplate": "phase_city", // If this is a technology being researched "count": 5, // number of units being trained "progress": 0.78, // Proportion of training completed (range 0.0 to 1.0) "metadata": {"role": "worker"}, // The AI can set metadata when adding a unit to the queue
     39  }, ... ], // Array of items currently in the training queue
     40
     41"foundationProgress": 78, // Percentage complete for construction
     42
     43  "resourceSupplyAmount": 195, // Current resources in a resource deposit (tree, mine, ...) "resourceCarrying": [{
     44    "type": "wood", // Resource type "amount": 8, // Amount currently being carried "max": 20 // Maximum amout of this resource which can be carried
     45  }, ... ], // array of resources being carried by a gathering unit
     46
     47"garrisoned": [167, 377, 345] // array of entity id's for the garrisoned entities } }}}
    6048
    6149== `events` ==
     
    6351
    6452== `passabilityMap` and `passabilityClasses` ==
    65 {{{#!js
    66 state.passabilityMap = {
    67   "width": 256,
    68   "height": 256,
    69   "data": [ ... ] // Uint16Array with width*height entries
    70 };
    71 }}}
    72 {{{#!js
    73 state.passabilityClasses = {
    74   "pathfinderObstruction": 1,
    75   "foundationObstruction": 2,
    76   "building-land": ..., // these are all the PassabilityClasses defined in simulation/data/pathfinder.xml
    77   ...
    78 };
    79 }}}
    80 `state.passabilityMap.data` encodes all the passability data of each terrain tile. `state.passabilityClasses` gives bitmasks that define how to interpret `state.map.data`. For example:
     53{{{#!js state.passabilityMap = {
    8154
    82 {{{#!js
    83 // Get the bitmask for tiles that will obstruct foundations (i.e. you can't place any buildings there)
    84 var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
     55  "width": 256, "height": 256, "data": [ ... ] // Uint16Array with width*height entries
     56
     57}; }}} {{{#!js state.passabilityClasses = {
     58
     59  "pathfinderObstruction": 1, "foundationObstruction": 2, "building-land": ..., // these are all the PassabilityClasses  defined in simulation/data/pathfinder.xml ...
     60
     61}; }}} `state.passabilityMap.data` encodes all the passability data of each terrain tile. `state.passabilityClasses` gives bitmasks that define how to interpret `state.map.data`. For example:
     62
     63{{{#!js // Get the bitmask for tiles that will obstruct foundations (i.e. you can't place any buildings there) var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
    8564
    8665for (var i = 0; i < map.data.length; ++i)
    87     if (map.data[i] & obstructionMask)
    88         ; // tile i is an unbuildable location
     66
     67  if (map.data[i] & obstructionMask)
     68    ; // tile i is an unbuildable location
     69
     70}}} Since these are bitmasks, you can 'or' them together:
     71
     72{{{#!js var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
     73
     74// Add in the bitmask for tiles that are obstructed for the "building-land" passability class // (i.e. tiles that are underwater or too steep, based on the definition in pathfinder.xml) obstructionMask |= gameState.getPassabilityClassMask("building-land");
     75
     76for (var i = 0; i < map.data.length; ++i)
     77
     78  if (map.data[i] & obstructionMask)
     79    ; // tile i is an unbuildable location for land-based buildings
    8980
    9081}}}
    91 Since these are bitmasks, you can 'or' them together:
    92 
    93 {{{#!js
    94 var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
    95 
    96 // Add in the bitmask for tiles that are obstructed for the "building-land" passability class
    97 // (i.e. tiles that are underwater or too steep, based on the definition in pathfinder.xml)
    98 obstructionMask |= gameState.getPassabilityClassMask("building-land");
    99 
    100 for (var i = 0; i < map.data.length; ++i)
    101     if (map.data[i] & obstructionMask)
    102         ; // tile i is an unbuildable location for land-based buildings
    103 }}}