Skip to content

Kotlin Implementation

TheDude86 edited this page Oct 27, 2025 · 1 revision

Kotlin Tutorial

Here is a simple example on how to get started with creating your first app in Kotlin. We will be implementing the three main concepts previously discussed of Apps, the Environment, App, and Block and how to register your app with Apps.

App & Environment

The first class we'll create is our App class, you can copy and paste this code block into a new file in your project:

class TutorialApp(player: Player): App(player) {
    override fun root(): Block {
        TODO("Not yet implemented")
    }

    override fun onCreate(child: Boolean) {

    }
}

You'll notice there's still a TODO in the root() method, we'll update this method after we create our root block. Also we're leaving the onCreate(child: Boolean) method empty as well. This method is called when a player opens your app, it is useful for initializing data or using Dependency Injection like Dagger.

Now that we have our App class created, we can create our Environment class. Here's the Environment code block you can copy and paste into your project:

class TutorialEnvironment(): Environment<TutorialApp>() {
    override fun build() {

    }

    override fun getInstance(player: Player): TutorialApp = TutorialApp(player)

    override fun name(): String = "Tutorial"

    override fun icon(): String = "http://textures.minecraft.net/texture/de99a406150048fa2673160409ca686662ce0f1c7a4ee54c20ecc901c9d0bd6f"

    override fun permission(): String? = "tutorial.all"

    override fun summary(): String = "This is a tutorial app for the Apps Wiki."
}

Since the Environment class requires an App type parameter, it's typically easier to create your App class first and then your Environment. The Environment class also has several methods for you to implement, most are simple methods used by Apps to properly display your app on the Apps List screen and the Admin app, here's a brief description of what each method does:

build()

This method is run once when you first register your Environment with Apps. It is meant for any initialization code like building a Dagger dependency tree for your app.

getInstance()

This method is called whenever a player opens your app. You should always create a new instance of your App class whenever this method is called as to not cause interference when two players are using your app at the same time.

name()

This method should return the name of your app. Apps uses this value to display the name of your app on the Apps List page.

icon()

This method should return a url to your app's icon. App icons are player heads so this url should be a textures.minecraft.net url.

permission()

This method should return a permission node that will determine if a player is allowed to see your app on the Apps List page. Apps will check with the server's permissions plugin to see if the player currently using Apps has this permissions node. If they do (or you set the method to return null), your app will be displayed in the Apps List page, otherwise, it will be hidden.

summary()

This method should return a simple description of your app. Just one or two sentences is the expected length. This text will be displayed in areas in the Admin app when editing enabled apps and modifying your app's config.

Block

Now that we have our Environment and App setup, now we need to create our first Block. This includes making a Block, ViewController, Presenter, and Interactor.

Presenter

First we'll create a presenter for our block. This is the contract between our Interactor and ViewController and should extend the base Presenter class. Here's a code block you can paste into your project to get started:

interface TutorialPresenter: Presenter {

}

ViewController

Now that we have our Presenter, we can create our ViewController. This class will implement our Present we just created which is why we created that first. Here's the code block for our ViewController:

class TutorialViewController(player: Player, origin: Location): NavigationViewController(player, origin), TutorialPresenter {

    override fun createView() {
        super.createView()
        val title = addTextView(
            modifier = Modifier()
                .size(WRAP_CONTENT, WRAP_CONTENT)
                .alignTopToTopOf(this)
                .centerHorizontally()
                .margins(top = 250, start = 400),
            text = "${ChatColor.BOLD}${ChatColor.ITALIC}${ChatColor.UNDERLINE}Hello World!",
            size = 16,
        )
    }
}

Now, we're actually extending the NavigationViewController class here and not ViewController. This is because the NavigationViewController automatically adds the navigation buttons (Back & Close) on the top of the screen. You can implement ViewController instead if you don't those buttons displayed but typically, you will want those buttons when creating a full screen block.

Interactor

Next we'll add our Interactor with this code block:

class TutorialInteractor(
    private val player: Player,
    private val presenter: TutorialPresenter,
): Interactor(presenter) {

    override fun onCreate() {
        super.onCreate()
    }
}

At this point, our Interactor does not do anything yet but notice that we're passing the TutorialPresenter as a parameter in our constructor. We'll be using the presenter later to set button listeners and update the screen.

Block

The last class we'll be implementing is the Block class. This is our builder class, responsible for satisfying any dependencies for the Interactor and ViewController classes as well as creating our Interactor and ViewController instances. Here's the code block for the Block class:

class TutorialBlock(
    player: Player,
    origin: Location,
): Block(player, origin) {
    private val view = TutorialViewController(player, origin)
    private val interactor = TutorialInteractor(player, view)

    override fun view(): ViewController = view
    override fun interactor(): Interactor = interactor
}

Since neither of our Interactor or ViewController have any extra dependencies, the Block class is pretty simple.

Now that we have have a block to load when our app launches, we can update our App class to set it as the root block. In your TutorialApp class, replace your root() method with this code block:

    override fun root(): Block = TutorialBlock(player, origin)

Registering Your App

And that's all the code we need to create our first app! The last thing we need to do is register our app with Apps. This is very simple and only one line of code:

AppInjector.register(TutorialEnvironment())

This line of code should be added you your JavaPlugin class in the onEnable() method to ensure your app is ready to use once players start joining the server.

Clone this wiki locally