@@ -10,6 +10,7 @@ import dev.jorel.commandapi.CommandAPICommand
1010import dev.jorel.commandapi.SuggestionInfo
1111import dev.jorel.commandapi.arguments.Argument
1212import dev.jorel.commandapi.arguments.ArgumentSuggestions
13+ import dev.jorel.commandapi.arguments.IntegerArgument
1314import dev.jorel.commandapi.commandsenders.BukkitCommandSender
1415import dev.jorel.commandapi.executors.CommandArguments
1516import dev.jorel.commandapi.executors.CommandExecutionInfo
@@ -35,6 +36,13 @@ fun Argument<*>.suggestNullable(block: (SuggestionInfo<CommandSender>) -> Collec
3536inline fun <reified T : Any > CommandArguments.map (name : String , ifNull : () -> T ) = get(name) as ? T ? : ifNull()
3637inline fun <reified T : Any > CommandArguments.map (name : String , ifNull : T ) = get(name) as ? T ? : ifNull
3738inline fun <reified T : Any > CommandArguments.map (name : String ) = get(name) as T
39+ inline fun <reified T : Any > CommandArguments.any (name : String , block : (T ) -> Boolean ): Boolean {
40+ var success = false
41+ mapNullable<Collection <T >>(name)?.forEach {
42+ if (block(it)) success = true
43+ }
44+ return success
45+ }
3846inline fun <reified T : Any > CommandArguments.mapNullable (name : String ) = get(name) as ? T
3947inline fun <reified T : Any > CommandArguments.mapString (name : String , mapper : (String ) -> T ) = map<String >(name).let (mapper)
4048inline fun <reified T : Any > CommandArguments.mapNullableString (name : String , mapper : (String ) -> T ? ) = mapNullable<String >(name)?.let (mapper)
@@ -45,111 +53,119 @@ class CommandModule(
4553 parent : CommandModule ? ,
4654 private val delegate : CommandAPICommand
4755) : CommandExecutionInfo {
48- companion object {
49- private val upperLineMessage = componentOf(" ------ BetterModel ${PLUGIN .semver()} ------" ) {
50- color(GRAY )
51- }
52- private val underLineMessage = componentOf(" ----------------------------------" ) {
53- color(GRAY )
54- }
55- private val requiredMessage = componentOf(
56- " <arg>" .toComponent(RED ),
57- spaceComponentOf(),
58- " - required" .toComponent()
59- )
60- private val optionalMessage = componentOf(
61- " [arg]" .toComponent(DARK_AQUA ),
62- spaceComponentOf(),
63- " - optional" .toComponent()
56+ private companion object {
57+ const val PAGE_SPLIT_INDEX = 6
58+
59+ val prefix = listOf (
60+ emptyComponentOf(),
61+ " ------ BetterModel ${PLUGIN .semver()} ------" .toComponent(GRAY ),
62+ emptyComponentOf()
6463 )
65- private val usefulLinks = componentOf {
66- decorate(TextDecoration .BOLD )
67- append(spaceComponentOf())
68- append(componentOf(" [Wiki]" ) {
69- color(AQUA )
70- toURLComponent(" https://github.com/toxicity188/BetterModel/wiki" )
71- })
72- append(spaceComponentOf())
73- append(componentOf(" [Download]" ) {
74- color(GREEN )
75- toURLComponent(" https://modrinth.com/plugin/bettermodel/versions" )
76- })
77- append(spaceComponentOf())
78- append(componentOf(" [Discord]" ) {
79- color(BLUE )
80- toURLComponent(" https://discord.com/invite/rePyFESDbk" )
81- })
82- }
8364
84- private fun TextComponent.Builder.toURLComponent (url : String ) = hoverEvent(HoverEvent .showText(componentOf(
65+ val fullPrefix = listOf (
66+ prefix,
67+ listOf (
68+ componentOf {
69+ decorate(TextDecoration .BOLD )
70+ append(spaceComponentOf())
71+ append(componentOf(" [Wiki]" ) {
72+ color(AQUA )
73+ toURLComponent(" https://github.com/toxicity188/BetterModel/wiki" )
74+ })
75+ append(spaceComponentOf())
76+ append(componentOf(" [Download]" ) {
77+ color(GREEN )
78+ toURLComponent(" https://modrinth.com/plugin/bettermodel/versions" )
79+ })
80+ append(spaceComponentOf())
81+ append(componentOf(" [Discord]" ) {
82+ color(BLUE )
83+ toURLComponent(" https://discord.com/invite/rePyFESDbk" )
84+ })
85+ },
86+ emptyComponentOf(),
87+ componentOf(
88+ " <arg>" .toComponent(RED ),
89+ spaceComponentOf(),
90+ " - required" .toComponent()
91+ ),
92+ componentOf(
93+ " [arg]" .toComponent(DARK_AQUA ),
94+ spaceComponentOf(),
95+ " - optional" .toComponent()
96+ ),
97+ emptyComponentOf()
98+ )
99+ ).flatten()
100+
101+ fun TextComponent.Builder.toURLComponent (url : String ) = hoverEvent(HoverEvent .showText(componentOf(
85102 url.toComponent(DARK_AQUA ),
86103 lineComponentOf(),
87104 lineComponentOf(),
88105 " Click to open link." .toComponent()
89106 ))).clickEvent(ClickEvent .openUrl(url))
90107
91- private val CommandAPICommand .shortName get() = if (aliases.isNotEmpty()) aliases.first() else name
108+ val CommandAPICommand .shortName: String get() = if (aliases.isNotEmpty()) aliases.first() else name
92109
93- private fun String.toTypeName () = lowercase().replace(' _' , ' ' )
110+ fun String.toTypeName () = lowercase().replace(' _' , ' ' )
94111 }
95112
96113 private val rootName: String = parent?.let { " ${it.rootName} ${delegate.name} " } ? : delegate.shortName
97114 private val rootPermission: String = parent?.let { " ${it.rootPermission} .${delegate.name} " } ? : delegate.name
115+
116+ private val rootNameComponent = " /$rootName " .toComponent(YELLOW )
117+ private val sub = mutableMapOf<String , CommandAPICommand >()
118+ private val maxPage get() = sub.size / PAGE_SPLIT_INDEX + 1
119+ private val helpComponentRange get() = 1 .. maxPage
98120 private val helpComponents by lazy {
99- mutableListOf (
100- emptyComponentOf(),
101- upperLineMessage,
102- emptyComponentOf(),
103- usefulLinks,
104- emptyComponentOf(),
105- requiredMessage,
106- optionalMessage,
107- emptyComponentOf(),
108- ).apply {
109- sub.sortedBy {
110- it.name
111- }.forEach {
112- add(it.toComponent())
113- }
114- add(underLineMessage)
115- add(emptyComponentOf())
116- }.toTypedArray()
121+ helpComponentRange.map { index ->
122+ (if (index == 1 ) fullPrefix else prefix).toMutableList()
123+ .also { list ->
124+ sub.values.toList().subList(PAGE_SPLIT_INDEX * (index - 1 ), (PAGE_SPLIT_INDEX * index).coerceAtMost(sub.size)).forEach {
125+ list + = it.toComponent()
126+ }
127+ list + = " /$rootName [help] [page] - help command." .toComponent(LIGHT_PURPLE )
128+ list + = emptyComponentOf()
129+ list + = " ---------< Page $index / $maxPage >---------" .toComponent(GRAY )
130+ }.toTypedArray()
131+ }
117132 }
133+ private val pageArgs get() = IntegerArgument (" page" )
118134
119135 init {
120136 delegate.withPermission(rootPermission)
137+ command(" help" ) {
138+ withAliases(" h" )
139+ withOptionalArguments(pageArgs.suggest { helpComponentRange.map(Any ::toString) })
140+ withShortDescription(" shows help command to player." )
141+ executes(this @CommandModule)
142+ }
121143 }
122144
123- private fun CommandAPICommand.autoPermission () = withPermission(" $rootPermission .$name " )
124- private val sub = mutableListOf (
125- CommandAPICommand (" help" )
126- .withAliases(" h" )
127- .withShortDescription(" shows help command to player." )
128- .autoPermission()
129- .executes(this )
130- )
131-
132145 fun command (name : String , block : CommandAPICommand .() -> Unit ): CommandModule {
133- sub.add( CommandAPICommand (name)
134- .autoPermission( )
146+ sub[name] = CommandAPICommand (name)
147+ .withPermission( " $rootPermission . $name " )
135148 .apply (block)
136- )
137149 return this
138150 }
139151
140152 fun commandModule (name : String , block : CommandAPICommand .() -> Unit ) = CommandModule (this , CommandAPICommand (name).apply (block))
141153
142154 fun build (): CommandAPICommand = delegate
143- .withSubcommands(* sub.toTypedArray())
155+ .withOptionalArguments(pageArgs)
156+ .withSubcommands(* sub.values.toTypedArray())
144157 .executes(this )
145158
146159
147160 override fun run (info : ExecutionInfo <CommandSender , BukkitCommandSender <out CommandSender >>) {
148- info.sender().audience().info(* helpComponents)
161+ val page = (info.args().mapNullable<Int >(" page" ) ? : 1 )
162+ .coerceAtLeast(1 )
163+ .coerceAtMost(sub.size / PAGE_SPLIT_INDEX + 1 )
164+ info.sender().audience().info(* helpComponents[page - 1 ])
149165 }
150166
151167 private fun CommandAPICommand.toComponent () = componentOf {
152- append(" / $rootName " .toComponent( YELLOW ) )
168+ append(rootNameComponent )
153169 append(spaceComponentOf())
154170 append(name.toComponent())
155171 append(arguments.map {
0 commit comments