Full Example: Permanent Effect
This page shows all the steps to add a permanent effect and to give it to players. For the terms on this page, see the Glossary.
In this example, players with the permission myplugin.vip get a holder named vip. Server owners write the effects of the holder in config.yml. The new effect no_fall_damage stops fall damage.
Overview
Make the effect.
Register the effect.
Make the holder from the config.
Register a holder provider. This gives the holder to players.
Write the config.
Libreforge then turns the effect on and off for you.
Step 1: Make the effect
package com.example.myplugin
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.map.listMap
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.effects.Effect
import com.willfp.libreforge.effects.Identifiers
import com.willfp.libreforge.effects.ProviderBinding
import org.bukkit.event.EventHandler
import org.bukkit.event.entity.EntityDamageEvent
import java.util.UUID
object EffectNoFallDamage : Effect<NoCompileData>("no_fall_damage") {
override val description = "Stops fall damage to the player."
override val shouldReload = false
override val providerBinding = ProviderBinding.NONE
// For each dispatcher, the identifiers of each active copy of this effect.
private val active = listMap<UUID, UUID>()
override fun onEnable(
dispatcher: Dispatcher<*>,
config: Config,
identifiers: Identifiers,
holder: ProvidedHolder,
compileData: NoCompileData
) {
active[dispatcher.uuid].add(identifiers.uuid)
}
override fun onDisable(dispatcher: Dispatcher<*>, identifiers: Identifiers, holder: ProvidedHolder) {
active[dispatcher.uuid].remove(identifiers.uuid)
}
@EventHandler(ignoreCancelled = true)
fun handle(event: EntityDamageEvent) {
if (event.cause != EntityDamageEvent.DamageCause.FALL) {
return
}
if (active[event.entity.uniqueId].isNotEmpty()) {
event.isCancelled = true
}
}
}
For more about each part, see Creating an Effect.
Steps 2 to 4: Register the effect, make the holder, and give it to players
package com.example.myplugin
import com.willfp.libreforge.Holder
import com.willfp.libreforge.SimpleHolder
import com.willfp.libreforge.SimpleProvidedHolder
import com.willfp.libreforge.ViolationContext
import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.effects.Effects
import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.registerSpecificHolderProvider
import org.bukkit.entity.Player
class MyPlugin : LibreforgePlugin() {
// Made again on each reload, so changes to config.yml apply.
// It is null until the first reload, and the provider must accept this.
private var vipHolder: Holder? = null
override fun handleEnable() {
// Step 2: Register the effect.
Effects.register(EffectNoFallDamage)
// Step 4: Give the holder to each player who has the permission.
registerSpecificHolderProvider<Player>(id = "myplugin:vip") { player ->
val holder = vipHolder
if (holder != null && player.hasPermission("myplugin.vip")) {
listOf(SimpleProvidedHolder(holder))
} else {
emptyList()
}
}
}
override fun handleReload() {
// Step 3: Make the holder from config.yml.
val context = ViolationContext(this, "config.yml")
vipHolder = SimpleHolder(
this.namespacedKeyFactory.create("vip"),
Effects.compile(configYml.getSubsections("vip.effects"), context),
Conditions.compile(configYml.getSubsections("vip.conditions"), context)
)
}
}
Step 5: Write the config
# config.yml
vip:
effects:
- id: no_fall_damage
conditions: []
The effect has no triggers, so it is permanent.
What occurs at runtime
A player with
myplugin.vipjoins. Libreforge asks the holder provider for the holders of the player.The provider gives the
vipholder. The conditions of the holder are true.Libreforge calls
onEnableofno_fall_damage. The player gets no fall damage.The player loses the permission. Libreforge asks the provider again and gets no holders.
Libreforge calls
onDisable. The player gets fall damage again.
When your plugin reloads, libreforge turns off all effects. Then it turns them on again with the new holders. You do not have to do this yourself.
When libreforge asks the provider again
Libreforge asks the holder provider again in these cases:
The items of the player change, the player respawns, or the player goes to a different world.
A fixed time passes. For players, this is 80 ticks (4 seconds) by default.
Your code tells libreforge to do it.
A permission change does not cause an event. To apply the change immediately, tell libreforge after you change the permission:
player.toDispatcher().refreshHolders()
You can also set the time and the events for each provider:
// Also import com.willfp.libreforge.HolderChange.
registerSpecificHolderProvider<Player>(
id = "myplugin:vip",
maxAge = { 200 }, // Ask again after 200 ticks. Return null to never ask on a timer.
invalidatedBy = setOf(HolderChange.Respawn) // Ask again only after these changes.
) { player ->
// ...
}
Caution: The provider must return the holders in the same order each time. If the order changes, libreforge can turn effects off and on again when nothing changed.