-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
946 additions
and
827 deletions.
There are no files selected for viewing
153 changes: 153 additions & 0 deletions
153
src/main/kotlin/com/github/zly2006/enclosure/command/AdminSubcommand.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package com.github.zly2006.enclosure.command | ||
|
||
import com.github.zly2006.enclosure.ServerMain | ||
import com.github.zly2006.enclosure.access.PlayerAccess | ||
import com.github.zly2006.enclosure.network.config.EnclosureInstalledC2SPacket | ||
import com.github.zly2006.enclosure.utils.Permission | ||
import com.github.zly2006.enclosure.utils.Serializable2Text.SerializationSettings | ||
import com.github.zly2006.enclosure.utils.TrT | ||
import com.github.zly2006.enclosure.utils.Utils | ||
import com.github.zly2006.enclosure.utils.plus | ||
import com.mojang.brigadier.arguments.StringArgumentType | ||
import net.minecraft.command.argument.EntityArgumentType | ||
import net.minecraft.text.ClickEvent | ||
import net.minecraft.text.Text | ||
import net.minecraft.util.math.BlockPos | ||
|
||
fun BuilderScope<*>.registerAdmin() { | ||
literal("admin") { | ||
literal("reload") { | ||
permission("enclosure.command.admin.reload", BuilderScope.Companion.DefaultPermission.OP) | ||
literal("all") { | ||
executes { | ||
ServerMain.reloadCommon() | ||
ServerMain.reloadLimits() | ||
source.sendMessage(Text.literal("Reloaded, some config may not affect until restart")) | ||
} | ||
} | ||
literal("common") { | ||
executes { | ||
ServerMain.reloadCommon() | ||
source.sendMessage(Text.literal("Reloaded, some config may not affect until restart")) | ||
} | ||
} | ||
literal("limits") { | ||
executes { | ||
ServerMain.reloadLimits() | ||
source.sendMessage(Text.literal("Reloaded, some config may not affect until restart")) | ||
} | ||
} | ||
} | ||
literal("limit_exceeded") { | ||
permission("enclosure.command.admin.limit_exceeded", BuilderScope.Companion.DefaultPermission.OP) | ||
literal("size") { | ||
executes { | ||
ServerMain.getAllEnclosures().flatMap { | ||
it.subEnclosures.areas.toList() + it | ||
}.map { | ||
val session = Session(null) | ||
session.pos1 = BlockPos(it.minX, it.minY, it.minZ) | ||
session.pos2 = BlockPos(it.maxX, it.maxY, it.maxZ) | ||
it to session.isValid(getLimits(this)) | ||
}.filter { it.second != null }.forEach { (area, text) -> | ||
source.sendMessage( | ||
Text.literal("Enclosure ") | ||
.append(area.serialize(SerializationSettings.Name, source.player)) | ||
.append(" is too large: ") | ||
.append(text) | ||
) | ||
} | ||
} | ||
} | ||
literal("count") { | ||
executes { | ||
ServerMain.getAllEnclosures().groupBy { | ||
it.owner | ||
}.forEach { (owner, enclosures) -> | ||
if (enclosures.size > getLimits(this).maxLands) { | ||
source.sendMessage( | ||
Text.literal("Player ") + | ||
Utils.getDisplayNameByUUID(owner) + | ||
" has too many enclosures: " + | ||
enclosures.size.toString() | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
literal("visited") { | ||
permission("enclosure.command.admin.visited", BuilderScope.Companion.DefaultPermission.OP) | ||
argument("player", EntityArgumentType.player()) { | ||
literal("get") { | ||
executes { | ||
val player = EntityArgumentType.getPlayer(this, "player") | ||
val visited = ServerMain.getAllEnclosures() | ||
.filter { it.uuid in (player as PlayerAccess).visitedEnclosures } | ||
val text = player.name.copy().append(" visited: ") | ||
visited.forEach { e -> | ||
text.append(e.serialize(SerializationSettings.Summarize, player)) | ||
.append(" ") | ||
} | ||
source.sendMessage(text) | ||
} | ||
} | ||
literal("clear") { | ||
executes { | ||
val player = EntityArgumentType.getPlayer(this, "player") | ||
(player as PlayerAccess).visitedEnclosures.clear() | ||
source.sendMessage(Text.literal("Cleared")) | ||
} | ||
} | ||
} | ||
} | ||
literal("closest") { | ||
permission("enclosure.command.admin.closest", BuilderScope.Companion.DefaultPermission.OP) | ||
executes { | ||
val enclosure = ServerMain.getAllEnclosures(source.world).areas | ||
.minByOrNull { | ||
it.distanceTo(source.position).horizontalLength() | ||
} | ||
if (enclosure == null) { | ||
source.sendMessage(Text.literal("No enclosure found")) | ||
} else { | ||
source.sendMessage( | ||
Text.literal("Closest enclosure: " + enclosure.fullName + ", click to show info") | ||
.styled { | ||
it.withClickEvent( | ||
ClickEvent( | ||
net.minecraft.text.ClickEvent.Action.RUN_COMMAND, | ||
"/enclosure info " + enclosure.fullName | ||
) | ||
) | ||
}) | ||
} | ||
} | ||
} | ||
literal("perm-info") { | ||
permission("enclosure.command.admin.perm_info", BuilderScope.Companion.DefaultPermission.OP) | ||
argument(permissionArgument(com.github.zly2006.enclosure.utils.Permission.Target.Both)) { | ||
executes { | ||
val permission = Permission.getValue(StringArgumentType.getString(this, "permission")) | ||
?: error(TrT.of("enclosure.message.invalid_permission"), this) | ||
source.sendMessage( | ||
Text.literal("Name: ${permission.name} Target: ${permission.target}\nDescription: ") + permission.description + Text.literal( | ||
"\nDefault: ${permission.defaultValue}\nComponents: ${permission.permissions.joinToString()}" | ||
) | ||
) | ||
} | ||
} | ||
} | ||
literal("clients") { | ||
permission("enclosure.command.admin.clients", BuilderScope.Companion.DefaultPermission.OP) | ||
executes { | ||
EnclosureInstalledC2SPacket.installedClientMod.forEach { | ||
source.sendMessage( | ||
source.server.playerManager.getPlayer(it.key)!!.name.copy() | ||
.append(Text.literal(": " + it.value.friendlyString)) | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} |
191 changes: 191 additions & 0 deletions
191
src/main/kotlin/com/github/zly2006/enclosure/command/BuilderScope.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
package com.github.zly2006.enclosure.command | ||
|
||
import com.github.zly2006.enclosure.EnclosureArea | ||
import com.github.zly2006.enclosure.LOGGER | ||
import com.github.zly2006.enclosure.ServerMain | ||
import com.github.zly2006.enclosure.exceptions.PermissionTargetException | ||
import com.github.zly2006.enclosure.minecraftServer | ||
import com.github.zly2006.enclosure.utils.TrT | ||
import com.github.zly2006.enclosure.utils.checkPermission | ||
import com.github.zly2006.enclosure.utils.hoverText | ||
import com.mojang.brigadier.Command | ||
import com.mojang.brigadier.arguments.ArgumentType | ||
import com.mojang.brigadier.arguments.IntegerArgumentType | ||
import com.mojang.brigadier.builder.RequiredArgumentBuilder | ||
import com.mojang.brigadier.context.CommandContext | ||
import com.mojang.brigadier.exceptions.CommandSyntaxException | ||
import net.minecraft.server.command.CommandManager | ||
import net.minecraft.server.command.ServerCommandSource | ||
import net.minecraft.text.* | ||
import net.minecraft.util.Formatting | ||
import net.minecraft.util.math.BlockPos | ||
|
||
class BuilderScope<T: argT>(var parent: T) { | ||
fun literal(name: String, action: BuilderScope<*>.() -> Unit) { | ||
val node = CommandManager.literal(name) | ||
BuilderScope(node).apply(action) | ||
parent.then(node) | ||
} | ||
|
||
fun argument(name: String, type: ArgumentType<*>, action: BuilderScope<*>.() -> Unit) { | ||
val node = CommandManager.argument(name, type) | ||
argument(node, action) | ||
} | ||
|
||
fun argument(node: RequiredArgumentBuilder<ServerCommandSource, *>, action: BuilderScope<*>.() -> Unit) { | ||
BuilderScope(node).apply(action) | ||
parent.then(node) | ||
} | ||
|
||
fun executes(action: CommandContext<ServerCommandSource>.() -> Unit) { | ||
parent.executes { | ||
try { | ||
action(it) | ||
1 | ||
} catch (e: PermissionTargetException) { | ||
error(e.text, it) | ||
} catch (e: CommandSyntaxException) { | ||
throw e | ||
} catch (e: Exception) { | ||
LOGGER.error("Error while executing command: " + it.input, e) | ||
error(TrT.of("enclosure.message.error").append(e.message), it) | ||
} | ||
} | ||
} | ||
|
||
fun paged(commandSupplier: CommandContext<ServerCommandSource>.() -> String? = { null }, listSupplier: CommandContext<ServerCommandSource>.() -> List<Text>) { | ||
val size = 5 | ||
val action: CommandContext<ServerCommandSource>.(Int) -> Unit = { p -> | ||
val command = commandSupplier() | ||
val list = listSupplier() | ||
val totalPage: Int = (list.size + size - 1) / size | ||
var page = p | ||
if (p < 1 || p > totalPage) { // 如果选取页码超过范围限制,则采用第一页 | ||
page = 1 | ||
} | ||
val firstPage = page == 1 | ||
val lastPage = page >= totalPage | ||
|
||
val ret: MutableText = TrT.of("enclosure.menu.page.0") | ||
.append(page.toString()) | ||
.append(TrT.of("enclosure.menu.page.1")) | ||
.append(totalPage.toString()) | ||
.append("\n") | ||
|
||
var i: Int = size * (page - 1) | ||
while (i < size * page && i < list.size) { | ||
ret.append(list[i]) | ||
ret.append("\n") | ||
i++ | ||
} | ||
|
||
if (command != null) { | ||
ret.append( | ||
TrT.of("enclosure.menu.previous").setStyle( | ||
if (firstPage) Style.EMPTY.withColor(Formatting.GRAY) | ||
else Style.EMPTY.withColor(Formatting.DARK_GREEN) | ||
.hoverText(Text.of("Page ${page - 1}")) | ||
.withClickEvent(ClickEvent(ClickEvent.Action.RUN_COMMAND, "$command ${page - 1}")) | ||
) | ||
) | ||
ret.append(" ") | ||
ret.append( | ||
TrT.of("enclosure.menu.next").setStyle( | ||
if (lastPage) Style.EMPTY.withColor(Formatting.GRAY) | ||
else Style.EMPTY.withColor(Formatting.DARK_GREEN) | ||
.withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.of("Page ${page + 1}"))) | ||
.withClickEvent(ClickEvent(ClickEvent.Action.RUN_COMMAND, "$command ${page + 1}")) | ||
) | ||
) | ||
} | ||
source.sendMessage(ret) | ||
} | ||
executes { action(0) } | ||
argument("page", IntegerArgumentType.integer(0)) { | ||
executes { | ||
action(IntegerArgumentType.getInteger(this, "page")) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @param action 传入参数表示是否包含[node] | ||
*/ | ||
private fun optionalNode(node: argT, action: BuilderScope<*>.(Boolean) -> Unit) { | ||
BuilderScope(node).apply { action(true) } | ||
parent.then(node) | ||
BuilderScope(parent).apply { action(false) } | ||
} | ||
|
||
fun optionalEnclosure(action: CommandContext<ServerCommandSource>.(EnclosureArea) -> Unit) { | ||
optionalNode(landArgument()) { | ||
executes { | ||
if (it) { | ||
val enclosure = getEnclosure(this) | ||
action(enclosure) | ||
} else { | ||
val blockPos = BlockPos.ofFloored(source.position) | ||
ServerMain.getSmallestEnclosure(source.world, blockPos) | ||
?.let { action(it) } | ||
?: error(TrT.of("enclosure.message.no_enclosure"), this) | ||
} | ||
} | ||
} | ||
} | ||
|
||
fun optionalEnclosure(action: CommandContext<ServerCommandSource>.(EnclosureArea) -> Unit, builder: (argT, Command<ServerCommandSource>) -> Unit) { | ||
optionalEnclosure(listOf(0), { _, c -> builder(parent, c) }) { a, _ -> action(a) } | ||
} | ||
|
||
fun <T: Any?> optionalEnclosure(list: List<T>, builder: BuilderScope<*>.(T, Command<ServerCommandSource>) -> Unit, action: CommandContext<ServerCommandSource>.(EnclosureArea, T) -> Unit) { | ||
list.forEach { t -> | ||
val node = landArgument() | ||
BuilderScope(node).apply { | ||
builder(t, Command { | ||
val enclosure = getEnclosure(it) | ||
it.action(enclosure, t) | ||
1 | ||
}) | ||
} | ||
BuilderScope(parent).apply { | ||
builder(t, Command { | ||
val blockPos = BlockPos.ofFloored(it.source.position) | ||
ServerMain.getSmallestEnclosure(it.source.world, blockPos) | ||
?.let { area -> action(it, area, t) } | ||
?: error(TrT.of("enclosure.message.no_enclosure"), it) | ||
1 | ||
}) | ||
} | ||
parent.then(node) | ||
} | ||
} | ||
|
||
|
||
companion object { | ||
enum class DefaultPermission { | ||
TRUE, FALSE, OP; | ||
|
||
fun get(source: ServerCommandSource) = | ||
when (this) { | ||
TRUE -> true | ||
FALSE -> false | ||
OP -> source.hasPermissionLevel( | ||
if (minecraftServer.isSingleplayer) 2 else 4 // 2 for LAN, 4 for normal | ||
) | ||
} | ||
} | ||
|
||
val map = mutableMapOf<String, DefaultPermission>( | ||
"enclosure.bypass" to DefaultPermission.OP | ||
) | ||
} | ||
fun permission(s: String, defaultPermission: DefaultPermission) { | ||
val old = parent.requirement | ||
if (!map.containsKey(s)) { | ||
map[s] = defaultPermission | ||
} | ||
parent.requires { source -> | ||
checkPermission(source, s) && old.test(source) | ||
} | ||
} | ||
} |
Oops, something went wrong.