Writing a Good Game State
The game state system provides structured data about the current state of the game in JSON format. This data supplements the visual information and provides precise details that may not be visible or easily extracted from screenshots.
Framework Required Fields
Include the interaction state in your game state implementation:
_can_interact (boolean)
Controls whether the agent can interact with the game. Should be false during:
- Loading screens
- Cutscenes
- Dialog sequences (where no interaction is possible)
- Menu transitions
- Any non-interactive state
When _can_interact is false, the agent will poll until the state becomes interactive again. This ensures that the agent doesn’t attempt to perform actions when the game is not ready for interaction.
Make sure that this field is only set to true when the game is going to be interactive again without any interaction needed. Otherwise the agent will stall indefinitely!!
Custom Fields
Public Fields
These fields are exposed to the agent and form the core of its decision-making data. Design them to reduce the need for expensive visual operations or unnecessary game actions.
Some examples of public fields include:
- Inventory and equipment items: helps agents avoid constant inventory opening
- Interactive Objects: helps agents narrow down what’s interactable
- Player status: health, stamina, buffs/debuffs: immediate access to player condition
- Environmental data: nearby threats/enemies, current area/zone -> situational awareness without exploration
Most importantly, the game_state helps the agent with calling flayer
functions. For example, if the agent needs to call a function that requires a
specific item, it can check the game state for that item before calling the
function. If the agent needs to navigate to a specific location, it can check
the game state for the coordinates of that location before calling the
function.
Private Fields
All private fields start with an underscore (_) and are hidden from the agent. They can be used for debugging as the full game state is always visible in the nexus timeline.
Best Practices
- Data Formatting
- Use human-readable strings for complex data structures
- Format coordinates as strings:
"x: 50, y: 30, z: 20"instead of separate values - Include units in value strings:
"20kg","5m/s"
- Relevance
- Prioritize information that saves the agent from performing expensive operations
- Include data that would otherwise require multiple UI interactions to obtain
- Provide aggregate data instead of requiring the agent to calculate it
- Remove irrelevant information during simple states
- Performance Considerations
- Keep the JSON structure flat where possible
- Avoid deep nesting of objects
- Context Awareness
- Include the current scene, menu, and relevant player state as public fields
- Only include information the agent actually needs
Example Game States
Here’s a complete example of a well-structured game state:
{
"_can_interact": true,
"player": {
"health": 90,
"stamina": 75,
"position": "x: 120, y: 45, z: 230",
"inventory": [
"5x wood in slot 3",
"7x stone in slot 5",
"1x iron sword in slot 1"
],
"equipment": {
"weapon": "iron sword (durability 80%)",
"armor": "leather set (protection 15)"
},
"status_effects": ["well_fed: 5min remaining", "rested: 2min remaining"]
},
"environment": {
"time_of_day": "morning",
"weather": "rain",
"temperature": "cold",
"location": {
"biome": "forest",
"zone": "starting_area",
"landmarks": ["trading_post: 50m north", "cave_entrance: 30m east"]
}
},
"interactive_objects": {
"resources": [
"iron_ore: x: 125, y: 45, z: 232 (requires mining lvl 2)",
"oak_tree: x: 118, y: 45, z: 228 (requires axe)"
],
"crafting_stations": [
"workbench: x: 115, y: 45, z: 225 (in range)",
"forge: x: 160, y: 45, z: 240 (too far)"
]
},
"entities": {
"hostile": [
"skeleton: x: 140, y: 45, z: 235 (aggressive)",
"wolf: x: 130, y: 45, z: 230 (passive)"
],
"friendly": [
"villager_merchant: x: 115, y: 45, z: 228 (can trade)",
"villager_quest: x: 118, y: 45, z: 229 (has quest)"
]
},
"active_quests": [
{
"name": "Gather Resources",
"objective": "Collect 10 wood and 5 iron ore",
"progress": "5/10 wood, 0/5 iron ore",
"reward": "50 gold, 1x steel axe",
"time_remaining": "2 hours"
}
],
"_debug": {
"_last_input": "move_forward",
"_physics_states": {
"_collision_count": 3,
"_raycast_hits": 2
}
}
}{
"_can_interact": true,
"player": {
"health": 100,
"armor": 50,
"position": "x: 200, y: 150, z: 300",
"inventory": [
"pistol: ammo: 15/30",
"shotgun: ammo: 5/8",
"grenade: x2"
],
"equipment": {
"primary_weapon": "assault_rifle (durability 90%)",
"secondary_weapon": "sniper_rifle (durability 80%)"
},
"status_effects": ["speed_boost: 10s remaining"]
},
"environment": {
"time_of_day": "afternoon",
"weather": "clear",
"location": {
"map_name": "downtown_area",
"landmarks": ["building_1", "park"]
}
},
"interactive_objects": {
"resources": [
"ammo_box: x: 205, y: 150, z: 305 (requires pickup)",
"health_pack: x: 210, y: 150, z: 310 (requires pickup)"
],
"vehicles": [
"car: x: 220, y: 150, z: 320 (requires key)",
"bike: x: 225, y: 150, z: 325 (available)"
]
},
"entities": {
"hostile": [
"enemy_soldier: x: 230, y: 150, z: 330 (aggressive)",
"enemy_sniper: x: 235, y: 150, z: 335 (passive)"
],
"friendly": [
"teammate_1: x: 240, y: 150, z: 340 (in range)",
"teammate_2: x: 245, y: 150, z: 345 (out of range)"
]
},
"active_quests": [
{
"name": "Secure the Area",
"objective": "Eliminate all enemies in the downtown area",
"progress": "3/5 enemies eliminated",
"reward": "100 gold, 1x health pack",
"time_remaining": "30 minutes"
}
],
"\_debug": {
"\_last_input": "shoot",
"\_physics_states": {
"\_collision_count": 2,
"\_raycast_hits": 1
}
}
}
{
"_can_interact": true,
"player": {
"health": 80,
"mana": 50,
"position": "x: 300, y: 200, z: 400",
"inventory": [
"health_potion: x5",
"mana_potion: x3",
"iron_sword: durability 70%"
],
"equipment": {
"weapon": "iron_sword (durability 70%)",
"armor": "chainmail (protection 20)"
},
"status_effects": ["blessed: 5min remaining"]
},
"environment": {
"time_of_day": "evening",
"weather": "foggy",
"location": {
"biome": "swamp",
"zone": "abandoned_village"
}
},
"interactive_objects": {
"resources": [
"herb: x: 305, y: 200, z: 405 (requires gathering)",
"treasure_chest: x: 310, y: 200, z: 410 (requires opening)"
],
"crafting_stations": [
"alchemy_table: x: 315, y: 200, z: 415 (in range)",
"forge: x: 320, y: 200, z: 420 (too far)"
]
},
"entities": {
"hostile": [
"goblin: x: 325, y: 200, z: 425 (aggressive)",
"wolf: x: 330, y: 200, z: 430 (passive)"
],
"friendly": [
"villager_merchant: x: 335, y: 200, z: 435 (can trade)",
"quest_giver: x: 340, y: 200, z: 440 (has quest)"
]
},
"active_quests": [
{
"name": "Collect Herbs",
"objective": "Gather 10 herbs from the swamp",
"progress": "3/10 herbs collected",
"reward": "50 gold, 1x health potion",
"time_remaining": "1 hour"
}
],
"_debug": {
"_last_input": "cast_spell",
"_physics_states": {
"_collision_count": 1,
"_raycast_hits": 0
}
}
}