Actions
Actions are what happens when an enchantment gets activated.
Creating an action
To start, create a class that implements the interface RegistrableAction
.
class MyAction : RegistrableAction {
override val aliases = listOf<String>()
override fun execute(event: Event, trigger: RegistrableTrigger, arguments: List<String>, target: TargetType): EventModifications? {
return null
}
}
Fill the aliases list with however you want to identify your action.
The execute
method is the main part of the action where the logic happens. You will notice that you are given:
event
- an instance of the event that has happenedtrigger
- the trigger which has activated the enchantmentarguments
- the arguments supplied for the actiontarget
- the target supplied for the action
Obtaining the target
Often the target will simply be the player that has activated the enchantment, but this is not always the case, which is why you are given a target.
If you have read the triggers preamble for users, you will know that triggers provide data retrieval methods. DataRetrievalType
is an enum separate from TargetType
, and there's no straight way to go from one to another as of 2.2. Internally, UnderscoreEnchants uses this extension function:
fun TargetType.mapToDrt(): DataRetrievalType = when (this) {
TargetType.FIRST_PLAYER -> DataRetrievalType.FIRST_PLAYER
TargetType.SECOND_PLAYER -> DataRetrievalType.SECOND_PLAYER
TargetType.THIRD_PLAYER -> DataRetrievalType.THIRD_PLAYER
TargetType.ENTITY -> DataRetrievalType.ENTITY
TargetType.BLOCK -> DataRetrievalType.BLOCK
TargetType.FIRST_ITEM -> DataRetrievalType.FIRST_ITEM
TargetType.SECOND_ITEM -> DataRetrievalType.SECOND_ITEM
}
You can copy and use it as well until a straightforward conversion is added to the API.
To obtain the target, you need to reference the trigger data holder, which is where the data retrieval methods are stored as a map of DataRetrievalType to Method. After you obtain it, invoke the method on the event and cast it to whatever type you need.
val method = trigger.getTriggerDataHolder().dataRetrievalMethods[target.mapToDrt()]
val target = method?.invoke(event) as? Player ?: return null
Using the arguments
The arguments in actions are positional and not named. As such, you can simply index the list of arguments to obtain what you need.
if (arguments.size < 2) return null
val argument1 = arguments[0].toDoubleOrNull() ?: return null
val argument2 = arguments[1]
Returning
The execute
method returns a nullable instance of EventModifications
. What is that? It is a list of methods to call or fields to modify on the event. Most actions will not benefit from this and just return null
. However, some actions, like the built-in cancel
event, will make use of it as follows:
return EventModifications.Builder()
// Adding a method and supplying arguments
.addMethodToCall(event.javaClass.getDeclaredMethod("setCancelled", Boolean::class.java), listOf(true))
.build()
Example action
class ApplyVelocityAction : RegistrableAction {
override val aliases = listOf("velocity", "apply-velocity")
override fun execute(event: Event, trigger: RegistrableTrigger, arguments: List<String>, target: TargetType): EventModifications? {
if (arguments.size < 3) return null
val x = arguments[0].toDoubleOrNull() ?: return null
val y = arguments[1].toDoubleOrNull() ?: return null
val z = arguments[2].toDoubleOrNull() ?: return null
val method = trigger.getTriggerDataHolder().dataRetrievalMethods[target.mapToDrt()] ?: return null
val entity = method.invoke(event) as? Entity ?: return null
entity.velocity = Vector(x, y, z)
return null
}
}