User:CS:GO Bot Behavior Trees

From Valve Developer Community
Revision as of 02:00, 9 November 2021 by Gazyi (talk | contribs) (Stub)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
English (en)

Stub

This article or section is a stub. You can help by expanding it.

Broom icon.png
This article or section needs to be updated to include current information regarding the subject.
Remember to check for any notes left by the tagger at this article's talk page.
Counter-Strike: Global Offensive Level Creation

In Template:Game name, bots can be given a Behavior Tree to follow. A behavior tree dictates how the bot senses things (vision, hearing, damage sensing), moves, attacks, and does other actions.

They use Valve's proprietary KeyValues3 format (.kv3), which is a text-based format with somewhat strict syntax. They typically use the bt_ prefix, to signify that file is a Behavior Tree. They are stored in csgo/scripts/ai. One can create and use his own behavior trees, see below.

Officially, behavior trees are used for the game modes Csgo icon coopstrike.png Co-op Strike, Csgo icon guardian.png Guardian and Csgo icon deathmatch.png Deathmatch.

Behavior trees were first added to the game on September 16, 2019. Since September 1, 2020, behavior trees can be packed into BSP files.

Using a Behavior Tree

The ConVar mp_bot_ai_bt can assign a behavior tree to all bots on the server. Its value is a string representing the path to a .kv3 file, starting from csgo/. For example, the following line is used for official Deathmatch and can be found in csgo/cfg/gamemode_deathmatch.cfg:

mp_bot_ai_bt "scripts/ai/deathmatch/bt_default.kv3"

For the Co-op game mode, info_enemy_terrorist_spawn entities have the KeyValue behavior_tree_file that can be used to specify a behavior tree only for bots spawning at this entity.

Related Console Commands

ConVar Default Value Description
cv_bot_ai_bt_debug_target -1 Draw the behavior tree of the given bot.
cv_bot_ai_bt_hiding_spot_show 0 Draw hiding spots.
cv_bot_ai_bt_moveto_show_next_hiding_spot 0 Draw the hiding spot the bot will check next.
mp_bot_ai_bt "" Use the specified behavior tree file to drive the bot behavior.
mp_bot_ai_bt_clear_cache ConCommand Clears the cache for behavior tree files.

Format

The first line of a .kv3 file is always a header specifying the KV3 version. For CS:GO, use this header:

<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->

Configuration

Todo: 
  • Explain parameters in bt_config

Nodes

This is a list of all nodes on 09/11/2021.

Todo: 
  • Complete node descriptions
  • Define variable types for parameters.
  • Explain all parameters
Function Signature Description
InputInputName bool InputInputName() Called when the entity receives an input from the I/O system. The name of the function needs to be Input followed by the name of the input in CamelCase, for example InputFireUser1 for the FireUser1 input. The function needs to return a boolean value. Setting it to true allows the entity to process the input, while false cancels it.
OnPostSpawn void OnPostSpawn() This is called after the entity has spawned.
Precache void Precache() This is called during entity spawning and after restore to allow scripts to precache any resources they need.

Examples

Default Deathmatch Behavior Tree

Found in csgo/scripts/ai/bt_default.kv3.


<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:generic:version{7412167c-06e9-4698-aff2-e63eb59037e7} -->
{
	config = "scripts/ai/deathmatch/bt_config.kv3"
	root =
	{
		type = "decorator_bot_service"
		memory_to_expire =
		[
			{
				key = "ShortTermAttackMemory"
				time = 0.7
				distance = 0
			},
			{
				key = "LongTermMemory"
				time = 10
				distance = 500
			},
			{
				key = "ShortTermInvestigateMemory"
				time = 3
				distance = 200
			}
		]
		child =
		{
			type = "decorator_buy_service"
			output = "ShouldBuy"
			child =
			{
				type = "parallel"
				children =
				[
					{
						type = "decorator_repeat"
						child =
						{
							type = "parallel"
							children =
							[
								// memorize enemies through vision
								{
									type = "subtree"
									file = "scripts/ai/modules/bt_memorize_enemies_vision.kv3"
									name = "MemorizeEnemiesVision"
								},
								// memorize noises happening right now
								{
									type = "subtree"
									file = "scripts/ai/modules/bt_memorize_noises.kv3"
									name = "MemorizeNoises"
								},
								// record the nearest memorized event to investigate
								{
									type = "subtree"
									file = "scripts/ai/modules/bt_memorize_nearest_investigation.kv3"
									name = "MemorizeNearestInvestigation"
								}
							]
						}
					},
					{
						type = "decorator_repeat"
						child =
						{
							type = "selector"
							children =
							[
								// Buy if we have to
								{
									type = "condition_is_empty"
									input = "ShouldBuy"
									negated = 1
									child =
									{
										// sequencer: evaluate first to last child, in order
										type = "sequencer"
										children =
										[
											{
												type = "action_wait"
												wait_time_min = 3
												wait_time_max = 3
											},
											{
												type = "action_buy"
											},
											{
												type = "decorator_remove_key"
												input = "ShouldBuy"
											}
										]
									}
								},
								// Else: face the damage source if we're taking damage
								{
									type = "decorator_sensor"
									entity_type_filter = "DAMAGE"
									output = "Damage"
									priority = 0
									child =
									{
										type = "condition_is_empty"
										input = "Damage"
										negated = 1
										child =
										{
											type = "action_aim"
											input = "Damage"
											acquire_only = 1
										}
									}
								},
								// Else: attack if we see an enemy
								{
									type = "subtree"
									file = "scripts/ai/modules/bt_attack.kv3"
									name = "Attack"
								},
								{
									type = "subtree"
									file = "scripts/ai/modules/bt_heal_if_needed.kv3"
									name = "HealIfNeeded"
								},
								// Else: investigate the closest memorized event
								{
									type = "subtree"
									file = "scripts/ai/modules/bt_investigate_closest_memorized_event.kv3"
									name = "InvestigateClosestMemorizedEvent"
								},
								// Else: hunt
								{
									// sequencer: evaluate first to last child, in order
									type = "sequencer"
									children =
									[
										{
											type = "action_equip_weapon"
											weapon = "BEST"
										},
										{
											type = "decorator_random_int"
											min = 0
											max = 1
											output = "BombSiteIndex"
											child =
											{
												type = "action_choose_bomb_site_area"
												input = "BombSiteIndex"
												output = "HuntAreas"
											}
										},
										{
											type = "action_choose_team_spawn_area"
											output = "HuntAreas"
										},
										{
											type = "action_choose_random_waypoint"
											input = "HuntAreas"
											output = "TargetHuntArea"
										},
										{
											type = "action_move_to"
											destination = "TargetHuntArea"
											movement_type = "BT_ACTION_MOVETO_RUN"
											route_type = "BT_ACTION_MOVETO_FASTEST_ROUTE"
										}
									]
								}
							]
						}
					}
				]
			}
		}
	}
}