finished loading custom commands and permissions from file

This commit is contained in:
DaMachinator 2018-02-18 23:58:13 +01:00
parent 968ff1aacc
commit 6c5a381903
18 changed files with 148 additions and 128 deletions

View File

@ -1,8 +1,8 @@
package matterlink
import matterlink.command.CommandMatterlink
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.command.CommandMatterlink
import matterlink.command.MatterLinkCommandSender
import matterlink.config.cfg
import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler
@ -58,15 +58,10 @@ object MatterLink : IMatterLink() {
FMLCommonHandler.instance().minecraftServerInstance.playerList.sendChatMsg(TextComponentString(msg))
}
//FORGE-DEPENDENT
override fun wrappedPlayerList(): Array<String> {
return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames
}
override fun log(level: String, formatString: String, vararg data: Any) =
logger.log(Level.toLevel(level, Level.INFO), formatString, *data)
override var commandSender: IMinecraftCommandSender = MatterlinkCommandSender
override fun commandSenderFor(user: String, userId: String, server: String) = MatterLinkCommandSender(user, userId, server)
override val mcVersion: String = MCVERSION
override val modVersion: String = MODVERSION

View File

@ -16,7 +16,7 @@ import net.minecraft.world.World
import net.minecraftforge.fml.common.FMLCommonHandler
import javax.annotation.Nonnull
object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
class MatterLinkCommandSender(user: String, userId: String, server: String) : IMinecraftCommandSender(user, userId, server), ICommandSender {
private var level: Int = 0
override fun execute(cmdString: String): Boolean {
@ -27,20 +27,18 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
}
override fun getDisplayName(): ITextComponent {
return TextComponentString("MatterLink")
return TextComponentString(user)
}
override fun getName(): String {
return "MatterLink"
}
override fun getName() = accountName
override fun getEntityWorld(): World {
return FMLCommonHandler.instance().minecraftServerInstance.worldServerForDimension(0)
}
override fun canUseCommand(permLevel: Int, commandName: String?): Boolean {
override fun canUseCommand(permLevel: Int, commandName: String): Boolean {
//we check user on our end
return true
return canExecute(commandName)
}
override fun getServer(): MinecraftServer? {
@ -59,7 +57,6 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
return true
}
//WtfMojangWhy
override fun getPosition(): BlockPos = BlockPos.ORIGIN
override fun setCommandStat(type: CommandResultStats.Type?, amount: Int) {}

View File

@ -1,8 +1,8 @@
package matterlink
import matterlink.command.CommandMatterlink
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.command.CommandMatterlink
import matterlink.command.MatterLinkCommandSender
import matterlink.config.cfg
import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler
@ -58,15 +58,10 @@ object MatterLink : IMatterLink() {
FMLCommonHandler.instance().minecraftServerInstance.playerList.sendMessage(TextComponentString(msg))
}
//FORGE-DEPENDENT
override fun wrappedPlayerList(): Array<String> {
return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames
}
override fun log(level: String, formatString: String, vararg data: Any) =
logger.log(Level.toLevel(level, Level.INFO), formatString, *data)
override var commandSender: IMinecraftCommandSender = MatterlinkCommandSender
override fun commandSenderFor(user: String, userId: String, server: String) = MatterLinkCommandSender(user, userId, server)
override val mcVersion: String = MCVERSION
override val modVersion: String = MODVERSION

View File

@ -16,7 +16,7 @@ import net.minecraft.world.World
import net.minecraftforge.fml.common.FMLCommonHandler
import javax.annotation.Nonnull
object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
class MatterLinkCommandSender(user: String, userId: String, server: String) : IMinecraftCommandSender(user, userId, server), ICommandSender {
override fun execute(cmdString: String): Boolean {
return 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand(
@ -26,20 +26,18 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
}
override fun getDisplayName(): ITextComponent {
return TextComponentString("MatterLink")
return TextComponentString(user)
}
override fun getName(): String {
return "MatterLink"
}
override fun getName() = accountName
override fun getEntityWorld(): World {
return FMLCommonHandler.instance().minecraftServerInstance.getWorld(0)
}
override fun canUseCommand(permLevel: Int, commandName: String?): Boolean {
override fun canUseCommand(permLevel: Int, commandName: String): Boolean {
//we now do permissions checking on our end
return true
return canExecute(commandName)
}
override fun getServer(): MinecraftServer? {

View File

@ -1,8 +1,8 @@
package matterlink
import matterlink.command.CommandMatterlink
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.command.CommandMatterlink
import matterlink.command.MatterLinkCommandSender
import matterlink.config.cfg
import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler
@ -63,15 +63,11 @@ object MatterLink : IMatterLink() {
FMLCommonHandler.instance().minecraftServerInstance.playerList.sendMessage(TextComponentString(msg))
}
//FORGE-DEPENDENT
override fun wrappedPlayerList(): Array<String> {
return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames
}
override fun log(level: String, formatString: String, vararg data: Any) =
logger.log(Level.toLevel(level, Level.INFO), formatString, *data)
override var commandSender: IMinecraftCommandSender = MatterlinkCommandSender
override fun commandSenderFor(user: String, userId: String, server: String) = MatterLinkCommandSender(user, userId, server)
override val mcVersion: String = MCVERSION
override val modVersion: String = MODVERSION
}

View File

@ -7,11 +7,12 @@ import matterlink.config.cfg
import net.minecraft.command.ICommandSender
import net.minecraft.server.MinecraftServer
import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.TextComponentString
import net.minecraft.world.World
import net.minecraftforge.fml.common.FMLCommonHandler
import javax.annotation.Nonnull
object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
class MatterLinkCommandSender(user: String, userId: String, server: String) : IMinecraftCommandSender(user, userId, server), ICommandSender {
override fun execute(cmdString: String): Boolean {
return 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand(
@ -20,17 +21,19 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
)
}
override fun getName(): String {
return "MatterLink"
override fun getDisplayName(): ITextComponent {
return TextComponentString(user)
}
override fun getName() = accountName
override fun getEntityWorld(): World {
return FMLCommonHandler.instance().minecraftServerInstance.getWorld(0)
}
override fun canUseCommand(permLevel: Int, commandName: String?): Boolean {
override fun canUseCommand(permLevel: Int, commandName: String): Boolean {
//permissions are checked on our end
return true
return canExecute(commandName)
}
override fun getServer(): MinecraftServer? {

View File

@ -5,7 +5,7 @@ import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.*
import matterlink.command.CommandMatterlink
import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.command.MatterlinkCommandSender
import matterlink.command.MatterLinkCommandSender
import matterlink.config.cfg
import net.minecraft.server.MinecraftServer
import net.minecraft.util.ChatComponentText
@ -60,15 +60,10 @@ class MatterLink : IMatterLink() {
MinecraftServer.getServer().addChatMessage(ChatComponentText(msg));
}
//FORGE-DEPENDENT
override fun wrappedPlayerList(): Array<String> {
return MinecraftServer.getServer().allUsernames
}
override fun log(level: String, formatString: String, vararg data: Any) =
logger.log(Level.toLevel(level, Level.INFO), formatString, *data)
override var commandSender: IMinecraftCommandSender = MatterlinkCommandSender
override fun commandSenderFor(user: String, userId: String, server: String) = MatterLinkCommandSender(user, userId, server)
override val mcVersion: String = MCVERSION
override val modVersion: String = MODVERSION

View File

@ -11,7 +11,7 @@ import net.minecraft.util.ChunkCoordinates
import net.minecraft.util.IChatComponent
import net.minecraft.world.World
object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
class MatterLinkCommandSender(user: String, userId: String, server: String) : IMinecraftCommandSender(user, userId, server), ICommandSender {
private var level: Int = 0
@ -23,20 +23,18 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
}
override fun getFormattedCommandSenderName(): IChatComponent {
return ChatComponentText(commandSenderName)
}
override fun getCommandSenderName(): String {
return "MatterLink"
return ChatComponentText(user)
}
override fun getCommandSenderName() = accountName
override fun getEntityWorld(): World {
return MinecraftServer.getServer().worldServerForDimension(0)
}
override fun canCommandSenderUseCommand(permLevel: Int, commandName: String?): Boolean {
override fun canCommandSenderUseCommand(permLevel: Int, commandName: String): Boolean {
//we do permission
return true
return canExecute(commandName)
}
override fun addChatMessage(component: IChatComponent) {
@ -46,5 +44,5 @@ object MatterlinkCommandSender : IMinecraftCommandSender, ICommandSender {
))
}
override fun getCommandSenderPosition(): ChunkCoordinates = ChunkCoordinates(0,0,0)
override fun getCommandSenderPosition(): ChunkCoordinates = ChunkCoordinates(0, 0, 0)
}

View File

@ -6,6 +6,7 @@ import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.config.cfg
import matterlink.update.UpdateChecker
import java.io.File
import java.time.Duration
lateinit var instance: IMatterLink
@ -13,14 +14,10 @@ abstract class IMatterLink {
abstract val mcVersion: String
abstract val modVersion: String
lateinit var cfgDir: File
abstract var commandSender: IMinecraftCommandSender
abstract fun commandSenderFor(user: String, userid: String, server: String): IMinecraftCommandSender
abstract fun wrappedSendToPlayers(msg: String)
abstract fun wrappedPlayerList(): Array<String>
private var firstRun: Boolean = true
fun connect() {
@ -63,13 +60,15 @@ abstract class IMatterLink {
}
fun getUptimeAsString(): String {
val total = this.getUptimeInSeconds()
val sec = total % 60
val min = (total / 60) % 60
val hr = (total / 3600) % 24
val day = total / 86400
return "${day}d ${hr}hr ${min}m ${sec}s"
val duration = Duration.ofSeconds((System.currentTimeMillis() - serverStartTime) / 1000)
return duration.toString()
// val total = this.getUptimeInSeconds()
// val sec = total % 60
// val min = (total / 60) % 60
// val hr = (total / 3600) % 24
// val day = total / 86400
//
// return "${day}d ${hr}hr ${min}m ${sec}s"
}
fun registerBridgeCommands() {

View File

@ -22,6 +22,16 @@ fun String.mapFormat(env: Map<String, String>): String {
return result
}
fun String.lazyFormat(env: Map<String, () -> String>): String {
var result = this
env.forEach { key, value ->
if (result.contains(key)) {
result = result.replace(key, value())
}
}
return result
}
val Exception.stackTraceString: String
get() {
val sw = StringWriter()

View File

@ -9,7 +9,7 @@ import java.util.*
object BridgeCommandRegistry {
private val commandMap: HashMap<String, IBridgeCommand> = HashMap()
private val commandMap: HashMap<String, IBridgeCommand> = hashMapOf()
fun handleCommand(input: ApiMessage): Boolean {
if (!cfg.command.enable) return false
@ -28,7 +28,7 @@ object BridgeCommandRegistry {
instance.error("Failed to register command: '${cmd.alias}'")
return false
}
if(!cmd.validate()) {
if (!cmd.validate()) {
instance.error("Failed to validate command: '${cmd.alias}'")
return false
}
@ -48,16 +48,22 @@ object BridgeCommandRegistry {
return if (help.isNotBlank()) help else "No help for '$cmd'"
}
fun getCommandList (permLvl : Int) : String {
return commandMap.filter { (key, value) ->
value.permLevel <= permLvl
}.map {it.key}.joinToString(" ")
fun getCommandList(permLvl: Int): String {
return commandMap
.filterValues {
it.permLevel <= permLvl
}
.keys
.joinToString(" ")
}
fun reloadCommands() {
commandMap.clear()
PermissionConfig.loadPermFile()
val permStatus = PermissionConfig.loadPermFile()
register(HelpCommand)
registerAll(*CommandConfig.readConfig())
val cmdStatus = CommandConfig.readConfig()
registerAll(*CommandConfig.commands)
}
operator fun get(command: String) = commandMap[command]
}

View File

@ -3,6 +3,7 @@ package matterlink.bridge.command
import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler
import matterlink.instance
import matterlink.lazyFormat
data class CustomCommand(
override val alias: String,
@ -11,23 +12,23 @@ data class CustomCommand(
val response: String = "",
override val permLevel: Int = 0,
override val help: String = "",
val allowArgs : Boolean = true
val allowArgs: Boolean = true
) : IBridgeCommand {
override fun execute(user: String, userId: String, server: String, args: String): Boolean {
if (!allowArgs && args.isNotBlank()) return false
if (IBridgeCommand.getPermLevel(userId,server) < permLevel) {
if (!canExecute(userId, server)) {
MessageHandler.transmit(ApiMessage(text = "$user is not permitted to perform command: $alias"))
return false
}
return when (type) {
CommandType.PASSTHROUGH -> {
//TODO: use a new commandSender for each user
instance.commandSender.execute("$execute $args")
//uses a new commandsender for each user
// TODO: cache CommandSenders
instance.commandSenderFor(user, userId, server).execute("$execute $args")
}
CommandType.RESPONSE -> {
//TODO: replace format variables, use arguments
MessageHandler.transmit(ApiMessage(text = response))
MessageHandler.transmit(ApiMessage(text = response.lazyFormat(getReplacements(user, args))))
true
}
}
@ -37,10 +38,20 @@ data class CustomCommand(
*
*/
override fun validate(): Boolean {
val typeCheck = when (type) {
CommandType.PASSTHROUGH -> execute.isNotBlank()
CommandType.RESPONSE -> response.isNotBlank()
}
if (!typeCheck) return false
return true
}
fun getReplacements(user: String, args: String): Map<String, () -> String> = mapOf(
"{UPTIME}" to instance::getUptimeAsString,
"{USER}" to { user },
"{ARGS}" to { args }
)
}
enum class CommandType {

View File

@ -3,17 +3,19 @@ package matterlink.bridge.command
import matterlink.config.PermissionConfig
interface IBridgeCommand {
val alias : String
val help : String
val permLevel : Int
val alias: String
val help: String
val permLevel: Int
fun execute(user:String, userId:String, server:String, args:String) : Boolean
fun execute(user: String, userId: String, server: String, args: String): Boolean
fun canExecute(userId: String, server: String): Boolean {
return getPermLevel(userId, server) >= permLevel
}
fun validate() = true
companion object {
fun getPermLevel(userId: String, server: String): Int {
if (PermissionConfig.perms[server] == null) return 0
return PermissionConfig.perms[server]?.get(userId) ?: 0

View File

@ -1,10 +1,21 @@
package matterlink.bridge.command
interface IMinecraftCommandSender {
import matterlink.instance
abstract class IMinecraftCommandSender(val user: String, val userId: String, val server: String) {
/**
* @param cmdString The command to execute with its arguments
*
* @return True for success, or false for failure
*/
fun execute(cmdString: String) : Boolean
abstract fun execute(cmdString: String): Boolean
val accountName = "$user (id=$userId server=$server)"
fun canExecute(commandName: String) : Boolean {
instance.info("testing $commandName")
val command = BridgeCommandRegistry[commandName] ?: return false
return command.canExecute(userId, server)
}
}

View File

@ -52,12 +52,7 @@ abstract class BaseConfig(rootDir: File) {
data class CommandOptions(
var prefix: String = "$",
var enable: Boolean = true,
var commandMapping: Map<String, String> = mapOf(
"tps" to "forge tps",
"list" to "list",
"seed" to "seed"
)
var enable: Boolean = true
)
data class UpdateOptions(
@ -147,21 +142,7 @@ abstract class BaseConfig(rootDir: File) {
command.prefix,
"Prefix for MC bridge commands. Accepts a single character (not alphanumeric or /)",
Pattern.compile("^[^0-9A-Za-z/]$")
),
commandMapping = getStringList(
"commandMapping",
category,
command.commandMapping.map { entry ->
"${entry.key}=${entry.value}"
}
.toTypedArray(),
"MC commands that can be executed through the bridge" +
"\nSeparate bridge command and MC command with '='."
).associate {
val key = it.substringBefore('=')
val value = it.substringAfter('=')
Pair(key, value)
}
)
)
category = "formatting"

View File

@ -2,14 +2,18 @@ package matterlink.config
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonSyntaxException
import com.google.gson.stream.MalformedJsonException
import matterlink.bridge.command.CommandType
import matterlink.bridge.command.CustomCommand
import matterlink.bridge.command.IBridgeCommand
import matterlink.instance
import java.io.File
object CommandConfig {
private val gson: Gson = GsonBuilder().setPrettyPrinting().create()
private val configFile: File = cfg.cfgDirectory.resolve("commands.json")
private val default = arrayOf(
private val default = arrayOf<CustomCommand>(
CustomCommand(
alias = "tps",
type = CommandType.PASSTHROUGH,
@ -32,16 +36,24 @@ object CommandConfig {
allowArgs = false
)
)
var commands: Array<CustomCommand> = default
private set
fun readConfig() : Array<CustomCommand> {
if(!configFile.exists()) {
fun readConfig(): Boolean {
if (!configFile.exists()) {
configFile.createNewFile()
configFile.writeText(gson.toJson(default))
return default
return true
}
val text = configFile.readText()
return gson.fromJson(text, Array<CustomCommand>::class.java)
try {
commands = gson.fromJson(text, Array<CustomCommand>::class.java)
} catch (e: JsonSyntaxException) {
instance.fatal("failed to parse $configFile using last good values as fallback")
return false
}
return true
}

View File

@ -2,26 +2,37 @@ package matterlink.config
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonSyntaxException
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.MalformedJsonException
import matterlink.instance
import java.io.File
typealias PermissionMap = HashMap<String, HashMap<String, Int>>
object PermissionConfig {
private val gson: Gson = GsonBuilder().setPrettyPrinting().create()
private val configFile: File = cfg.cfgDirectory.resolve("permissions.json")
private val default = hashMapOf<String,HashMap<String,Int>>()
private val default = PermissionMap()
var perms : HashMap<String,HashMap<String,Int>> = default
var perms: PermissionMap = default
fun loadPermFile() {
if(!configFile.exists()) {
fun loadPermFile(): Boolean {
if (!configFile.exists()) {
configFile.createNewFile()
perms = default
configFile.writeText(gson.toJson(default))
return
return true
}
val text = configFile.readText()
perms = gson.fromJson(text, object : TypeToken <HashMap<String,HashMap<String,Int>>>(){}.type)
try {
perms = gson.fromJson(text, object : TypeToken<PermissionMap>() {}.type)
} catch (e: JsonSyntaxException) {
instance.fatal("failed to parse $configFile using last good values as fallback")
return false
}
return true
}
}

View File

@ -1,3 +1,3 @@
mod_name = MatterLink
mod_version = 1.4.1
mod_version = 1.4.2
forgelin_version = 1.6.0