summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/command/ParcelCommandBuilder.kt
blob: b4eae309340a7d3569d3e0dd73c01fbeda5b16ca (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package io.dico.parcels2.command

import io.dico.dicore.command.*
import io.dico.dicore.command.parameter.ArgumentBuffer
import io.dico.dicore.command.predef.DefaultGroupCommand
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration
import io.dico.parcels2.Interactables
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.logger
import io.dico.parcels2.util.ext.hasPermAdminManage
import org.bukkit.command.CommandSender
import java.util.LinkedList
import java.util.Queue

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

    setChatHandler(ParcelsChatHandler())
    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)
                Interactables.classesById.forEach {
                    addSubCommand(it.name, command)
                }
            }
        }

        val adminPrivilegesGlobal = CommandsAdminPrivilegesGlobal(plugin)

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

        group("admin", "a") {
            setCommand(AdminGroupCommand())
            registerCommands(CommandsAdmin(plugin))

            group("global", "g") {
                registerCommands(adminPrivilegesGlobal)
            }
        }

        if (!logger.isDebugEnabled) return@group

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

    generateHelpAndSyntaxCommands(parcelsAddress)
}.getDispatcher().also {
    RootCommandAddress.debugChildren(it as ModifiableCommandAddress)
}

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

private 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()
        cur.childrenMainKeys.mapTo(addresses) { cur.getChild(it) }
        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 + ":")
        }
    }

    // h:1
    @Throws(CommandException::class)
    override fun getChild(context: ExecutionContext, buffer: ArgumentBuffer): ChildCommandAddress? {
        speciallyParsedIndex = null

        val key = buffer.next() ?: return 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)
    }

}

private class AdminGroupCommand : DefaultGroupCommand() {
    override fun isVisibleTo(sender: CommandSender) = sender.hasPermAdminManage
}