summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt
blob: 7be112db4559ff3857ad1c441ac56970d79c68fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package io.dico.parcels2.command

import io.dico.dicore.command.*
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration
import io.dico.parcels2.Interactables
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.logger
import java.util.LinkedList
import java.util.Queue

@Suppress("UsePropertyAccessSyntax")
fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = CommandBuilder().apply {
    val parcelsAddress = SpecialCommandAddress()

    setChatController(ParcelsChatController())
    addParameterType(false, ParcelParameterType(plugin.parcelProvider))
    addParameterType(false, ProfileParameterType())
    addParameterType(true, ParcelTarget.PType(plugin.parcelProvider, parcelsAddress))

    group(parcelsAddress, "parcel", "plot", "plots", "p") {
        addContextFilter(IContextFilter.inheritablePermission("parcels.command"))
        registerCommands(CommandsGeneral(plugin, parcelsAddress))
        registerCommands(CommandsPrivilegesLocal(plugin))

        group("option", "opt", "o") {
            setGroupDescription(
                "changes interaction options for this parcel",
                "Sets whether players who are not allowed to",
                "build here can interact with certain things."
            )

            group("interact", "i") {
                val command = ParcelOptionsInteractCommand(plugin.parcelProvider)
                Interactables.classesById.forEach {
                    addSubCommand(it.name, command)
                }
            }
        }

        group("global", "g") {
            registerCommands(CommandsPrivilegesGlobal(plugin))
        }

        group("admin", "a") {
            registerCommands(CommandsAdmin(plugin))
        }

        if (!logger.isDebugEnabled) return@group

        group("debug", "d") {
            registerCommands(CommandsDebug(plugin))
        }
    }

    generateHelpAndSyntaxCommands(parcelsAddress)
}.getDispatcher()

inline fun CommandBuilder.group(name: String, vararg aliases: String, config: CommandBuilder.() -> Unit) {
    group(name, *aliases)
    config()
    parent()
}

inline fun CommandBuilder.group(address: ICommandAddress, name: String, vararg aliases: String, config: CommandBuilder.() -> Unit) {
    group(address, name, *aliases)
    config()
    parent()
}

private fun CommandBuilder.generateHelpAndSyntaxCommands(root: ICommandAddress): CommandBuilder {
    generateCommands(root, "help", "syntax")
    return this
}

private fun generateCommands(address: ICommandAddress, vararg names: String) {
    val addresses: Queue<ICommandAddress> = LinkedList()
    addresses.offer(address)

    while (addresses.isNotEmpty()) {
        val cur = addresses.poll()
        addresses.addAll(cur.children.values.distinct())
        if (cur.hasCommand()) {
            ReflectiveRegistration.generateCommands(cur, names)
        }
    }
}

class SpecialCommandAddress : ChildCommandAddress() {
    private val speciallyTreatedKeys = mutableListOf<String>()

    // Used to allow /p h:1 syntax, which is the same as what PlotMe uses.
    var speciallyParsedIndex: Int? = null; private set

    fun addSpeciallyTreatedKeys(vararg keys: String) {
        for (key in keys) {
            speciallyTreatedKeys.add(key + ":")
        }
    }

    @Throws(CommandException::class)
    override fun getChild(key: String, context: ExecutionContext): ChildCommandAddress? {
        speciallyParsedIndex = null

        for (specialKey in speciallyTreatedKeys) {
            if (key.startsWith(specialKey)) {
                val result = getChild(specialKey.substring(0, specialKey.length - 1))
                    ?: return null

                val text = key.substring(specialKey.length)
                val num = text.toIntOrNull() ?: throw CommandException("$text is not a number")
                speciallyParsedIndex = num

                return result
            }
        }

        return super.getChild(key)
    }

}