feat: Add party commands
This commit is contained in:
9
src/main/kotlin/events/PartyMessageReceivedEvent.kt
Normal file
9
src/main/kotlin/events/PartyMessageReceivedEvent.kt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
|
data class PartyMessageReceivedEvent(
|
||||||
|
val from: ProcessChatEvent,
|
||||||
|
val message: String,
|
||||||
|
val name: String,
|
||||||
|
) : FirmamentEvent() {
|
||||||
|
companion object : FirmamentEventBus<PartyMessageReceivedEvent>()
|
||||||
|
}
|
||||||
134
src/main/kotlin/features/chat/PartyCommands.kt
Normal file
134
src/main/kotlin/features/chat/PartyCommands.kt
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package moe.nea.firmament.features.chat
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher
|
||||||
|
import com.mojang.brigadier.StringReader
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException
|
||||||
|
import com.mojang.brigadier.tree.LiteralCommandNode
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import moe.nea.firmament.annotations.Subscribe
|
||||||
|
import moe.nea.firmament.commands.CaseInsensitiveLiteralCommandNode
|
||||||
|
import moe.nea.firmament.commands.thenExecute
|
||||||
|
import moe.nea.firmament.events.CommandEvent
|
||||||
|
import moe.nea.firmament.events.PartyMessageReceivedEvent
|
||||||
|
import moe.nea.firmament.events.ProcessChatEvent
|
||||||
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
|
import moe.nea.firmament.util.ErrorUtil
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.TimeMark
|
||||||
|
import moe.nea.firmament.util.tr
|
||||||
|
import moe.nea.firmament.util.useMatch
|
||||||
|
|
||||||
|
object PartyCommands {
|
||||||
|
|
||||||
|
val messageInChannel = "(?<channel>Party|Guild) >([^:]+?)? (?<name>[^: ]+): (?<message>.+)".toPattern()
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun onChat(event: ProcessChatEvent) {
|
||||||
|
messageInChannel.useMatch(event.unformattedString) {
|
||||||
|
val channel = group("channel")
|
||||||
|
val message = group("message")
|
||||||
|
val name = group("name")
|
||||||
|
if (channel == "Party") {
|
||||||
|
PartyMessageReceivedEvent.publish(PartyMessageReceivedEvent(
|
||||||
|
event, message, name
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commandPrefixes = "!-?$.&#+~€\"@°_;:³²`'´ß\\,|".toSet()
|
||||||
|
|
||||||
|
data class PartyCommandContext(
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
|
|
||||||
|
val dispatch = CommandDispatcher<PartyCommandContext>().also { dispatch ->
|
||||||
|
fun register(
|
||||||
|
name: String,
|
||||||
|
vararg alias: String,
|
||||||
|
block: CaseInsensitiveLiteralCommandNode.Builder<PartyCommandContext>.() -> Unit = {},
|
||||||
|
): LiteralCommandNode<PartyCommandContext> {
|
||||||
|
val node =
|
||||||
|
dispatch.register(CaseInsensitiveLiteralCommandNode.Builder<PartyCommandContext>(name).also(block))
|
||||||
|
alias.forEach { register(it) { redirect(node) } }
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
register("warp", "pw", "pwarp", "partywarp") {
|
||||||
|
executes {
|
||||||
|
// TODO: add check if you are the party leader
|
||||||
|
MC.sendCommand("p warp")
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register("transfer", "pt", "ptme") {
|
||||||
|
executes {
|
||||||
|
MC.sendCommand("p transfer ${it.source.name}")
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register("allinvite", "allinv") {
|
||||||
|
executes {
|
||||||
|
MC.sendCommand("p settings allinvite")
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register("coords") {
|
||||||
|
executes {
|
||||||
|
val p = MC.player?.blockPos ?: BlockPos.ORIGIN
|
||||||
|
MC.sendCommand("pc x: ${p.x}, y: ${p.y}, z: ${p.z}")
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: downtime tracker (display message again at end of dungeon)
|
||||||
|
// instance ends: kuudra, dungeons, bacte
|
||||||
|
// TODO: at TPS command
|
||||||
|
}
|
||||||
|
|
||||||
|
object TConfig : ManagedConfig("party-commands", Category.CHAT) {
|
||||||
|
val enable by toggle("enable") { false }
|
||||||
|
val cooldown by duration("cooldown", 0.seconds, 20.seconds) { 2.seconds }
|
||||||
|
val ignoreOwnCommands by toggle("ignore-own") { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastCommand = TimeMark.farPast()
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun listPartyCommands(event: CommandEvent.SubCommand) {
|
||||||
|
event.subcommand("partycommands") {
|
||||||
|
thenExecute {
|
||||||
|
// TODO: Better help, including descriptions and redirect detection
|
||||||
|
MC.sendChat(tr("firmament.partycommands.help", "Available party commands: ${dispatch.root.children.map { it.name }}. Available prefixes: $commandPrefixes"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
fun onPartyMessage(event: PartyMessageReceivedEvent) {
|
||||||
|
if (!TConfig.enable) return
|
||||||
|
if (event.message.firstOrNull() !in commandPrefixes) return
|
||||||
|
if (event.name == MC.playerName && TConfig.ignoreOwnCommands) return
|
||||||
|
if (lastCommand.passedTime() < TConfig.cooldown) {
|
||||||
|
MC.sendChat(tr("firmament.partycommands.cooldown", "Skipping party command. Cooldown not passed."))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: add trust levels
|
||||||
|
val commandLine = event.message.substring(1)
|
||||||
|
try {
|
||||||
|
dispatch.execute(StringReader(commandLine), PartyCommandContext(event.name))
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
if (ex is CommandSyntaxException) {
|
||||||
|
MC.sendChat(tr("firmament.partycommands.unknowncommand", "Unknown party command."))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
MC.sendChat(tr("firmament.partycommands.unknownerror", "Unknown error during command execution."))
|
||||||
|
ErrorUtil.softError("Unknown error during command execution.", ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastCommand = TimeMark.now()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,6 +64,8 @@ object MC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun sendCommand(command: String) {
|
fun sendCommand(command: String) {
|
||||||
|
// TODO: add a queue to this and sendServerChat
|
||||||
|
ErrorUtil.softCheck("Server commands have an implied /", !command.startsWith("/"))
|
||||||
player?.networkHandler?.sendCommand(command)
|
player?.networkHandler?.sendCommand(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,8 +98,9 @@ object MC {
|
|||||||
inline val camera: Entity? get() = instance.cameraEntity
|
inline val camera: Entity? get() = instance.cameraEntity
|
||||||
inline val guiAtlasManager get() = instance.guiAtlasManager
|
inline val guiAtlasManager get() = instance.guiAtlasManager
|
||||||
inline val world: ClientWorld? get() = TestUtil.unlessTesting { instance.world }
|
inline val world: ClientWorld? get() = TestUtil.unlessTesting { instance.world }
|
||||||
|
inline val playerName: String? get() = player?.name?.unformattedString
|
||||||
inline var screen: Screen?
|
inline var screen: Screen?
|
||||||
get() = TestUtil.unlessTesting{ instance.currentScreen }
|
get() = TestUtil.unlessTesting { instance.currentScreen }
|
||||||
set(value) = instance.setScreen(value)
|
set(value) = instance.setScreen(value)
|
||||||
val screenName get() = screen?.title?.unformattedString?.trim()
|
val screenName get() = screen?.title?.unformattedString?.trim()
|
||||||
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
|
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
|
||||||
|
|||||||
@@ -129,6 +129,13 @@
|
|||||||
"firmament.config.item-rarity-cosmetics.background-hotbar": "Hotbar Background Rarity",
|
"firmament.config.item-rarity-cosmetics.background-hotbar": "Hotbar Background Rarity",
|
||||||
"firmament.config.item-rarity-cosmetics.background-hotbar.description": "Show item rarity background in the hotbar.",
|
"firmament.config.item-rarity-cosmetics.background-hotbar.description": "Show item rarity background in the hotbar.",
|
||||||
"firmament.config.item-rarity-cosmetics.background.description": "Show a background behind each item, depending on its rarity.",
|
"firmament.config.item-rarity-cosmetics.background.description": "Show a background behind each item, depending on its rarity.",
|
||||||
|
"firmament.config.party-commands": "Party Commands",
|
||||||
|
"firmament.config.party-commands.cooldown": "Cooldown",
|
||||||
|
"firmament.config.party-commands.cooldown.description": "Prevent people from spamming commands with a delay between party commands.",
|
||||||
|
"firmament.config.party-commands.enable": "Enable Party Commands",
|
||||||
|
"firmament.config.party-commands.enable.description": "Allow people in your party to use commands like !warp, !coords, !ptme and so on. See /firm partycommands for a list",
|
||||||
|
"firmament.config.party-commands.ignore-own": "Ignore Own Messages",
|
||||||
|
"firmament.config.party-commands.ignore-own.description": "Prevent your own messages from triggering party commands",
|
||||||
"firmament.config.pets": "Pets",
|
"firmament.config.pets": "Pets",
|
||||||
"firmament.config.pets.highlight-pet": "Highlight active pet",
|
"firmament.config.pets.highlight-pet": "Highlight active pet",
|
||||||
"firmament.config.pets.highlight-pet.description": "Highlight your currently selected pet in the /pets menu.",
|
"firmament.config.pets.highlight-pet.description": "Highlight your currently selected pet in the /pets menu.",
|
||||||
|
|||||||
Reference in New Issue
Block a user