Annotations
@Listenerswill auto register event listener:@Listeners class DemoListener : Listener { /* No need to instantiate the class or do pluginManager.registerEvents() the listener will register automatically. */ @EventHandler fun PlayerJoinEvent.on() { player.sendMessage("Hello!") } }
@AutoRegisterwill auto instantiate the class:@AutoRegister class DemoAutoRegister { /* No need to instantiate the class, it will do that automatically (works only for classes with an empty constructor!) */ init { Chat.sendToConsole("Hello console!") } }
@Serviceused to instantiate service classes (check out services to learn more about service usage):// Example item class sealed class Item { abstract val id: String } // Example item impl class (::class.serviceId returns the id from above ^ in this example "diamond-item") @Service("diamond-item") class DiamondItem : Item() { override val id: String = DiamondItem::class.serviceId!! }
PreConfigure
PreConfigureSubTypeProcessor is used to do something with all services of a specific class:
object PreconfigureUsage {
/*
Example usage of `PreConfigureSubTypeProcessor`
loop through all classes extending Item with the @Service annotation.
*/
init {
PreConfigureSubTypeProcessor
.register<Item> {
Chat.sendToConsole("Item service id: ${it.id}")
}
}
}Services
Basically the service of services; get, create, register, autoRegister:
object ServicesService {
/*
Example usage of the Service feature
create "items" service, register all the items with the @Service annotation
send the player the amount of registered items when he joins (debug)
*/
init {
Services.create<Item>("items")
Services.services.autoRegister<Item>("items")
Events
.subscribe(PlayerJoinEvent::class.java)
.handler {
it.player.sendMessage("${Services.services.getService<Item>("items")!!.size}")
}
}
}Commands
We uses ACF for our command system. Here's how to use it:
@CommandAlias("example|ex")
class ExampleCommand : BaseCommand() {
@Default
@Description("Shows the main example command")
fun onDefault(player: Player) {
player.sendMessage("This is the example command!")
}
@Subcommand("test")
@Description("A test subcommand")
fun onTest(player: Player) {
player.sendMessage("This is a test subcommand!")
}
}To register ACF commands, add them to the CommandManager in a class:
override fun enable() {
// ... other initialization code ...
CommandManager.initialize(this)
// ... other initialization code ...
}The CommandManager will automatically register your ACF commands.
MongoDB
Easily serialize/deserialize objects to your MongoDB database:
// Initialize MongoDB in your main plugin class
override fun enable() {
// ... other initialization code ...
Mongo.initialize(config)
// ... other initialization code ...
}
// Example usage in code
object AbilityServiceDemo {
init {
ConfigurationSerialization.registerClass(AbilityDemo::class.java)
MongoController.create<AbilityDemo>()
val demo = AbilityDemo("test", 5000, ItemStack(Material.AIR))
MongoController.find<AbilityDemo>()
.save("test", demo)
Schedulers
.sync()
.runLater({
MongoController.findObject<AbilityDemo>("test")!!.thenAccept {
Chat.sendToConsole("Ability name: ${it.name}")
}
}, 20L)
}
}The MongoController provides easy-to-use methods for CRUD operations:
create<T>(): Create a new collection for type Tfind<T>(): Find the collection for type Tsave<T>(id: String, obj: T): Save an object to the databasefindObject<T>(id: String): Find an object by its IDdelete<T>(id: String): Delete an object by its ID
All operations are asynchronous and return CompletableFuture for easy handling of async results.
Redis
Redis support for caching and pub/sub messaging:
// Initialize Redis in your main plugin class
override fun enable() {
// ... other initialization code ...
val redisHost = config.getString("redis.host") ?: "localhost"
val redisPort = config.getInt("redis.port", 6379)
val redisPassword = config.getString("redis.password")
RedisManager.initialize(redisHost, redisPort, redisPassword)
// ... other initialization code ...
}
// Example usage in your code
RedisManager.set("key", "value")
val value = RedisManager.get("key")
RedisManager.delete("key")The RedisManager provides simple methods for interacting with Redis:
set(key: String, value: String): Set a key-value pairget(key: String): String?: Get the value for a keydelete(key: String): Delete a key-value pair
Remember to close the Redis connection when disabling your plugin:
override fun disable() {
// ... other disable code ...
RedisManager.close()
// ... other disable code ...
}Configuration
We provide a ConfigurationManager for easy handling of configuration files:
// Load a configuration file
ConfigurationManager.load("config.yml")
// Get values from the configuration
val mongoUrl = ConfigurationManager.getString("config.yml", "mongo.url") ?: "mongodb://localhost:27017"
val redisPort = ConfigurationManager.getInt("config.yml", "redis.port", 6379)
val debugMode = ConfigurationManager.getBoolean("config.yml", "debug", false)
// Set values in the configuration
ConfigurationManager.set("config.yml", "some.path", "some value")
// Save changes to the configuration file
ConfigurationManager.save("config.yml")
// Reload a configuration file
ConfigurationManager.reload("config.yml")The ConfigurationManager provides methods for:
- Loading configuration files
- Getting values (with type safety and default values)
- Setting values
- Saving changes
- Reloading configurations
This approach to configuration management makes it easy to handle multiple configuration files and access their values throughout a plugin.