Transitions
Transitions define how your automation moves between states. With Brobot's modern @TransitionSet annotation system (1.1.0+), all transitions for a state are grouped together in a single class, providing better organization and clearer intent.
Modern Transition Definition with @TransitionSetโ
The @TransitionSet annotation groups all transitions for a state in one class. Each class contains:
@FromTransitionmethods that define how to navigate TO this state FROM other states@IncomingTransitionmethod that verifies arrival at this state
// Note: BrobotProperties must be injected as a dependency
@Autowired
private BrobotProperties brobotProperties;
@TransitionSet(state = WorldState.class, description = "World state transitions")
@Component
@RequiredArgsConstructor
@Slf4j
public class WorldTransitions {
private final HomeState homeState;
private final WorldState worldState;
private final IslandState islandState;
private final Action action;
/**
* Navigate from Home to World by clicking the world button.
*/
@FromTransition(from = HomeState.class, priority = 1, description = "Navigate from Home to World")
public boolean fromHome() {
log.info("Navigating from Home to World");
// Mock mode support for testing
if (io.github.jspinak.brobot.config.core.brobotProperties.getCore().isMock()) {
log.info("Mock mode: simulating successful navigation");
return true;
}
return action.click(homeState.getToWorldButton()).isSuccess();
}
/**
* Navigate from Island back to World.
*/
@FromTransition(from = IslandState.class, priority = 2, description = "Return from Island to World")
public boolean fromIsland() {
log.info("Navigating from Island to World");
if (io.github.jspinak.brobot.config.core.brobotProperties.getCore().isMock()) {
return true;
}
return action.click(islandState.getBackToWorldButton()).isSuccess();
}
/**
* Verify that we have successfully arrived at the World state.
*/
@IncomingTransition(description = "Verify arrival at World state")
public boolean verifyArrival() {
log.info("Verifying arrival at World state");
if (io.github.jspinak.brobot.config.core.brobotProperties.getCore().isMock()) {
return true;
}
// Check for world-specific elements
boolean foundMinimap = action.find(worldState.getMinimap()).isSuccess();
if (foundMinimap) {
log.info("Successfully confirmed World state is active");
return true;
} else {
log.error("Failed to confirm World state - minimap not found");
return false;
}
}
}
Key Features of @TransitionSetโ
1. Unified Class Structureโ
All transitions for a state are in ONE class:
- Better organization - easy to find all paths to/from a state
- Clear separation of concerns - navigation vs verification
- Natural file structure that mirrors state structure
2. Method-Level Annotationsโ
@FromTransitionโ
Defines how to navigate TO this state FROM another state:
@FromTransition(
from = SourceState.class, // Required: source state
priority = 1, // Optional: higher = preferred path
description = "Navigation logic" // Optional: documentation
)
public boolean fromSource() {
// Navigation logic
}
@IncomingTransitionโ
Verifies successful arrival at the state:
@IncomingTransition(
description = "Verification logic", // Optional: documentation
)
public boolean verifyArrival() {
// Verification logic
}
3. Automatic Registrationโ
No manual transition setup needed - the framework handles everything automatically.
4. Dependency Injectionโ
Transitions are Spring components with full DI support:
@TransitionSet(state = DashboardState.class)
@Component
@RequiredArgsConstructor
public class DashboardTransitions {
private final LoginState loginState;
private final DashboardState dashboardState;
private final Action action;
private final DatabaseService databaseService; // Any Spring bean
@FromTransition(from = LoginState.class, priority = 1)
public boolean fromLogin() {
// Access any injected dependencies
return action.click(loginState.getSubmitButton()).isSuccess();
}
}
Complete Example: Island Transitionsโ
@TransitionSet(state = IslandState.class, description = "Island state transitions")
@Component
@RequiredArgsConstructor
@Slf4j
public class IslandTransitions {
private final IslandState islandState;
private final WorldState worldState;
private final Action action;
/**
* Navigate from World to Island by clicking on an island.
*/
@FromTransition(from = WorldState.class, priority = 1)
public boolean fromWorld() {
log.info("Navigating from World to Island");
if (io.github.jspinak.brobot.config.core.brobotProperties.getCore().isMock()) {
return true;
}
// Try clicking different islands
ActionResult result = action.click(worldState.getCastle());
if (!result.isSuccess()) {
result = action.click(worldState.getFarms());
}
if (!result.isSuccess()) {
result = action.click(worldState.getMines());
}
return result.isSuccess();
}
/**
* Verify arrival at Island state.
*/
@IncomingTransition
public boolean verifyArrival() {
log.info("Verifying arrival at Island state");
if (io.github.jspinak.brobot.config.core.brobotProperties.getCore().isMock()) {
return true;
}
return action.find(islandState.getIslandName()).isSuccess();
}
}
Transition Patternsโ
Simple Navigationโ
@TransitionSet(state = SettingsState.class)
@Component
@RequiredArgsConstructor
public class SettingsTransitions {
private final HomeState homeState;
private final SettingsState settingsState;
private final Action action;
@FromTransition(from = HomeState.class, priority = 1)
public boolean fromHome() {
if (brobotProperties.getCore().isMock()) return true;
return action.click(homeState.getSettingsIcon()).isSuccess();
}
@IncomingTransition
public boolean verifyArrival() {
if (brobotProperties.getCore().isMock()) return true;
return action.find(settingsState.getSettingsHeader()).isSuccess();
}
}