Interaction Bound
The InteractionBounds allows you to constrain the lifetime of an interactions to specific conditions, such as player location or actions. For example, a player staying within range of an NPC during a conversation or while they are sitting on a bench.
States and Behavior
InteractionBounds operate in three states:
- INTERRUPTING: When the bound condition is broken (e.g., player moves too far), the interaction ends
- BLOCKING: Prevents the bound from being broken (e.g., cancels movement beyond the allowed range)
- IGNORING: Bound conditions are not enforced (e.g., player can move freely)
The bound itself doesn't determine the state - it only responds to the current state provided by the system.
Implementation
Here's how to create a interaction bound:
@Entry("example_bound", "An example interaction bound", Colors.MEDIUM_PURPLE, "mdi:square-rounded")
class ExampleBoundEntry(
override val id: String = "",
override val name: String = "",
override val criteria: List<Criteria> = emptyList(),
override val modifiers: List<Modifier> = emptyList(),
override val triggers: List<Ref<TriggerableEntry>> = emptyList(),
override val interruptTriggers: List<Ref<TriggerableEntry>> = emptyList(),
) : InteractionBoundEntry {
override fun build(player: Player): InteractionBound =
ExampleBound(player, priority, interruptTriggers.eventTriggers)
}
class ExampleBound(
private val player: Player,
override val priority: Int,
override val interruptionTriggers: List<EventTrigger>,
) : ListenerInteractionBound {
override suspend fun initialize() {
super.initialize()
// Setup initial state
}
override suspend fun transitionTo(bound: InteractionBound): Boolean {
// Called before this bound is replaced
// Return false to cancel the transition
return true
}
override suspend fun transitionFrom(bound: InteractionBound) {
// Called after becoming the new bound
// Use this to inherit state from the previous bound
}
@EventHandler(priority = EventPriority.HIGHEST)
private fun onPlayerAction(event: SomeCancellablePlayerEvent) {
if (event.player.uniqueId != player.uniqueId) return
if (boundConditionBroken()) {
// For PlayerEvents, we have a handy method to handle the breaking
handleEvent(event)
// A manual version of the above
when (event.player.boundState) {
InteractionBoundState.BLOCKING -> event.isCancelled = true
InteractionBoundState.INTERRUPTING -> event.player.interruptInteraction()
InteractionBoundState.IGNORING -> {}
}
}
}
private fun boundConditionBroken(): Boolean {
// Check if the bound condition is broken
return false
}
override suspend fun tick() {
// Do something every tick
}
override suspend fun teardown() {
// Cleanup any state
super.teardown()
}
}
Transition Methods
The InteractionBound interface includes two methods for handling transitions between bounds:
transitionTo(bound: InteractionBound): Boolean
Called on the current bound when the system wants to change to a new bound. If this method returns false, the transition is canceled and the current bound remains active. This allows bounds to:
- Seamlessly transition to a new bound without interruption
transitionFrom(bound: InteractionBound)
Called on the new bound before its initialize() method, with the previous bound as a parameter. This allows the new bound to:
- Inherit state from the previous bound
- Perform setup based on the previous bound's state
Implementation Tips
- Always use
handleEvent()for consistent state handling - Check player UUID to ensure you're handling the right player
- Clean up resources in
teardown() - Consider performance for frequently triggered events
Example Flow
Here's how a typical radius bound might work with transitions:
1. Player starts interaction
2. Bound initializes with start location
3. Player moves:
- Within range: No action
- Beyond range:
- If BLOCKING: Cancel movement
- If INTERRUPTING: End interaction
- If IGNORING: Allow movement
4. When switching bounds:
- Call transitionTo() on current bound
- If it returns false, keep current bound
- If true, call teardown on the old bound and transitionFrom() then initialize() on new bound
5. Interaction ends, bound tears down