mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-19 12:25:12 -04:00
connection commands
This commit is contained in:
parent
30bfd53466
commit
f3dc3219a0
@ -19,4 +19,4 @@ abstract class ReaderError(
|
|||||||
val reader: CommandReader,
|
val reader: CommandReader,
|
||||||
val start: Int,
|
val start: Int,
|
||||||
val end: Int,
|
val end: Int,
|
||||||
) : Exception("Error at $start-$end: ${reader.string} (at ${reader.string.substring(start, end)}")
|
) : Exception("Error at $start-$end: ${reader.string} (at ${reader.string.substring(start, end)})")
|
||||||
|
@ -83,4 +83,8 @@ abstract class CommandNode(
|
|||||||
}
|
}
|
||||||
return suggestions
|
return suggestions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
children.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,19 @@ package de.bixilon.minosoft.commands.nodes
|
|||||||
import de.bixilon.minosoft.commands.nodes.builder.CommandNodeBuilder
|
import de.bixilon.minosoft.commands.nodes.builder.CommandNodeBuilder
|
||||||
import de.bixilon.minosoft.commands.stack.CommandStack
|
import de.bixilon.minosoft.commands.stack.CommandStack
|
||||||
import de.bixilon.minosoft.commands.util.CommandReader
|
import de.bixilon.minosoft.commands.util.CommandReader
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
|
||||||
class RootNode : CommandNode {
|
class RootNode : CommandNode {
|
||||||
|
|
||||||
constructor() : super(false, null)
|
constructor() : super(false, null)
|
||||||
constructor(builder: CommandNodeBuilder) : super(builder.executable, null)
|
constructor(builder: CommandNodeBuilder) : super(builder.executable, null)
|
||||||
|
|
||||||
fun execute(command: String) {
|
fun execute(command: String, connection: PlayConnection? = null) {
|
||||||
execute(CommandReader(command), CommandStack())
|
val stack = CommandStack()
|
||||||
|
if (connection != null) {
|
||||||
|
stack.connection = connection
|
||||||
|
}
|
||||||
|
execute(CommandReader(command), stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSuggestions(command: String): List<Any?> {
|
fun getSuggestions(command: String): List<Any?> {
|
||||||
|
@ -21,6 +21,7 @@ import de.bixilon.minosoft.commands.parser.minecraft.target.targets.selector.pro
|
|||||||
import de.bixilon.minosoft.commands.parser.minecraft.target.targets.selector.properties.rotation.YawRotation
|
import de.bixilon.minosoft.commands.parser.minecraft.target.targets.selector.properties.rotation.YawRotation
|
||||||
import de.bixilon.minosoft.commands.parser.minecraft.target.targets.selector.properties.sort.SortProperty
|
import de.bixilon.minosoft.commands.parser.minecraft.target.targets.selector.properties.sort.SortProperty
|
||||||
|
|
||||||
|
// See https://minecraft.fandom.com/wiki/Target_selectors
|
||||||
object TargetProperties {
|
object TargetProperties {
|
||||||
val properties: MutableMap<String, TargetPropertyFactory<*>> = mutableMapOf()
|
val properties: MutableMap<String, TargetPropertyFactory<*>> = mutableMapOf()
|
||||||
|
|
||||||
|
@ -15,12 +15,14 @@ package de.bixilon.minosoft.commands.stack
|
|||||||
|
|
||||||
import de.bixilon.kutil.cast.CastUtil.nullCast
|
import de.bixilon.kutil.cast.CastUtil.nullCast
|
||||||
import de.bixilon.minosoft.data.entities.entities.Entity
|
import de.bixilon.minosoft.data.entities.entities.Entity
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
|
||||||
class CommandStack {
|
class CommandStack {
|
||||||
private val stack: MutableList<StackEntry> = mutableListOf()
|
private val stack: MutableList<StackEntry> = mutableListOf()
|
||||||
val size: Int get() = stack.size
|
val size: Int get() = stack.size
|
||||||
|
|
||||||
var executor: Entity? = null
|
var executor: Entity? = null
|
||||||
|
lateinit var connection: PlayConnection
|
||||||
|
|
||||||
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
|
||||||
inline operator fun <reified T> get(name: String): T? {
|
inline operator fun <reified T> get(name: String): T? {
|
||||||
|
@ -209,7 +209,7 @@ open class CommandReader(val string: String) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val string = string.substring(pointer, string.length)
|
val string = string.substring(pointer, string.length)
|
||||||
pointer = string.length
|
pointer = this.string.length
|
||||||
return string
|
return string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ import de.bixilon.minosoft.protocol.packets.c2s.handshaking.HandshakeC2SP
|
|||||||
import de.bixilon.minosoft.protocol.packets.c2s.login.StartC2SP
|
import de.bixilon.minosoft.protocol.packets.c2s.login.StartC2SP
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolStates
|
import de.bixilon.minosoft.protocol.protocol.ProtocolStates
|
||||||
import de.bixilon.minosoft.terminal.RunConfiguration
|
import de.bixilon.minosoft.terminal.RunConfiguration
|
||||||
|
import de.bixilon.minosoft.terminal.cli.CLI
|
||||||
import de.bixilon.minosoft.util.ServerAddress
|
import de.bixilon.minosoft.util.ServerAddress
|
||||||
import de.bixilon.minosoft.util.logging.Log
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
import de.bixilon.minosoft.util.logging.LogLevels
|
import de.bixilon.minosoft.util.logging.LogLevels
|
||||||
@ -119,6 +120,9 @@ class PlayConnection(
|
|||||||
assetsManager.unload()
|
assetsManager.unload()
|
||||||
state = PlayConnectionStates.DISCONNECTED
|
state = PlayConnectionStates.DISCONNECTED
|
||||||
ACTIVE_CONNECTIONS -= this
|
ACTIVE_CONNECTIONS -= this
|
||||||
|
if (CLI.connection === this) {
|
||||||
|
CLI.connection = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
network::state.observe(this) {
|
network::state.observe(this) {
|
||||||
@ -131,6 +135,10 @@ class PlayConnection(
|
|||||||
ProtocolStates.PLAY -> {
|
ProtocolStates.PLAY -> {
|
||||||
state = PlayConnectionStates.JOINING
|
state = PlayConnectionStates.JOINING
|
||||||
|
|
||||||
|
if (CLI.connection == null) {
|
||||||
|
CLI.connection = this
|
||||||
|
}
|
||||||
|
|
||||||
registerEvent(CallbackEventInvoker.of<ChatMessageReceiveEvent> {
|
registerEvent(CallbackEventInvoker.of<ChatMessageReceiveEvent> {
|
||||||
val additionalPrefix = when (it.type.position) {
|
val additionalPrefix = when (it.type.position) {
|
||||||
ChatTextPositions.SYSTEM -> "[SYSTEM] "
|
ChatTextPositions.SYSTEM -> "[SYSTEM] "
|
||||||
|
@ -14,16 +14,38 @@
|
|||||||
package de.bixilon.minosoft.terminal.cli
|
package de.bixilon.minosoft.terminal.cli
|
||||||
|
|
||||||
import de.bixilon.kutil.latch.CountUpAndDownLatch
|
import de.bixilon.kutil.latch.CountUpAndDownLatch
|
||||||
|
import de.bixilon.kutil.watcher.DataWatcher.Companion.observe
|
||||||
|
import de.bixilon.kutil.watcher.DataWatcher.Companion.watched
|
||||||
import de.bixilon.minosoft.ShutdownReasons
|
import de.bixilon.minosoft.ShutdownReasons
|
||||||
|
import de.bixilon.minosoft.commands.nodes.RootNode
|
||||||
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
import de.bixilon.minosoft.terminal.commands.Commands
|
import de.bixilon.minosoft.terminal.commands.Commands
|
||||||
|
import de.bixilon.minosoft.terminal.commands.ConnectionCommand
|
||||||
import de.bixilon.minosoft.util.ShutdownManager
|
import de.bixilon.minosoft.util.ShutdownManager
|
||||||
import org.jline.reader.*
|
import org.jline.reader.*
|
||||||
import org.jline.terminal.Terminal
|
import org.jline.terminal.Terminal
|
||||||
import org.jline.terminal.TerminalBuilder
|
import org.jline.terminal.TerminalBuilder
|
||||||
|
|
||||||
object CLI {
|
object CLI {
|
||||||
var connection: PlayConnection? = null
|
var connection: PlayConnection? by watched(null)
|
||||||
|
private val ROOT_NODE = RootNode()
|
||||||
|
|
||||||
|
init {
|
||||||
|
register()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
private fun register() {
|
||||||
|
ROOT_NODE.clear()
|
||||||
|
val connection = this.connection
|
||||||
|
|
||||||
|
for (command in Commands.COMMANDS) {
|
||||||
|
if (command is ConnectionCommand && connection == null) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ROOT_NODE.addChild(command.node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun startThread(latch: CountUpAndDownLatch) {
|
fun startThread(latch: CountUpAndDownLatch) {
|
||||||
@ -41,6 +63,9 @@ object CLI {
|
|||||||
.completer(NodeCompleter)
|
.completer(NodeCompleter)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
this::connection.observe(this) { register() }
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
val line: String = reader.readLine().removeDuplicatedWhitespaces()
|
val line: String = reader.readLine().removeDuplicatedWhitespaces()
|
||||||
@ -48,7 +73,7 @@ object CLI {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
terminal.flush()
|
terminal.flush()
|
||||||
Commands.ROOT_NODE.execute(line)
|
ROOT_NODE.execute(line, connection)
|
||||||
} catch (exception: UserInterruptException) {
|
} catch (exception: UserInterruptException) {
|
||||||
ShutdownManager.shutdown(reason = ShutdownReasons.ALL_FINE)
|
ShutdownManager.shutdown(reason = ShutdownReasons.ALL_FINE)
|
||||||
} catch (exception: Throwable) {
|
} catch (exception: Throwable) {
|
||||||
@ -64,7 +89,7 @@ object CLI {
|
|||||||
object NodeCompleter : Completer {
|
object NodeCompleter : Completer {
|
||||||
|
|
||||||
override fun complete(reader: LineReader, line: ParsedLine, candidates: MutableList<Candidate>) {
|
override fun complete(reader: LineReader, line: ParsedLine, candidates: MutableList<Candidate>) {
|
||||||
val suggestions = Commands.ROOT_NODE.getSuggestions(line.line())
|
val suggestions = ROOT_NODE.getSuggestions(line.line())
|
||||||
for (suggestion in suggestions) {
|
for (suggestion in suggestions) {
|
||||||
candidates += Candidate(suggestion.toString())
|
candidates += Candidate(suggestion.toString())
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,5 @@ package de.bixilon.minosoft.terminal.commands
|
|||||||
import de.bixilon.minosoft.commands.nodes.LiteralNode
|
import de.bixilon.minosoft.commands.nodes.LiteralNode
|
||||||
|
|
||||||
interface Command {
|
interface Command {
|
||||||
|
var node: LiteralNode
|
||||||
fun build(): LiteralNode
|
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,9 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.terminal.commands
|
package de.bixilon.minosoft.terminal.commands
|
||||||
|
|
||||||
import de.bixilon.minosoft.commands.nodes.RootNode
|
|
||||||
|
|
||||||
object Commands {
|
object Commands {
|
||||||
val ROOT_NODE = RootNode()
|
val COMMANDS: List<Command> = listOf(
|
||||||
.register(HelpCommand)
|
HelpCommand,
|
||||||
|
SayCommand,
|
||||||
fun RootNode.register(command: Command): RootNode {
|
)
|
||||||
this.addChild(command.build())
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.terminal.commands
|
||||||
|
|
||||||
|
interface ConnectionCommand : Command
|
@ -20,11 +20,8 @@ import de.bixilon.minosoft.commands.nodes.LiteralNode
|
|||||||
import de.bixilon.minosoft.commands.parser.minosoft.enums.EnumParser
|
import de.bixilon.minosoft.commands.parser.minosoft.enums.EnumParser
|
||||||
|
|
||||||
object HelpCommand : Command {
|
object HelpCommand : Command {
|
||||||
|
override var node: LiteralNode = LiteralNode("help", setOf("?"), executor = { printHelp() })
|
||||||
override fun build(): LiteralNode {
|
|
||||||
return LiteralNode("help", setOf("?"), executor = { printHelp() })
|
|
||||||
.addChild(ArgumentNode("subcommand", parser = EnumParser(HelpCommands), executor = { printHelp(it["subcommand"]!!) }))
|
.addChild(ArgumentNode("subcommand", parser = EnumParser(HelpCommands), executor = { printHelp(it["subcommand"]!!) }))
|
||||||
}
|
|
||||||
|
|
||||||
fun printHelp() {
|
fun printHelp() {
|
||||||
println("-------------- Minosoft help --------------")
|
println("-------------- Minosoft help --------------")
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.terminal.commands
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.commands.nodes.ArgumentNode
|
||||||
|
import de.bixilon.minosoft.commands.nodes.LiteralNode
|
||||||
|
import de.bixilon.minosoft.commands.parser.brigadier.string.StringParser
|
||||||
|
|
||||||
|
object SayCommand : ConnectionCommand {
|
||||||
|
override var node = LiteralNode("say", setOf("chat", "send", "write"))
|
||||||
|
.addChild(ArgumentNode("message", StringParser(StringParser.StringModes.GREEDY), executor = {
|
||||||
|
it.connection.util.sendChatMessage(it.get<String>("message")!!)
|
||||||
|
}))
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user