Skip to content
/ MChallenge-Addon Public template

A sample MChallenge addon that shows how to add custom challenges to MChallenge - Paper Plugin

License

Notifications You must be signed in to change notification settings

MUtils-MC/MChallenge-Addon

Repository files navigation

MChallenge Addon Template

A template to create your own MChallenge addon. This addon is developed in Kotlin and as a PaperMC plugin. You can create MChallenge addons for all platforms as long as MChallenge supports them too (Paper & Fabric).

More information - MUtils Website

IMPORTANT
MChallenge addons must be published under the same licence as MUtils (AGPL v3) and must comply with the MUtils TOS


HOW TO

If you already know how to clone and access repositories, skip to step 3.
Just make sure to add the mutils-addon tag

- Step 1

Clone this repository to create your new addon and add the tag mutils-addon by clicking on the cogwheel in the about section. Create a new IntelliJ project and click on Project from Version Control and enter your repository URL. Finally, wait for Gradle to load your new project.

Images - Click to unfold Clone this template repository

---
Copy your new repository link into IntelliJ

- Step 2

If you plan to publish your addon, you should rename the de.miraculixx namespace to your own namespace. If you own a domain you can use this (e.g. mutils.net -> net.mutils). To rename a file or package press shift + F6, enter your new name and refactor.
Additionally, you need to apply your changes in the plugin.yml file in the resources folder by changing the main attribute.

Images - Click to unfold Rename a package or file

---
Change the main attribute

- Step 3

Add a new mod enum in the utils/AddonMod enum class:

enum class AddonMod(val uuid: UUID) {
    MOD_ONE(UUID.randomUUID()),
    MOD_TWO(UUID.randomUUID()),
    ;
}

Additionally, each mod/challenge needs a default configuration (settings) and mod data (icon, name, ...). You can add a default configuration by extending the getDefaultSetting() function:

fun getDefaultSetting(): ChallengeData {
    return when (this) {
        MOD_ONE -> ChallengeData(emptyMap(), emptyMap()) // No settings
        MOD_TWO -> ChallengeData( // One integer setting with id 'damage'
                mapOf("damage" to ChallengeIntSetting("BEETROOT", 2, "hp", min = 1, max = 20)), // Setting data
                mapOf("damage" to IconNaming(cmp("Setting Name"), listOf(cmp("Setting Lore")))), // Setting display
            )
    }
}

You can add mod data by extending the getModData() function:

fun getModData(): CustomChallengeData {
    return when (this) {
        MOD_ONE -> CustomChallengeData(
            uuid,
            ModOneClass(),
            AddonManager.getSettings(this),
            Icon("CHEST", naming = IconNaming(cmp("Mod Name"), listOf(cmp("Mod Description")))),
            setOf(ChallengeTags.FUN)
        )
    }
}

- Step 4

Finally, you have to add the core of your new mod, the logic! Create a new class inside the mods package (e.g. ModOneClass) and extend the Challenge interface from MChallenge API. You must override at least the register() and unregister() functions. A detailed description can be viewed by hovering over all API classes and functions or entering them with strg + left-click.

A full example for a Mod that damage you on chest interactions:

class DamageOnChest : Challenge {
    private var damage: Int = 2

    override fun start(): Boolean {
        // Refresh all mod settings and apply them
        val settings = AddonManager.getSettings(AddonMod.DAMAGE_ON_CHEST_CLICK).settings
        damage = settings["damage"]?.toInt()?.getValue() ?: 2

        return true
    }

    override fun register() {
        // Register our listener
        onChestClick.register()
    }

    override fun unregister() {
        // Unregister our listener
        onChestClick.unregister()
    }

    /**
     * We use KSpigot to easily implement our listeners.
     * 
     * IMPORTANT
     * - Set the listen state "register" to false, to prevent preloading the listener!
     * - If you not use KSpigot for any reason, use a local state variable that toggles on and off in [register] and [unregister] and check the state at the start of your listener
     */
    private val onChestClick = listen<PlayerInteractEvent>(register = false) {
        val block = it.clickedBlock ?: return@listen
        if (block.type != Material.CHEST) return@listen
        it.player.damage(damage.toDouble())
    }
}

About

A sample MChallenge addon that shows how to add custom challenges to MChallenge - Paper Plugin

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages