update to kotlin 1.3

[1.7.10] fixed send to player NPE
This commit is contained in:
NikkyAI 2018-11-02 04:13:29 +01:00
parent 3082d3e592
commit 34887a833c
62 changed files with 1682 additions and 1560 deletions

2
.gitignore vendored
View File

@ -102,3 +102,5 @@ run/
\.floo \.floo
\.flooignore \.flooignore
bugreport/

View File

@ -115,3 +115,7 @@ curseforge {
} }
} }
} }
runServer {
outputs.upToDateWhen { false }
}

View File

@ -1,3 +1,3 @@
mc_version = 1.12.2 mc_version = 1.12.2
mcp_mappings = snapshot_20171003 mcp_mappings = stable_39
forge_version = 14.23.1.2599 forge_version = 14.23.5.2768

View File

@ -1,7 +1,13 @@
package matterlink package matterlink
import kotlinx.coroutines.runBlocking
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.handlers.* import matterlink.handlers.ChatEvent
import matterlink.handlers.ChatProcessor
import matterlink.handlers.DeathHandler
import matterlink.handlers.JoinLeaveHandler
import matterlink.handlers.ProgressHandler
import matterlink.handlers.TickHandler
import net.minecraft.command.server.CommandBroadcast import net.minecraft.command.server.CommandBroadcast
import net.minecraft.command.server.CommandEmote import net.minecraft.command.server.CommandEmote
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
@ -22,8 +28,8 @@ object EventHandler {
//MC-VERSION & FORGE DEPENDENT //MC-VERSION & FORGE DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun progressEvent(e: AdvancementEvent) { fun progressEvent(e: AdvancementEvent) = runBlocking {
if (e.advancement.display == null) return if (e.advancement.display == null) return@runBlocking
ProgressHandler.handleProgress( ProgressHandler.handleProgress(
name = e.entityPlayer.displayName.unformattedText, name = e.entityPlayer.displayName.unformattedText,
message = "has made the advancement", message = "has made the advancement",
@ -38,8 +44,8 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun chatEvent(e: ServerChatEvent) { fun chatEvent(e: ServerChatEvent) = runBlocking {
if (e.isCanceled) return if (e.isCanceled) return@runBlocking
e.isCanceled = ChatProcessor.sendToBridge( e.isCanceled = ChatProcessor.sendToBridge(
user = e.player.displayName.unformattedText, user = e.player.displayName.unformattedText,
msg = e.message, msg = e.message,
@ -55,7 +61,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun commandEvent(e: CommandEvent) { fun commandEvent(e: CommandEvent) = runBlocking {
val sender = when { val sender = when {
e.sender is DedicatedServer -> cfg.outgoing.systemUser e.sender is DedicatedServer -> cfg.outgoing.systemUser
@ -66,7 +72,7 @@ object EventHandler {
when { when {
this is CommandEmote || name.equals("me", true) -> ChatEvent.ACTION this is CommandEmote || name.equals("me", true) -> ChatEvent.ACTION
this is CommandBroadcast || name.equals("say", true) -> ChatEvent.BROADCAST this is CommandBroadcast || name.equals("say", true) -> ChatEvent.BROADCAST
else -> return else -> return@runBlocking
} }
} }
ChatProcessor.sendToBridge( ChatProcessor.sendToBridge(
@ -86,7 +92,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun deathEvent(e: LivingDeathEvent) { fun deathEvent(e: LivingDeathEvent) = runBlocking {
if (e.entityLiving is EntityPlayer) { if (e.entityLiving is EntityPlayer) {
DeathHandler.handleDeath( DeathHandler.handleDeath(
player = e.entityLiving.displayName.unformattedText, player = e.entityLiving.displayName.unformattedText,
@ -103,7 +109,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) { fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) = runBlocking {
JoinLeaveHandler.handleJoin( JoinLeaveHandler.handleJoin(
player = e.player.displayName.unformattedText, player = e.player.displayName.unformattedText,
x = e.player.posX.toInt(), x = e.player.posX.toInt(),
@ -116,7 +122,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) { fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) = runBlocking {
JoinLeaveHandler.handleLeave( JoinLeaveHandler.handleLeave(
player = e.player.displayName.unformattedText, player = e.player.displayName.unformattedText,
x = e.player.posX.toInt(), x = e.player.posX.toInt(),
@ -129,8 +135,9 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun serverTickEvent(e: TickEvent.ServerTickEvent) { fun serverTickEvent(e: TickEvent.ServerTickEvent) = runBlocking {
if (e.phase == TickEvent.Phase.END) if (e.phase == TickEvent.Phase.END)
TickHandler.handleTick() TickHandler.handleTick()
} }
} }

View File

@ -1,7 +1,7 @@
package matterlink package matterlink
import com.mojang.authlib.GameProfile import com.mojang.authlib.GameProfile
import jline.internal.Log.warn import kotlinx.coroutines.runBlocking
import matterlink.bridge.command.IBridgeCommand import matterlink.bridge.command.IBridgeCommand
import matterlink.command.AuthCommand import matterlink.command.AuthCommand
import matterlink.command.MatterLinkCommand import matterlink.command.MatterLinkCommand
@ -9,9 +9,7 @@ import matterlink.command.MatterLinkCommandSender
import matterlink.config.BaseConfig import matterlink.config.BaseConfig
import matterlink.config.cfg import matterlink.config.cfg
import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.entity.player.EntityPlayerMP
import net.minecraft.server.MinecraftServer
import net.minecraft.util.text.TextComponentString import net.minecraft.util.text.TextComponentString
import net.minecraftforge.common.DimensionManager
import net.minecraftforge.common.ForgeVersion import net.minecraftforge.common.ForgeVersion
import net.minecraftforge.fml.common.FMLCommonHandler import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.Mod
@ -21,7 +19,7 @@ import net.minecraftforge.fml.common.event.FMLServerStartingEvent
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent import net.minecraftforge.fml.common.event.FMLServerStoppingEvent
import org.apache.logging.log4j.Level import org.apache.logging.log4j.Level
import org.apache.logging.log4j.core.config.Configurator import org.apache.logging.log4j.core.config.Configurator
import java.util.* import java.util.UUID
@Mod( @Mod(
@ -59,6 +57,7 @@ object MatterLink : IMatterLink() {
@Mod.EventHandler @Mod.EventHandler
fun init(event: FMLInitializationEvent) { fun init(event: FMLInitializationEvent) {
logger.debug("Registering bridge commands")
this.registerBridgeCommands() this.registerBridgeCommands()
} }
@ -67,11 +66,13 @@ object MatterLink : IMatterLink() {
logger.debug("Registering server commands") logger.debug("Registering server commands")
event.registerServerCommand(MatterLinkCommand) event.registerServerCommand(MatterLinkCommand)
event.registerServerCommand(AuthCommand) event.registerServerCommand(AuthCommand)
runBlocking {
start() start()
} }
}
@Mod.EventHandler @Mod.EventHandler
fun serverStopping(event: FMLServerStoppingEvent) { fun serverStopping(event: FMLServerStoppingEvent) = runBlocking {
stop() stop()
} }
@ -104,21 +105,23 @@ object MatterLink : IMatterLink() {
player.sendMessage(TextComponentString(msg)) player.sendMessage(TextComponentString(msg))
} }
override fun isOnline(username: String) = FMLCommonHandler.instance().minecraftServerInstance.onlinePlayerNames.contains(username) override fun isOnline(username: String) =
FMLCommonHandler.instance().minecraftServerInstance.onlinePlayerNames.contains(username)
private fun playerByProfile(gameProfile: GameProfile): EntityPlayerMP? = FMLCommonHandler.instance().minecraftServerInstance.playerList.getPlayerByUUID(gameProfile.id) private fun playerByProfile(gameProfile: GameProfile): EntityPlayerMP? =
FMLCommonHandler.instance().minecraftServerInstance.playerList.getPlayerByUUID(gameProfile.id)
private fun profileByUUID(uuid: UUID): GameProfile? = try { private fun profileByUUID(uuid: UUID): GameProfile? = try {
FMLCommonHandler.instance().minecraftServerInstance.playerProfileCache.getProfileByUUID(uuid) FMLCommonHandler.instance().minecraftServerInstance.playerProfileCache.getProfileByUUID(uuid)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
warn("cannot find profile by uuid $uuid") logger.warn("cannot find profile by uuid $uuid")
null null
} }
private fun profileByName(username: String): GameProfile? = try { private fun profileByName(username: String): GameProfile? = try {
FMLCommonHandler.instance().minecraftServerInstance.playerProfileCache.getGameProfileForUsername(username) FMLCommonHandler.instance().minecraftServerInstance.playerProfileCache.getGameProfileForUsername(username)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
warn("cannot find profile by username $username") logger.warn("cannot find profile by username $username")
null null
} }

View File

@ -1,5 +1,6 @@
package matterlink.command package matterlink.command
import kotlinx.coroutines.runBlocking
import net.minecraft.command.CommandBase import net.minecraft.command.CommandBase
import net.minecraft.command.ICommandSender import net.minecraft.command.ICommandSender
import net.minecraft.command.WrongUsageException import net.minecraft.command.WrongUsageException
@ -21,9 +22,9 @@ object MatterLinkCommand : CommandBase() {
return CommandCoreML.aliases return CommandCoreML.aliases
} }
override fun execute(server: MinecraftServer, sender: ICommandSender, args: Array<String>) { override fun execute(server: MinecraftServer, sender: ICommandSender, args: Array<String>) = runBlocking {
if (args.isEmpty()) { if (args.isEmpty()) {
throw WrongUsageException("Invalid command! Valid uses: ${this.getUsage(sender)}") throw WrongUsageException("Invalid command! Valid uses: ${getUsage(sender)}")
} }
val uuid = (sender as? EntityPlayer)?.uniqueID?.toString() val uuid = (sender as? EntityPlayer)?.uniqueID?.toString()

View File

@ -1,5 +1,6 @@
package matterlink.command package matterlink.command
import kotlinx.coroutines.runBlocking
import matterlink.bridge.command.IBridgeCommand import matterlink.bridge.command.IBridgeCommand
import matterlink.bridge.command.IMinecraftCommandSender import matterlink.bridge.command.IMinecraftCommandSender
import net.minecraft.command.ICommandSender import net.minecraft.command.ICommandSender
@ -13,11 +14,12 @@ import javax.annotation.Nonnull
class MatterLinkCommandSender( class MatterLinkCommandSender(
user: String, user: String,
env: IBridgeCommand.CommandEnvironment, env: IBridgeCommand.CommandEnvironment,
op: Boolean) : IMinecraftCommandSender(user, env, op), ICommandSender { op: Boolean
) : IMinecraftCommandSender(user, env, op), ICommandSender {
override fun execute(cmdString: String): Boolean { override fun execute(cmdString: String): Boolean = runBlocking {
return 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand( 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand(
this, this@MatterLinkCommandSender,
cmdString cmdString
).apply { ).apply {
sendReply(cmdString) sendReply(cmdString)

View File

@ -11,17 +11,12 @@ buildscript {
} }
dependencies { dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '1.2-SNAPSHOT' classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '1.2-SNAPSHOT'
classpath group: 'com.github.jengelman.gradle.plugins', name: 'shadow', version: shadowVersion
classpath group: 'gradle.plugin.com.matthewprenger', name: 'CurseGradle', version: cursegradleVersion classpath group: 'gradle.plugin.com.matthewprenger', name: 'CurseGradle', version: cursegradleVersion
classpath group: 'com.vanniktech', name: 'gradle-dependency-graph-generator-plugin', version: '0.5.0'
} }
} }
apply plugin: 'forge' apply plugin: 'forge'
//apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'com.matthewprenger.cursegradle' apply plugin: 'com.matthewprenger.cursegradle'
apply plugin: "com.vanniktech.dependency.graph.generator"
version = project.mc_version + '-' + project.modVersion version = project.mc_version + '-' + project.modVersion
@ -39,6 +34,12 @@ dependencies {
shade (project(':Jankson')) { transitive = false } shade (project(':Jankson')) { transitive = false }
shade group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion shade group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion
shade(group: "com.github.NikkyAi.Fuel", name: "fuel", version: "feature~chunked-SNAPSHOT")
shade(group: "com.github.NikkyAi.Fuel", name: "fuel-coroutines", version: "feature~chunked-SNAPSHOT")
shade(group: 'com.github.kittinunf.result', name: 'result', version: resultVersion)
shade(group: "org.jetbrains.kotlinx", name: "kotlinx-coroutines-core", version: "1.0.0")
shade(group: "org.jetbrains.kotlinx", name: "kotlinx-serialization-runtime", version: "0.9.0")
shade group: 'com.github.kittinunf.fuel', name: 'fuel', version: fuelVersion shade group: 'com.github.kittinunf.fuel', name: 'fuel', version: fuelVersion
shade group: 'com.github.kittinunf.result', name: 'result', version: resultVersion shade group: 'com.github.kittinunf.result', name: 'result', version: resultVersion

View File

@ -3,9 +3,14 @@ package matterlink
import cpw.mods.fml.common.eventhandler.SubscribeEvent import cpw.mods.fml.common.eventhandler.SubscribeEvent
import cpw.mods.fml.common.gameevent.PlayerEvent import cpw.mods.fml.common.gameevent.PlayerEvent
import cpw.mods.fml.common.gameevent.TickEvent import cpw.mods.fml.common.gameevent.TickEvent
import matterlink.api.ApiMessage.Companion.USER_ACTION import kotlinx.coroutines.runBlocking
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.handlers.* import matterlink.handlers.ChatEvent
import matterlink.handlers.ChatProcessor
import matterlink.handlers.DeathHandler
import matterlink.handlers.JoinLeaveHandler
import matterlink.handlers.ProgressHandler
import matterlink.handlers.TickHandler
import net.minecraft.command.server.CommandBroadcast import net.minecraft.command.server.CommandBroadcast
import net.minecraft.command.server.CommandEmote import net.minecraft.command.server.CommandEmote
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
@ -22,13 +27,13 @@ object EventHandler {
//MC-VERSION & FORGE DEPENDENT //MC-VERSION & FORGE DEPENDENT
@SubscribeEvent @SubscribeEvent
fun progressEvent(e: AchievementEvent) { fun progressEvent(e: AchievementEvent) = runBlocking {
val achievement = e.achievement val achievement = e.achievement
val entityPlayer = e.entityPlayer as? EntityPlayerMP ?: return val entityPlayer = e.entityPlayer as? EntityPlayerMP ?: return@runBlocking
val statFile = entityPlayer.statFile val statFile = entityPlayer.statFile
if (!statFile.canUnlockAchievement(achievement) || statFile.hasAchievementUnlocked(achievement)) { if (!statFile.canUnlockAchievement(achievement) || statFile.hasAchievementUnlocked(achievement)) {
return return@runBlocking
} }
ProgressHandler.handleProgress( ProgressHandler.handleProgress(
@ -44,8 +49,8 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun chatEvent(e: ServerChatEvent) { fun chatEvent(e: ServerChatEvent) = runBlocking {
if(e.isCanceled) return if (e.isCanceled) return@runBlocking
e.isCanceled = ChatProcessor.sendToBridge( e.isCanceled = ChatProcessor.sendToBridge(
user = e.player.displayName, user = e.player.displayName,
msg = e.message, msg = e.message,
@ -60,7 +65,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun commandEvent(e: CommandEvent) { fun commandEvent(e: CommandEvent) = runBlocking {
val sender = when { val sender = when {
e.sender is DedicatedServer -> cfg.outgoing.systemUser e.sender is DedicatedServer -> cfg.outgoing.systemUser
else -> e.sender.commandSenderName else -> e.sender.commandSenderName
@ -70,7 +75,7 @@ object EventHandler {
when { when {
this is CommandEmote || commandName.equals("me", true) -> ChatEvent.ACTION this is CommandEmote || commandName.equals("me", true) -> ChatEvent.ACTION
this is CommandBroadcast || commandName.equals("say", true) -> ChatEvent.BROADCAST this is CommandBroadcast || commandName.equals("say", true) -> ChatEvent.BROADCAST
else -> return else -> return@runBlocking
} }
} }
val s = e.sender val s = e.sender
@ -95,7 +100,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun deathEvent(e: LivingDeathEvent) { fun deathEvent(e: LivingDeathEvent) = runBlocking {
if (e.entityLiving is EntityPlayer) { if (e.entityLiving is EntityPlayer) {
val player = e.entityLiving as EntityPlayer val player = e.entityLiving as EntityPlayer
DeathHandler.handleDeath( DeathHandler.handleDeath(
@ -112,18 +117,19 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) { fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) = runBlocking {
JoinLeaveHandler.handleJoin( JoinLeaveHandler.handleJoin(
player = e.player.displayName, player = e.player.displayName,
x = e.player.posX.toInt(), x = e.player.posX.toInt(),
y = e.player.posY.toInt(), y = e.player.posY.toInt(),
z = e.player.posZ.toInt(), z = e.player.posZ.toInt(),
dimension = e.player.dimension) dimension = e.player.dimension
)
} }
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) { fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) = runBlocking {
JoinLeaveHandler.handleLeave( JoinLeaveHandler.handleLeave(
player = e.player.displayName, player = e.player.displayName,
x = e.player.posX.toInt(), x = e.player.posX.toInt(),
@ -135,7 +141,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun serverTickEvent(e: TickEvent.ServerTickEvent) { fun serverTickEvent(e: TickEvent.ServerTickEvent) = runBlocking {
if (e.phase == TickEvent.Phase.END) if (e.phase == TickEvent.Phase.END)
TickHandler.handleTick() TickHandler.handleTick()
} }

View File

@ -7,6 +7,7 @@ import cpw.mods.fml.common.event.FMLInitializationEvent
import cpw.mods.fml.common.event.FMLPreInitializationEvent import cpw.mods.fml.common.event.FMLPreInitializationEvent
import cpw.mods.fml.common.event.FMLServerStartingEvent import cpw.mods.fml.common.event.FMLServerStartingEvent
import cpw.mods.fml.common.event.FMLServerStoppingEvent import cpw.mods.fml.common.event.FMLServerStoppingEvent
import kotlinx.coroutines.runBlocking
import matterlink.bridge.command.IBridgeCommand import matterlink.bridge.command.IBridgeCommand
import matterlink.command.AuthCommand import matterlink.command.AuthCommand
import matterlink.command.MatterLinkCommand import matterlink.command.MatterLinkCommand
@ -18,7 +19,7 @@ import net.minecraft.server.MinecraftServer
import net.minecraft.util.ChatComponentText import net.minecraft.util.ChatComponentText
import net.minecraftforge.common.ForgeVersion import net.minecraftforge.common.ForgeVersion
import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.MinecraftForge
import java.util.* import java.util.UUID
@Mod( @Mod(
modid = MODID, modid = MODID,
@ -57,7 +58,7 @@ class MatterLink : IMatterLink() {
} }
@Mod.EventHandler @Mod.EventHandler
fun serverStarting(event: FMLServerStartingEvent) { fun serverStarting(event: FMLServerStartingEvent) = runBlocking {
logger.debug("Registering server commands") logger.debug("Registering server commands")
event.registerServerCommand(MatterLinkCommand) event.registerServerCommand(MatterLinkCommand)
event.registerServerCommand(AuthCommand) event.registerServerCommand(AuthCommand)
@ -65,7 +66,7 @@ class MatterLink : IMatterLink() {
} }
@Mod.EventHandler @Mod.EventHandler
fun serverStopping(event: FMLServerStoppingEvent) { fun serverStopping(event: FMLServerStoppingEvent) = runBlocking {
stop() stop()
} }
@ -102,7 +103,8 @@ class MatterLink : IMatterLink() {
.minecraftServerInstance.configurationManager.getPlayerByUsername(username) ?: null) != null .minecraftServerInstance.configurationManager.getPlayerByUsername(username) ?: null) != null
private fun playerByProfile(gameProfile: GameProfile): EntityPlayerMP? { private fun playerByProfile(gameProfile: GameProfile): EntityPlayerMP? {
return FMLCommonHandler.instance().minecraftServerInstance.configurationManager.createPlayerForUser(gameProfile) return FMLCommonHandler.instance()
.minecraftServerInstance.configurationManager.getPlayerByUsername(gameProfile.name)
} }
private fun profileByUUID(uuid: UUID): GameProfile? = try { private fun profileByUUID(uuid: UUID): GameProfile? = try {

View File

@ -1,5 +1,6 @@
package matterlink.command package matterlink.command
import kotlinx.coroutines.runBlocking
import net.minecraft.command.CommandBase import net.minecraft.command.CommandBase
import net.minecraft.command.ICommandSender import net.minecraft.command.ICommandSender
import net.minecraft.command.WrongUsageException import net.minecraft.command.WrongUsageException
@ -20,9 +21,9 @@ object MatterLinkCommand : CommandBase() {
return CommandCoreML.aliases return CommandCoreML.aliases
} }
override fun processCommand(sender: ICommandSender, args: Array<String>) { override fun processCommand(sender: ICommandSender, args: Array<String>) = runBlocking {
if (args.isEmpty()) { if (args.isEmpty()) {
throw WrongUsageException("Invalid command! Valid uses: ${this.getCommandUsage(sender)}") throw WrongUsageException("Invalid command! Valid uses: ${getCommandUsage(sender)}")
} }
val uuid = (sender as? EntityPlayer)?.uniqueID?.toString() val uuid = (sender as? EntityPlayer)?.uniqueID?.toString()

View File

@ -1,5 +1,6 @@
package matterlink.command package matterlink.command
import kotlinx.coroutines.runBlocking
import matterlink.bridge.command.IBridgeCommand import matterlink.bridge.command.IBridgeCommand
import matterlink.bridge.command.IMinecraftCommandSender import matterlink.bridge.command.IMinecraftCommandSender
import net.minecraft.command.ICommandSender import net.minecraft.command.ICommandSender
@ -12,11 +13,12 @@ import net.minecraft.world.World
class MatterLinkCommandSender( class MatterLinkCommandSender(
user: String, user: String,
env: IBridgeCommand.CommandEnvironment, env: IBridgeCommand.CommandEnvironment,
op: Boolean) : IMinecraftCommandSender(user, env, op), ICommandSender { op: Boolean
) : IMinecraftCommandSender(user, env, op), ICommandSender {
override fun execute(cmdString: String): Boolean { override fun execute(cmdString: String): Boolean = runBlocking {
return 0 < MinecraftServer.getServer().commandManager.executeCommand( return@runBlocking 0 < MinecraftServer.getServer().commandManager.executeCommand(
this, this@MatterLinkCommandSender,
cmdString cmdString
).apply { ).apply {
sendReply(cmdString) sendReply(cmdString)

View File

@ -1,7 +1,13 @@
package matterlink package matterlink
import kotlinx.coroutines.runBlocking
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.handlers.* import matterlink.handlers.ChatEvent
import matterlink.handlers.ChatProcessor
import matterlink.handlers.DeathHandler
import matterlink.handlers.JoinLeaveHandler
import matterlink.handlers.ProgressHandler
import matterlink.handlers.TickHandler
import net.minecraft.command.server.CommandBroadcast import net.minecraft.command.server.CommandBroadcast
import net.minecraft.command.server.CommandEmote import net.minecraft.command.server.CommandEmote
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
@ -20,13 +26,13 @@ object EventHandler {
//MC-VERSION & FORGE DEPENDENT //MC-VERSION & FORGE DEPENDENT
@SubscribeEvent @SubscribeEvent
fun progressEvent(e: AchievementEvent) { fun progressEvent(e: AchievementEvent) = runBlocking {
val achievement = e.achievement val achievement = e.achievement
val entityPlayer = e.entityPlayer as? EntityPlayerMP ?: return val entityPlayer = e.entityPlayer as? EntityPlayerMP ?: return@runBlocking
val statFile = entityPlayer.statFile val statFile = entityPlayer.statFile
if (!statFile.canUnlockAchievement(achievement) || statFile.hasAchievementUnlocked(achievement)) { if (!statFile.canUnlockAchievement(achievement) || statFile.hasAchievementUnlocked(achievement)) {
return return@runBlocking
} }
ProgressHandler.handleProgress( ProgressHandler.handleProgress(
name = e.entityPlayer.displayName.unformattedText, name = e.entityPlayer.displayName.unformattedText,
@ -41,8 +47,8 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun chatEvent(e: ServerChatEvent) { fun chatEvent(e: ServerChatEvent) = runBlocking {
if(e.isCanceled) return if (e.isCanceled) return@runBlocking
e.isCanceled = ChatProcessor.sendToBridge( e.isCanceled = ChatProcessor.sendToBridge(
user = e.player.displayName.unformattedText, user = e.player.displayName.unformattedText,
msg = e.message, msg = e.message,
@ -57,7 +63,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun commandEvent(e: CommandEvent) { fun commandEvent(e: CommandEvent) = runBlocking {
val sender = when { val sender = when {
e.sender is DedicatedServer -> cfg.outgoing.systemUser e.sender is DedicatedServer -> cfg.outgoing.systemUser
else -> e.sender.displayName.unformattedText else -> e.sender.displayName.unformattedText
@ -67,7 +73,7 @@ object EventHandler {
when { when {
this is CommandEmote || commandName.equals("me", true) -> ChatEvent.ACTION this is CommandEmote || commandName.equals("me", true) -> ChatEvent.ACTION
this is CommandBroadcast || commandName.equals("say", true) -> ChatEvent.BROADCAST this is CommandBroadcast || commandName.equals("say", true) -> ChatEvent.BROADCAST
else -> return else -> return@runBlocking
} }
} }
ChatProcessor.sendToBridge( ChatProcessor.sendToBridge(
@ -86,7 +92,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun deathEvent(e: LivingDeathEvent) { fun deathEvent(e: LivingDeathEvent) = runBlocking {
if (e.entityLiving is EntityPlayer) { if (e.entityLiving is EntityPlayer) {
DeathHandler.handleDeath( DeathHandler.handleDeath(
player = e.entityLiving.displayName.unformattedText, player = e.entityLiving.displayName.unformattedText,
@ -102,7 +108,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) { fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) = runBlocking {
JoinLeaveHandler.handleJoin( JoinLeaveHandler.handleJoin(
player = e.player.displayName.unformattedText, player = e.player.displayName.unformattedText,
x = e.player.posX.toInt(), x = e.player.posX.toInt(),
@ -114,7 +120,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) { fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) = runBlocking {
JoinLeaveHandler.handleLeave( JoinLeaveHandler.handleLeave(
player = e.player.displayName.unformattedText, player = e.player.displayName.unformattedText,
x = e.player.posX.toInt(), x = e.player.posX.toInt(),
@ -126,7 +132,7 @@ object EventHandler {
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
fun serverTickEvent(e: TickEvent.ServerTickEvent) { fun serverTickEvent(e: TickEvent.ServerTickEvent) = runBlocking {
if (e.phase == TickEvent.Phase.END) if (e.phase == TickEvent.Phase.END)
TickHandler.handleTick() TickHandler.handleTick()
} }

View File

@ -1,6 +1,7 @@
package matterlink package matterlink
import com.mojang.authlib.GameProfile import com.mojang.authlib.GameProfile
import kotlinx.coroutines.runBlocking
import matterlink.bridge.command.IBridgeCommand import matterlink.bridge.command.IBridgeCommand
import matterlink.command.AuthCommand import matterlink.command.AuthCommand
import matterlink.command.MatterLinkCommand import matterlink.command.MatterLinkCommand
@ -8,7 +9,6 @@ import matterlink.command.MatterLinkCommandSender
import matterlink.config.BaseConfig import matterlink.config.BaseConfig
import matterlink.config.cfg import matterlink.config.cfg
import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.entity.player.EntityPlayerMP
import net.minecraft.server.MinecraftServer
import net.minecraft.util.text.TextComponentString import net.minecraft.util.text.TextComponentString
import net.minecraftforge.common.ForgeVersion import net.minecraftforge.common.ForgeVersion
import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.MinecraftForge
@ -18,7 +18,7 @@ import net.minecraftforge.fml.common.event.FMLInitializationEvent
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent import net.minecraftforge.fml.common.event.FMLPreInitializationEvent
import net.minecraftforge.fml.common.event.FMLServerStartingEvent import net.minecraftforge.fml.common.event.FMLServerStartingEvent
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent import net.minecraftforge.fml.common.event.FMLServerStoppingEvent
import java.util.* import java.util.UUID
@Mod( @Mod(
modid = MODID, modid = MODID,
@ -58,7 +58,7 @@ object MatterLink : IMatterLink() {
} }
@Mod.EventHandler @Mod.EventHandler
fun serverStarting(event: FMLServerStartingEvent) { fun serverStarting(event: FMLServerStartingEvent) = runBlocking {
logger.debug("Registering server commands") logger.debug("Registering server commands")
event.registerServerCommand(MatterLinkCommand) event.registerServerCommand(MatterLinkCommand)
event.registerServerCommand(AuthCommand) event.registerServerCommand(AuthCommand)
@ -66,7 +66,7 @@ object MatterLink : IMatterLink() {
} }
@Mod.EventHandler @Mod.EventHandler
fun serverStopping(event: FMLServerStoppingEvent) { fun serverStopping(event: FMLServerStoppingEvent) = runBlocking {
stop() stop()
} }
@ -99,9 +99,11 @@ object MatterLink : IMatterLink() {
player.addChatMessage(TextComponentString(msg)) player.addChatMessage(TextComponentString(msg))
} }
override fun isOnline(username: String) = FMLCommonHandler.instance().minecraftServerInstance.playerList.allUsernames.contains(username) override fun isOnline(username: String) =
FMLCommonHandler.instance().minecraftServerInstance.playerList.allUsernames.contains(username)
private fun playerByProfile(gameProfile: GameProfile): EntityPlayerMP? = FMLCommonHandler.instance().minecraftServerInstance.playerList.getPlayerByUUID(gameProfile.id) private fun playerByProfile(gameProfile: GameProfile): EntityPlayerMP? =
FMLCommonHandler.instance().minecraftServerInstance.playerList.getPlayerByUUID(gameProfile.id)
private fun profileByUUID(uuid: UUID): GameProfile? = try { private fun profileByUUID(uuid: UUID): GameProfile? = try {

View File

@ -1,5 +1,6 @@
package matterlink.command package matterlink.command
import kotlinx.coroutines.runBlocking
import net.minecraft.command.CommandBase import net.minecraft.command.CommandBase
import net.minecraft.command.ICommandSender import net.minecraft.command.ICommandSender
import net.minecraft.command.WrongUsageException import net.minecraft.command.WrongUsageException
@ -21,9 +22,9 @@ object MatterLinkCommand : CommandBase() {
return CommandCoreML.aliases return CommandCoreML.aliases
} }
override fun execute(server: MinecraftServer, sender: ICommandSender, args: Array<String>) { override fun execute(server: MinecraftServer, sender: ICommandSender, args: Array<String>) = runBlocking {
if (args.isEmpty()) { if (args.isEmpty()) {
throw WrongUsageException("Invalid command! Valid uses: ${this.getCommandUsage(sender)}") throw WrongUsageException("Invalid command! Valid uses: ${getCommandUsage(sender)}")
} }
val uuid = (sender as? EntityPlayer)?.uniqueID?.toString() val uuid = (sender as? EntityPlayer)?.uniqueID?.toString()

View File

@ -1,5 +1,6 @@
package matterlink.command package matterlink.command
import kotlinx.coroutines.runBlocking
import matterlink.bridge.command.IBridgeCommand import matterlink.bridge.command.IBridgeCommand
import matterlink.bridge.command.IMinecraftCommandSender import matterlink.bridge.command.IMinecraftCommandSender
import net.minecraft.command.CommandResultStats import net.minecraft.command.CommandResultStats
@ -17,10 +18,11 @@ import javax.annotation.Nonnull
class MatterLinkCommandSender( class MatterLinkCommandSender(
user: String, user: String,
env: IBridgeCommand.CommandEnvironment, env: IBridgeCommand.CommandEnvironment,
op: Boolean) : IMinecraftCommandSender(user, env, op), ICommandSender { op: Boolean
override fun execute(cmdString: String): Boolean { ) : IMinecraftCommandSender(user, env, op), ICommandSender {
return 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand( override fun execute(cmdString: String): Boolean = runBlocking {
this, return@runBlocking 0 < FMLCommonHandler.instance().minecraftServerInstance.commandManager.executeCommand(
this@MatterLinkCommandSender,
cmdString cmdString
).apply { ).apply {
sendReply(cmdString) sendReply(cmdString)

@ -1 +1 @@
Subproject commit 091281a436b6b3807484aec2236641716d1a94ed Subproject commit 7d27c28784bacba17450faa9e723ca6b6eb39602

14
TODO.MD Normal file
View File

@ -0,0 +1,14 @@
# Replacement for guava
# using Fuel everywhere to simplify code
# Adittional player values
add optional feature:
GET json dictionary of player values like TEAM, NICK, TOWN
from url based on uuid / playername
config input: `http://rest.wurmcraft.com/user/find/{UUID}`
url: `http://rest.wurmcraft.com/user/find/148cf139-dd14-4bf4-97a2-08305dfef0a9`

View File

@ -4,6 +4,7 @@ buildscript {
} }
dependencies { dependencies {
classpath group: "org.jetbrains.kotlin", name: "kotlin-gradle-plugin", version: kotlinVersion classpath group: "org.jetbrains.kotlin", name: "kotlin-gradle-plugin", version: kotlinVersion
classpath group: "org.jetbrains.kotlin", name: "kotlin-serialization", version: kotlinVersion
} }
} }
@ -14,6 +15,7 @@ plugins {
subprojects { subprojects {
apply plugin: "kotlin" apply plugin: "kotlin"
apply plugin: "kotlinx-serialization"
apply plugin: "idea" apply plugin: "idea"
if (System.env.BUILD_NUMBER) { if (System.env.BUILD_NUMBER) {
@ -35,24 +37,28 @@ subprojects {
} }
repositories { repositories {
jcenter() jcenter()
mavenCentral()
maven { maven {
name = "bintray" name = "bintray"
url = 'http://jcenter.bintray.com' url = "http://jcenter.bintray.com"
} }
maven { maven {
name = "elytradev" name = "jitpack"
url = 'http://unascribed.com/maven/releases' url = "https://jitpack.io"
url = 'https://repo.elytradev.com'
} }
maven {
name = "kotlinx"
url = "https://kotlin.bintray.com/kotlinx/"
}
// maven {
// name = "elytradev"
// // url = 'http://unascribed.com/maven/releases'
// url = "https://repo.elytradev.com"
// }
maven { maven {
name = "shadowfacts" name = "shadowfacts"
url = "http://maven.shadowfacts.net/" url = "http://maven.shadowfacts.net/"
} }
ivy {
//Resolves baubles and jankson
name = "endless.blue dependency mirror"
artifactPattern "https://endless.blue/files/ivy/[module]-[revision].[ext]"
}
} }
compileKotlin { compileKotlin {
kotlinOptions { kotlinOptions {

View File

@ -0,0 +1,11 @@
object MatterLink {
const val version = "1.6.5"
}
object Kotlin {
const val version = "1.3.0"
}
object Forgelin {
const val version = "1.8.0"
}

View File

@ -23,11 +23,16 @@ dependencies {
compile group: 'com.google.code.gson', name: 'gson', version: '+' compile group: 'com.google.code.gson', name: 'gson', version: '+'
compile group: 'com.google.guava', name: 'guava', version: '+' compile group: 'com.google.guava', name: 'guava', version: '+'
compile group: 'com.github.kittinunf.fuel', name: 'fuel', version: fuelVersion compile(group: "com.github.NikkyAi.Fuel", name: "fuel", version: "feature~chunked-SNAPSHOT")
shadow (group: 'com.github.kittinunf.fuel', name: 'fuel', version: fuelVersion) { transitive = false } shadow(group: "com.github.NikkyAi.Fuel", name: "fuel", version: "feature~chunked-SNAPSHOT") { transitive = false }
compile group: 'com.github.kittinunf.result', name: 'result', version: resultVersion compile(group: "com.github.NikkyAi.Fuel", name: "fuel-coroutines", version: "feature~chunked-SNAPSHOT")
shadow(group: "com.github.NikkyAi.Fuel", name: "fuel-coroutines", version: "feature~chunked-SNAPSHOT") { transitive = false }
compile(group: 'com.github.kittinunf.result', name: 'result', version: resultVersion)
shadow(group: 'com.github.kittinunf.result', name: 'result', version: resultVersion) { transitive = false } shadow(group: 'com.github.kittinunf.result', name: 'result', version: resultVersion) { transitive = false }
compile(group: "org.jetbrains.kotlinx", name: "kotlinx-coroutines-core", version: "1.0.0")
compile(group: "org.jetbrains.kotlinx", name: "kotlinx-serialization-runtime", version: "0.9.0")
compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion
} }

View File

@ -159,6 +159,7 @@ sealed class Area {
override fun testInBounds(x: Int, y: Int, z: Int): Boolean { override fun testInBounds(x: Int, y: Int, z: Int): Boolean {
return x in x1..x2 && z in z1..z2 return x in x1..x2 && z in z1..z2
} }
companion object { companion object {
fun parse(jsonObj: JsonObject): Area { fun parse(jsonObj: JsonObject): Area {

View File

@ -4,10 +4,9 @@ import matterlink.bridge.MessageHandlerInst
import matterlink.bridge.command.BridgeCommandRegistry import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.bridge.command.IBridgeCommand import matterlink.bridge.command.IBridgeCommand
import matterlink.bridge.command.IMinecraftCommandSender import matterlink.bridge.command.IMinecraftCommandSender
import matterlink.config.BaseConfig
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.update.UpdateChecker import matterlink.update.UpdateChecker
import java.util.* import java.util.UUID
lateinit var logger: Logger lateinit var logger: Logger
@ -19,7 +18,11 @@ abstract class IMatterLink {
abstract val buildNumber: Int abstract val buildNumber: Int
abstract val forgeVersion: String abstract val forgeVersion: String
abstract fun commandSenderFor(user: String, env: IBridgeCommand.CommandEnvironment, op: Boolean): IMinecraftCommandSender abstract fun commandSenderFor(
user: String,
env: IBridgeCommand.CommandEnvironment,
op: Boolean
): IMinecraftCommandSender
abstract fun wrappedSendToPlayers(msg: String) abstract fun wrappedSendToPlayers(msg: String)
@ -29,50 +32,19 @@ abstract class IMatterLink {
abstract fun nameToUUID(username: String): UUID? abstract fun nameToUUID(username: String): UUID?
abstract fun uuidToName(uuid: UUID): String? abstract fun uuidToName(uuid: UUID): String?
init { suspend fun start() {
}
fun start() {
// MessageHandlerInst.logger = { level, msg ->
// when (level) {
// "FATAL" -> logger.fatal(msg)
// "ERROR" -> logger.error(msg)
// "WARN" -> logger.warn(msg)
// "INFO" -> logger.info(msg)
// "DEBUG" -> logger.debug(msg)
// "TRACE" -> logger.trace(msg)
// }
// }
MessageHandlerInst.logger = logger MessageHandlerInst.logger = logger
serverStartTime = System.currentTimeMillis() serverStartTime = System.currentTimeMillis()
if (cfg.connect.autoConnect) if (cfg.connect.autoConnect)
MessageHandlerInst.start("Server started, connecting to matterbridge API", true) MessageHandlerInst.start("Server started, connecting to matterbridge API", true)
UpdateChecker.run() UpdateChecker.check()
} }
fun stop() { suspend fun stop() {
MessageHandlerInst.stop("Server shutting down, disconnecting from matterbridge API") MessageHandlerInst.stop("Server shutting down, disconnecting from matterbridge API")
} }
// abstract fun log(level: String, formatString: String, vararg data: Any)
// fun fatal(formatString: String, vararg data: Any) = log("FATAL", formatString, *data)
// fun error(formatString: String, vararg data: Any) = log("ERROR", formatString, *data)
// fun warn(formatString: String, vararg data: Any) = log("WARN", formatString, *data)
// fun info(formatString: String, vararg data: Any) = log("INFO", formatString, *data)
//
// fun debug(formatString: String, vararg data: Any) {
// if (cfg.debug.logLevel == "DEBUG" || cfg.debug.logLevel == "TRACE")
// log("INFO", "DEBUG: " + formatString.replace("\n", "\nDEBUG: "), *data)
// }
//
// fun trace(formatString: String, vararg data: Any) {
// if (cfg.debug.logLevel == "TRACE")
// log("INFO", "TRACE: " + formatString.replace("\n", "\nTRACE: "), *data)
// }
/** /**
* in milliseconds * in milliseconds
*/ */

View File

@ -1,8 +1,6 @@
package matterlink package matterlink
import blue.endless.jankson.Jankson import blue.endless.jankson.Jankson
import blue.endless.jankson.JsonObject
import blue.endless.jankson.impl.Marshaller
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL

View File

@ -8,9 +8,7 @@ import blue.endless.jankson.impl.Marshaller
import matterlink.config.cfg import matterlink.config.cfg
import java.io.PrintWriter import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import java.lang.Thread.yield
import java.util.* import java.util.*
import kotlin.streams.asSequence
private const val ZWSP: Char = '\u200b' private const val ZWSP: Char = '\u200b'
@ -76,20 +74,27 @@ fun <T : Any> JsonObject.getOrDefault(key: String, default: T, comment: String?
inline fun <reified T : Any> Jankson.fromJson(obj: JsonObject): T = this.fromJson(obj, T::class.java) inline fun <reified T : Any> Jankson.fromJson(obj: JsonObject): T = this.fromJson(obj, T::class.java)
inline fun <reified T : Any> Jankson.fromJson(json: String): T = this.fromJson(json, T::class.java) inline fun <reified T : Any> Jankson.fromJson(json: String): T = this.fromJson(json, T::class.java)
inline fun <reified T : Any> Jankson.Builder.registerTypeAdapter(noinline adapter: (JsonObject) -> T) = this.registerTypeAdapter(T::class.java, adapter) inline fun <reified T : Any> Jankson.Builder.registerTypeAdapter(noinline adapter: (JsonObject) -> T) =
this.registerTypeAdapter(T::class.java, adapter)
inline fun <reified T : Any> Jankson.Builder.registerPrimitiveTypeAdapter(noinline adapter: (Any) -> T) = this.registerPrimitiveTypeAdapter(T::class.java, adapter) inline fun <reified T : Any> Jankson.Builder.registerPrimitiveTypeAdapter(noinline adapter: (Any) -> T) =
this.registerPrimitiveTypeAdapter(T::class.java, adapter)
inline fun <reified T : Any> Jankson.Builder.registerSerializer(noinline serializer: (T, Marshaller) -> JsonElement) = this.registerSerializer(T::class.java, serializer) inline fun <reified T : Any> Jankson.Builder.registerSerializer(noinline serializer: (T, Marshaller) -> JsonElement) =
this.registerSerializer(T::class.java, serializer)
inline fun <reified T : Any> Marshaller.registerSerializer(noinline serializer: (T) -> JsonElement) = this.registerSerializer(T::class.java, serializer) inline fun <reified T : Any> Marshaller.registerSerializer(noinline serializer: (T) -> JsonElement) =
this.registerSerializer(T::class.java, serializer)
inline fun <reified T : Any> Marshaller.registerSerializer(noinline serializer: (T, Marshaller) -> JsonElement) = this.registerSerializer(T::class.java, serializer) inline fun <reified T : Any> Marshaller.registerSerializer(noinline serializer: (T, Marshaller) -> JsonElement) =
this.registerSerializer(T::class.java, serializer)
inline fun <reified T : Any> JsonObject.getReified(key: String, comment: String? = null): T? = this.get(T::class.java, key) inline fun <reified T : Any> JsonObject.getReified(key: String, comment: String? = null): T? =
this.get(T::class.java, key)
?.also { setComment(key, comment) } ?.also { setComment(key, comment) }
inline fun <reified T : Any> JsonObject.getReifiedOrDelete(key: String, comment: String? = null): T? = this.get(T::class.java, key) inline fun <reified T : Any> JsonObject.getReifiedOrDelete(key: String, comment: String? = null): T? =
this.get(T::class.java, key)
?.also { setComment(key, comment) } ?.also { setComment(key, comment) }
?: run { ?: run {
this.remove(key) this.remove(key)
@ -124,7 +129,11 @@ inline fun <reified T : Any> JsonObject.getOrPutList(key: String, default: List<
} ?: this.putDefault(key, default, comment) ?: default } ?: this.putDefault(key, default, comment) ?: default
} }
inline fun <reified T : Any> JsonObject.getOrPutMap(key: String, default: Map<String, T>, comment: String?): Map<String, T> { inline fun <reified T : Any> JsonObject.getOrPutMap(
key: String,
default: Map<String, T>,
comment: String?
): Map<String, T> {
return this[key]?.let { map -> return this[key]?.let { map ->
when (map) { when (map) {
is JsonObject -> { is JsonObject -> {

View File

@ -1,7 +1,10 @@
package matterlink.api package matterlink.api
import com.google.gson.GsonBuilder import kotlinx.serialization.Encoder
import com.google.gson.annotations.SerializedName import kotlinx.serialization.Optional
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.json.JSON
/** /**
* Created by nikky on 07/05/18. * Created by nikky on 07/05/18.
@ -9,84 +12,77 @@ import com.google.gson.annotations.SerializedName
* @author Nikky * @author Nikky
* @version 1.0 * @version 1.0
*/ */
class ApiMessage ( @Serializable
username: String? = null, data class ApiMessage(
text: String? = null, @Optional var username: String = "",
gateway: String? = null, @Optional var text: String = "",
channel: String? = null, @Optional var gateway: String = "",
userid: String? = null, @Optional var timestamp: String = "",
avatar: String? = null, @Optional var channel: String = "",
account: String? = null, @Optional var userid: String = "",
protocol: String? = null, @Optional var avatar: String = "",
event: String? = null, @Optional var account: String = "",
id: String? = null @Optional var protocol: String = "",
@Optional var event: String = "",
@Optional var id: String = "",
@Optional var Extra: Map<String, String>? = null
) { ) {
@SerializedName("username") private var _username: String? = username
@SerializedName("text") private var _text: String? = text
@SerializedName("gateway") private var _gateway: String? = gateway
@SerializedName("channel") private var _channel: String? = channel
@SerializedName("userid") private var _userid: String? = userid
@SerializedName("avatar") private var _avatar: String? = avatar
@SerializedName("account") private var _account: String? = account
@SerializedName("protocol") private var _protocol: String? = protocol
@SerializedName("event") private var _event: String? = event
@SerializedName("id") private var _id: String? = id
var username: String
get() = _username ?: ""
set(username) { this._username = username }
var text: String
get() = _text ?: ""
set(text) { this._text = text }
var gateway: String
get() = _gateway ?: ""
set(gateway) { this._gateway = gateway }
var channel: String
get() = _channel ?: ""
set(channel) { this._channel = channel }
var userid: String
get() = _userid ?: ""
set(userid) { this._userid = userid }
var avatar: String
get() = _avatar ?: ""
set(avatar) { this._avatar = avatar }
var account: String
get() = _account ?: ""
set(account) { this._account = account }
var protocol: String
get() = _protocol ?: ""
set(protocol) { this._protocol = protocol }
var event: String
get() = _event ?: ""
set(event) { this._event = event }
var id: String
get() = _id ?: ""
set(id) { this._id = id }
fun encode(): String { fun encode(): String {
return gson.toJson(this) return JSON.stringify(Companion, this)
} }
override fun toString(): String = encode() override fun toString(): String = encode()
@Serializer(forClass = ApiMessage::class)
companion object { companion object {
override fun serialize(output: Encoder, obj: ApiMessage) {
val elemOutput = output.beginStructure(descriptor)
obj.username.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 0, it)
}
obj.text.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 1, it)
}
obj.gateway.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 2, it)
}
obj.timestamp.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 3, it)
}
obj.channel.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 4, it)
}
obj.userid.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 5, it)
}
obj.avatar.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 6, it)
}
obj.account.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 7, it)
}
obj.protocol.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 8, it)
}
obj.event.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 9, it)
}
obj.id.takeIf { it.isNotEmpty() }?.let {
elemOutput.encodeStringElement(descriptor, 10, it)
}
// obj.Extra.takeIf { ! it.isNullOrEmpty() }?.let {
// elemOutput.encodeStringElement(descriptor, 11, it)
// }
elemOutput.endStructure(descriptor)
}
val USER_ACTION = "user_action" val USER_ACTION = "user_action"
val JOIN_LEAVE = "join_leave" val JOIN_LEAVE = "join_leave"
private val gson = GsonBuilder()
.create()
fun decode(json: String): ApiMessage { fun decode(json: String): ApiMessage {
return gson.fromJson(json, ApiMessage::class.java) return JSON.parse(Companion, json)
} }
} }
} }

View File

@ -7,8 +7,7 @@ data class Config (
var announceDisconnect: Boolean = true, var announceDisconnect: Boolean = true,
var reconnectWait: Long = 500, var reconnectWait: Long = 500,
var systemUser: String = "Server" var systemUser: String = "Server"
) ) {
{
fun sync(connection: StreamConnection) { fun sync(connection: StreamConnection) {
connection.token = token connection.token = token
connection.host = url connection.host = url

View File

@ -1,15 +1,31 @@
package matterlink.api package matterlink.api
import awaitStringResponse
import com.github.kittinunf.fuel.core.FuelManager
import com.github.kittinunf.fuel.core.Method
import com.github.kittinunf.fuel.core.ResponseDeserializable
import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.fuel.httpPost
import com.github.kittinunf.result.Result
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.channels.broadcast
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.JSON
import kotlinx.serialization.list
import matterlink.Logger import matterlink.Logger
import java.io.BufferedReader import java.io.Reader
import java.io.DataOutputStream import kotlin.coroutines.CoroutineContext
import java.io.IOException
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.MalformedURLException
import java.net.ProtocolException
import java.net.URL
import java.util.concurrent.ConcurrentLinkedQueue
/** /**
* Created by nikky on 07/05/18. * Created by nikky on 07/05/18.
@ -17,66 +33,60 @@ import java.util.concurrent.ConcurrentLinkedQueue
* @author Nikky * @author Nikky
* @version 1.0 * @version 1.0
*/ */
open class MessageHandler { open class MessageHandler : CoroutineScope {
override val coroutineContext: CoroutineContext = Job()
private var enabled = false private var enabled = false
private var connectErrors = 0 private var connectErrors = 0
private var reconnectCooldown = 0 private var reconnectCooldown = 0L
private var sendErrors = 0 private var sendErrors = 0
var config: Config = Config()
set(value) { private var sendChannel: SendChannel<ApiMessage> = senderActor()
field = value.apply {
sync(streamConnection) private val messageStream = Channel<ApiMessage>(Channel.UNLIMITED)
var broadcast: BroadcastChannel<ApiMessage> = broadcast {
while (true) {
val msg = messageStream.receive()
send(msg)
} }
} }
//TODO: make callbacks: onConnect onDisconnect onError etc
var queue: ConcurrentLinkedQueue<ApiMessage> = ConcurrentLinkedQueue()
private set private set
private var streamConnection: StreamConnection = StreamConnection(queue) private val keepOpenManager = FuelManager().apply {
timeoutInMillisecond = 0
var logger: Logger timeoutReadInMillisecond = 0
get() = streamConnection.logger
set(l) {
streamConnection.logger = l
} }
var config: Config = Config()
private var nextCheck: Long = 0 var logger = object : Logger {
override fun info(message: String) = println("INFO: $message")
init { override fun debug(message: String) = println("DEBUG: $message")
streamConnection.addOnSuccess { success -> override fun error(message: String) = println("ERROR: $message")
if (success) { override fun warn(message: String) = println("WARN: $message")
logger.info("connected successfully") override fun trace(message: String) = println("TRACE: $message")
connectErrors = 0
reconnectCooldown = 0
} else {
reconnectCooldown = connectErrors
connectErrors++
logger.error(String.format("connectErrors: %d", connectErrors))
}
}
} }
fun stop(message: String? = null) { suspend fun stop(message: String? = null) {
if (message != null && config.announceDisconnect) { if (message != null && config.announceDisconnect) {
sendStatusUpdate(message) sendStatusUpdate(message)
} }
enabled = false enabled = false
streamConnection.close() rcvJob?.cancel()
rcvJob = null
} }
private var rcvJob: Job? = null
fun start(message: String?, clear: Boolean) { suspend fun start(message: String?, clear: Boolean) {
config.sync(streamConnection) logger.debug("starting connection")
if (clear) { if (clear) {
clear() clear()
} }
enabled = true enabled = true
streamConnection.open()
rcvJob = messageBroadcast()
if (message != null && config.announceConnect) { if (message != null && config.announceConnect) {
sendStatusUpdate(message) sendStatusUpdate(message)
@ -84,37 +94,42 @@ open class MessageHandler {
} }
private fun clear() { private suspend fun clear() {
try { val url = "${config.url}/api/messages"
val url = URL(config.url + "/api/messages") val (request, response, result) = url.httpGet()
val conn = url.openConnection() as HttpURLConnection .apply {
if (config.token.isNotEmpty()) {
if (!config.token.isEmpty()) { headers["Authorization"] = "Bearer ${config.token}"
val bearerAuth = "Bearer " + config.token
conn.setRequestProperty("Authorization", bearerAuth)
} }
conn.requestMethod = "GET"
BufferedReader(InputStreamReader(conn.inputStream)).forEachLine { line ->
logger.trace("skipping $line")
} }
} catch (e: MalformedURLException) { .awaitStringResponse()
e.printStackTrace()
} catch (e: ProtocolException) { when (result) {
e.printStackTrace() is Result.Success -> {
} catch (e: IOException) { val messages: List<ApiMessage> = JSON.parse(ApiMessage.list, result.value)
e.printStackTrace() messages.forEach { msg ->
logger.trace("skipping $msg")
}
logger.debug("skipped ${messages.count()} messages")
}
is Result.Failure -> {
logger.error("failed to clear messages")
logger.error("url: $url")
logger.error("cUrl: ${request.cUrlString()}")
logger.error("response: $response")
logger.error(result.error.exception.localizedMessage)
result.error.exception.printStackTrace()
}
} }
} }
open fun sendStatusUpdate(message: String) { open suspend fun sendStatusUpdate(message: String) {
transmit(ApiMessage(text = message)) transmit(ApiMessage(text = message))
} }
open fun transmit(msg: ApiMessage) { open suspend fun transmit(msg: ApiMessage) {
if (streamConnection.isConnected || streamConnection.isConnecting) { // if (streamConnection.isConnected || streamConnection.isConnecting) {
if (msg.username.isEmpty()) if (msg.username.isEmpty())
msg.username = config.systemUser msg.username = config.systemUser
if (msg.gateway.isEmpty()) { if (msg.gateway.isEmpty()) {
@ -122,80 +137,95 @@ open class MessageHandler {
return return
} }
logger.debug("Transmitting: $msg") logger.debug("Transmitting: $msg")
transmitMessage(msg) sendChannel.send(msg)
} // }
} }
private fun transmitMessage(message: ApiMessage) { @Deprecated("use coroutine api", level = DeprecationLevel.ERROR)
try { fun checkConnection() {
val url = URL(config.url + "/api/message")
val conn = url.openConnection() as HttpURLConnection
if (!config.token.isEmpty()) {
val bearerAuth = "Bearer " + config.token
conn.setRequestProperty("Authorization", bearerAuth)
} }
val postData = message.encode() private fun CoroutineScope.senderActor() = actor<ApiMessage>(context = Dispatchers.IO) {
logger.trace(postData) consumeEach {
logger.debug("sending $it")
conn.requestMethod = "POST" val url = "${config.url}/api/message"
conn.setRequestProperty("Content-Type", "application/json") val (request, response, result) = url.httpPost()
conn.setRequestProperty("charset", "utf-8") .apply {
conn.setRequestProperty("Content-Length", "" + postData.toByteArray().size) if (config.token.isNotEmpty()) {
conn.doOutput = true headers["Authorization"] = "Bearer ${config.token}"
conn.doInput = true
DataOutputStream(conn.outputStream).use { wr -> wr.write(postData.toByteArray()) }
// conn.getInputStream().close();
conn.connect()
val code = conn.responseCode
if (code != 200) {
logger.error("Server returned $code")
sendErrors++
if (sendErrors > 5) {
logger.error("Interrupting Connection to matterbridge API due to status code $code")
stop()
} }
} else { }
.jsonBody(it.encode())
.responseString()
when (result) {
is Result.Success -> {
logger.info("sent $it")
sendErrors = 0 sendErrors = 0
} }
} catch (e: IOException) { is Result.Failure -> {
e.printStackTrace()
logger.error("sending message caused $e")
sendErrors++ sendErrors++
if (sendErrors > 5) { logger.error("failed to deliver: $it")
logger.error("Caught too many errors, closing bridge") logger.error("url: $url")
stop() logger.error("cUrl: ${request.cUrlString()}")
logger.error("response: $response")
logger.error(result.error.exception.localizedMessage)
result.error.exception.printStackTrace()
// close()
throw result.error.exception
}
}
} }
} }
private fun CoroutineScope.messageBroadcast() = launch(context = Dispatchers.IO + CoroutineName("msgBroadcaster")) {
loop@ while (isActive) {
logger.info("opening connection")
val url = "${config.url}/api/stream"
val (request, response, result) = keepOpenManager.request(Method.GET, url)
.apply {
if (config.token.isNotEmpty()) {
headers["Authorization"] = "Bearer ${config.token}"
} }
}
.responseObject(object : ResponseDeserializable<Unit> {
override fun deserialize(reader: Reader) =
runBlocking(Dispatchers.IO + CoroutineName("msgReceiver")) {
logger.info("connected successfully")
connectErrors = 0
reconnectCooldown = 0
/** reader.useLines { lines ->
* clll this method every tick / cycle to make sure it is reconnecting lines.forEach { line ->
*/ val msg = ApiMessage.decode(line)
fun checkConnection() { logger.info("received: $msg")
if (enabled && !streamConnection.isConnected && !streamConnection.isConnecting) { if (msg.event != "api_connect") {
logger.trace("check connection") messageStream.send(msg)
logger.trace("next: $nextCheck") }
logger.trace("now: " + System.currentTimeMillis()) }
if (nextCheck > System.currentTimeMillis()) return }
nextCheck = System.currentTimeMillis() + config.reconnectWait }
})
when (result) {
is Result.Success -> {
logger.info("connection closed")
}
is Result.Failure -> {
connectErrors++
reconnectCooldown = connectErrors * 1000L
logger.error("connectErrors: $connectErrors")
logger.error("connection error")
logger.error("curl: ${request.cUrlString()}")
logger.error(result.error.localizedMessage)
result.error.exception.printStackTrace()
if (connectErrors >= 10) { if (connectErrors >= 10) {
logger.error("Caught too many errors, closing bridge") logger.error("Caught too many errors, closing bridge")
stop("Interrupting connection to matterbridge API due to accumulated connection errors") stop("Interrupting connection to matterbridge API due to accumulated connection errors")
return break@loop
}
if (reconnectCooldown <= 0) {
logger.info("Trying to reconnect")
start("Reconnecting to matterbridge API after connection error", false)
} else {
reconnectCooldown--
} }
} }
} }
delay(reconnectCooldown) // reconnect delay in ms
}
}
} }

View File

@ -2,7 +2,6 @@ package matterlink.api
import matterlink.Logger import matterlink.Logger
import java.io.IOException import java.io.IOException
import java.io.InputStream
import java.net.ConnectException import java.net.ConnectException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.MalformedURLException import java.net.MalformedURLException

View File

@ -1,18 +1,23 @@
package matterlink.bridge package matterlink.bridge
import matterlink.* import matterlink.Paste
import matterlink.PasteSection
import matterlink.PasteUtil
import matterlink.antiping
import matterlink.api.ApiMessage import matterlink.api.ApiMessage
import matterlink.api.MessageHandler import matterlink.api.MessageHandler
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.handlers.ChatEvent import matterlink.handlers.ChatEvent
import matterlink.handlers.LocationHandler import matterlink.handlers.LocationHandler
import matterlink.mapFormat
import matterlink.stackTraceString
object MessageHandlerInst : MessageHandler() { object MessageHandlerInst : MessageHandler() {
override fun transmit(msg: ApiMessage) { override suspend fun transmit(msg: ApiMessage) {
transmit(msg, cause = "") transmit(msg, cause = "")
} }
override fun sendStatusUpdate(message: String) { override suspend fun sendStatusUpdate(message: String) {
LocationHandler.sendToLocations( LocationHandler.sendToLocations(
msg = message, msg = message,
x = 0, y = 0, z = 0, dimension = null, x = 0, y = 0, z = 0, dimension = null,
@ -22,7 +27,7 @@ object MessageHandlerInst : MessageHandler() {
) )
} }
fun transmit(msg: ApiMessage, cause: String, maxLines: Int = cfg.outgoing.inlineLimit) { suspend fun transmit(msg: ApiMessage, cause: String, maxLines: Int = cfg.outgoing.inlineLimit) {
if (msg.username.isEmpty()) { if (msg.username.isEmpty()) {
msg.username = cfg.outgoing.systemUser msg.username = cfg.outgoing.systemUser

View File

@ -5,7 +5,7 @@ import matterlink.config.IdentitiesConfig
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.instance import matterlink.instance
import matterlink.randomString import matterlink.randomString
import java.util.* import java.util.UUID
object AuthBridgeCommand : IBridgeCommand() { object AuthBridgeCommand : IBridgeCommand() {
val syntax = "Syntax: auth [username]" val syntax = "Syntax: auth [username]"
@ -13,7 +13,7 @@ object AuthBridgeCommand : IBridgeCommand() {
override val permLevel: Double override val permLevel: Double
get() = cfg.command.defaultPermUnauthenticated get() = cfg.command.defaultPermUnauthenticated
override fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean { override suspend fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean {
if (env !is CommandEnvironment.BridgeEnv) { if (env !is CommandEnvironment.BridgeEnv) {
env.respond("please initiate authentication from linked external chat") env.respond("please initiate authentication from linked external chat")
return true return true
@ -28,8 +28,10 @@ object AuthBridgeCommand : IBridgeCommand() {
val argList = args.split(' ', limit = 2) val argList = args.split(' ', limit = 2)
val target = argList.getOrNull(0) ?: run { val target = argList.getOrNull(0) ?: run {
env.respond("no username/uuid provided\n" + env.respond(
syntax) "no username/uuid provided\n" +
syntax
)
return true return true
} }
@ -62,7 +64,16 @@ object AuthBridgeCommand : IBridgeCommand() {
instance.wrappedSendToPlayer(targetUserName, "otherwise you may ignore this message") instance.wrappedSendToPlayer(targetUserName, "otherwise you may ignore this message")
IdentitiesConfig.authRequests.put(requestId, AuthRequest(username = targetUserName, uuid = targetUUid, nonce = nonce, platform = env.platform, userid = env.userId)) IdentitiesConfig.authRequests.put(
requestId,
AuthRequest(
username = targetUserName,
uuid = targetUUid,
nonce = nonce,
platform = env.platform,
userid = env.userId
)
)
env.respond("please accept the authentication request ingame, do not share the code") env.respond("please accept the authentication request ingame, do not share the code")
return true return true

View File

@ -1,15 +1,13 @@
package matterlink.bridge.command package matterlink.bridge.command
import matterlink.api.ApiMessage import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst
import matterlink.config.CommandConfig import matterlink.config.CommandConfig
import matterlink.config.IdentitiesConfig import matterlink.config.IdentitiesConfig
import matterlink.config.PermissionConfig import matterlink.config.PermissionConfig
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.instance
import matterlink.logger import matterlink.logger
import matterlink.stripColorOut import java.util.HashMap
import java.util.* import java.util.UUID
object BridgeCommandRegistry { object BridgeCommandRegistry {
@ -19,7 +17,7 @@ object BridgeCommandRegistry {
* *
* @return consume message flag * @return consume message flag
*/ */
fun handleCommand(input: ApiMessage): Boolean { suspend fun handleCommand(input: ApiMessage): Boolean {
if (!cfg.command.enable || input.text.isBlank()) return false if (!cfg.command.enable || input.text.isBlank()) return false
if (input.text[0] != cfg.command.prefix || input.text.length < 2) return false if (input.text[0] != cfg.command.prefix || input.text.length < 2) return false
@ -29,7 +27,13 @@ object BridgeCommandRegistry {
val uuid = IdentitiesConfig.getUUID(input.account, input.userid) val uuid = IdentitiesConfig.getUUID(input.account, input.userid)
val env = IBridgeCommand.CommandEnvironment.BridgeEnv(input.username, input.userid, input.account, input.gateway, uuid) val env = IBridgeCommand.CommandEnvironment.BridgeEnv(
input.username,
input.userid,
input.account,
input.gateway,
uuid
)
return commandMap[cmd[0]]?.let { return commandMap[cmd[0]]?.let {
if (!it.reachedTimeout()) { if (!it.reachedTimeout()) {
logger.debug("dropped command ${it.alias}") logger.debug("dropped command ${it.alias}")
@ -46,7 +50,7 @@ object BridgeCommandRegistry {
} ?: false } ?: false
} }
fun handleCommand(text: String, username: String, uuid: UUID): Boolean { suspend fun handleCommand(text: String, username: String, uuid: UUID): Boolean {
if (!cfg.command.enable || text.isBlank()) return false if (!cfg.command.enable || text.isBlank()) return false
if (text[0] != cfg.command.prefix || text.length < 2) return false if (text[0] != cfg.command.prefix || text.length < 2) return false

View File

@ -17,7 +17,7 @@ data class CustomCommand(
val argumentsRegex: Regex? = null val argumentsRegex: Regex? = null
) : IBridgeCommand() { ) : IBridgeCommand() {
override fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean { override suspend fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean {
if (argumentsRegex != null) { if (argumentsRegex != null) {
logger.debug("testing '$args' against '${argumentsRegex.pattern}'") logger.debug("testing '$args' against '${argumentsRegex.pattern}'")
if (!argumentsRegex.matches(args)) { if (!argumentsRegex.matches(args)) {
@ -35,8 +35,10 @@ data class CustomCommand(
commandSender.execute(cmd) || commandSender.reply.isNotEmpty() commandSender.execute(cmd) || commandSender.reply.isNotEmpty()
} }
CommandType.RESPONSE -> { CommandType.RESPONSE -> {
env.respond(response?.lazyFormat(getReplacements(user, env, args)) env.respond(
?: "", cause = "response to command: $alias") response?.lazyFormat(getReplacements(user, env, args))
?: "", cause = "response to command: $alias"
)
true true
} }

View File

@ -1,16 +1,13 @@
package matterlink.bridge.command package matterlink.bridge.command
import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.stripColorOut
object HelpCommand : IBridgeCommand() { object HelpCommand : IBridgeCommand() {
override val help: String = "Returns the help string for the given command. Syntax: help <command>" override val help: String = "Returns the help string for the given command. Syntax: help <command>"
override val permLevel: Double override val permLevel: Double
get() = cfg.command.defaultPermUnauthenticated get() = cfg.command.defaultPermUnauthenticated
override fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean { override suspend fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean {
val msg: String = when { val msg: String = when {
args.isEmpty() -> args.isEmpty() ->
"Available commands: ${BridgeCommandRegistry.getCommandList(IBridgeCommand.getPermLevel(env.uuid))}" "Available commands: ${BridgeCommandRegistry.getCommandList(IBridgeCommand.getPermLevel(env.uuid))}"

View File

@ -8,7 +8,7 @@ import matterlink.handlers.TickHandler
import matterlink.instance import matterlink.instance
import matterlink.logger import matterlink.logger
import matterlink.stripColorOut import matterlink.stripColorOut
import java.util.* import java.util.UUID
abstract class IBridgeCommand { abstract class IBridgeCommand {
abstract val help: String abstract val help: String
@ -35,7 +35,7 @@ abstract class IBridgeCommand {
override val uuid: UUID override val uuid: UUID
) : CommandEnvironment() ) : CommandEnvironment()
fun respond(text: String, cause: String = "") { suspend fun respond(text: String, cause: String = "") {
when (this) { when (this) {
is BridgeEnv -> { is BridgeEnv -> {
MessageHandlerInst.transmit( MessageHandlerInst.transmit(
@ -72,7 +72,7 @@ abstract class IBridgeCommand {
* *
* @return consume message flag * @return consume message flag
*/ */
abstract fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean abstract suspend fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean
fun canExecute(uuid: UUID?): Boolean { fun canExecute(uuid: UUID?): Boolean {
logger.trace("canExecute this: $this uuid: $uuid permLevel: $permLevel") logger.trace("canExecute this: $this uuid: $uuid permLevel: $permLevel")

View File

@ -1,7 +1,5 @@
package matterlink.bridge.command package matterlink.bridge.command
import matterlink.stripColorOut
abstract class IMinecraftCommandSender(val user: String, val env: IBridgeCommand.CommandEnvironment, val op: Boolean) { abstract class IMinecraftCommandSender(val user: String, val env: IBridgeCommand.CommandEnvironment, val op: Boolean) {
/** /**
* @param cmdString The command to execute with its arguments * @param cmdString The command to execute with its arguments
@ -37,7 +35,7 @@ abstract class IMinecraftCommandSender(val user: String, val env: IBridgeCommand
reply += text reply += text
} }
fun sendReply(cmdString: String) { suspend fun sendReply(cmdString: String) {
env.respond( env.respond(
text = reply.joinToString("\n"), text = reply.joinToString("\n"),
cause = "executed command: $cmdString" cause = "executed command: $cmdString"

View File

@ -11,7 +11,7 @@ object RequestPermissionsCommand : IBridgeCommand() {
override val permLevel: Double override val permLevel: Double
get() = cfg.command.defaultPermAuthenticated get() = cfg.command.defaultPermAuthenticated
override fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean { override suspend fun execute(alias: String, user: String, env: CommandEnvironment, args: String): Boolean {
val uuid = env.uuid val uuid = env.uuid
if (uuid == null) { if (uuid == null) {
@ -23,8 +23,10 @@ object RequestPermissionsCommand : IBridgeCommand() {
val requestedLevelArg = argList.getOrNull(0) val requestedLevelArg = argList.getOrNull(0)
val requestedLevel = requestedLevelArg?.takeIf { it.isNotEmpty() }?.let { val requestedLevel = requestedLevelArg?.takeIf { it.isNotEmpty() }?.let {
it.toDoubleOrNull() ?: run { it.toDoubleOrNull() ?: run {
env.respond("cannot parse permlevel '$requestedLevelArg'\n" + env.respond(
syntax) "cannot parse permlevel '$requestedLevelArg'\n" +
syntax
)
return true return true
} }
} }
@ -33,7 +35,10 @@ object RequestPermissionsCommand : IBridgeCommand() {
val requestId = user.toLowerCase() val requestId = user.toLowerCase()
PermissionConfig.permissionRequests.put(requestId, PermissionRequest(uuid = uuid, user = user, nonce = nonce, powerlevel = requestedLevel)) PermissionConfig.permissionRequests.put(
requestId,
PermissionRequest(uuid = uuid, user = user, nonce = nonce, powerlevel = requestedLevel)
)
env.respond("please ask a op to accept your permission elevation with `/ml permAccept $requestId $nonce [permLevel]`") env.respond("please ask a op to accept your permission elevation with `/ml permAccept $requestId $nonce [permLevel]`")
return true return true

View File

@ -1,11 +1,6 @@
package matterlink.command package matterlink.command
import matterlink.bridge.MessageHandlerInst
import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.config.IdentitiesConfig import matterlink.config.IdentitiesConfig
import matterlink.config.PermissionConfig
import matterlink.config.baseCfg
import matterlink.config.cfg
object CommandCoreAuth { object CommandCoreAuth {
val name = "auth" val name = "auth"
@ -38,7 +33,13 @@ object CommandCoreAuth {
return "uuid in request does not match ${request.uuid} != $uuid" return "uuid in request does not match ${request.uuid} != $uuid"
} }
IdentitiesConfig.add(request.uuid, request.username, request.platform, request.userid, "Accepted by $user") IdentitiesConfig.add(
request.uuid,
request.username,
request.platform,
request.userid,
"Accepted by $user"
)
IdentitiesConfig.authRequests.invalidate(requestId) IdentitiesConfig.authRequests.invalidate(requestId)
"${request.userid} on ${request.platform} is now identified as $user" "${request.userid} on ${request.platform} is now identified as $user"

View File

@ -13,7 +13,7 @@ object CommandCoreML {
val usage = "ml <connect|disconnect|reload|permAccept>" val usage = "ml <connect|disconnect|reload|permAccept>"
fun execute(args: Array<String>, user: String, uuid: String?): String { suspend fun execute(args: Array<String>, user: String, uuid: String?): String {
val cmd = args[0].toLowerCase() val cmd = args[0].toLowerCase()
return when (cmd) { return when (cmd) {

View File

@ -4,12 +4,17 @@ import blue.endless.jankson.Jankson
import blue.endless.jankson.JsonObject import blue.endless.jankson.JsonObject
import blue.endless.jankson.impl.Marshaller import blue.endless.jankson.impl.Marshaller
import blue.endless.jankson.impl.SyntaxError import blue.endless.jankson.impl.SyntaxError
import matterlink.* import matterlink.Area
import matterlink.bridge.MessageHandlerInst import matterlink.bridge.MessageHandlerInst
import matterlink.getOrDefault
import matterlink.getOrPutList
import matterlink.getReifiedOrDelete
import matterlink.logger
import matterlink.registerSerializer
import matterlink.registerTypeAdapter
import matterlink.stackTraceString
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.util.*
import kotlin.collections.LinkedHashMap
lateinit var cfg: BaseConfig.MatterLinkConfig lateinit var cfg: BaseConfig.MatterLinkConfig
lateinit var baseCfg: BaseConfig lateinit var baseCfg: BaseConfig
@ -174,7 +179,15 @@ data class BaseConfig(val rootDir: File) {
"explosion" to arrayOf("\uD83D\uDCA3", "\uD83D\uDCA5"), //💣 💥 "explosion" to arrayOf("\uD83D\uDCA3", "\uD83D\uDCA5"), //💣 💥
"explosion.player" to arrayOf("\uD83D\uDCA3", "\uD83D\uDCA5"), //💣 💥 "explosion.player" to arrayOf("\uD83D\uDCA3", "\uD83D\uDCA5"), //💣 💥
"ieWireShock" to arrayOf("\uD83D\uDD0C", "\u26A1"), //🔌 ⚡ "ieWireShock" to arrayOf("\uD83D\uDD0C", "\u26A1"), //🔌 ⚡
"immersiverailroading:hitByTrain" to arrayOf("\uD83D\uDE82", "\uD83D\uDE83", "\uD83D\uDE84", "\uD83D\uDE85", "\uD83D\uDE87", "\uD83D\uDE88", "\uD83D\uDE8A") //🚂 🚃 🚄 🚅 🚇 🚈 🚊 "immersiverailroading:hitByTrain" to arrayOf(
"\uD83D\uDE82",
"\uD83D\uDE83",
"\uD83D\uDE84",
"\uD83D\uDE85",
"\uD83D\uDE87",
"\uD83D\uDE88",
"\uD83D\uDE8A"
) //🚂 🚃 🚄 🚅 🚇 🚈 🚊
) )
) )
@ -362,7 +375,8 @@ data class BaseConfig(val rootDir: File) {
.registerTypeAdapter { .registerTypeAdapter {
with(Location()) { with(Location()) {
Location( Location(
label = it.getOrDefault("label", label = it.getOrDefault(
"label",
label, label,
"location label for identification" "location label for identification"
), ),
@ -549,7 +563,7 @@ data class BaseConfig(val rootDir: File) {
"damageTypMapping", "damageTypMapping",
"Damage type mapping for death cause" "Damage type mapping for death cause"
) )
it.mapValues { (key, element) -> it.mapValues { (key, _) ->
it.getOrDefault(key, damageTypeMapping[key] ?: emptyArray(), key) it.getOrDefault(key, damageTypeMapping[key] ?: emptyArray(), key)
.apply { it[key] }.apply { .apply { it[key] }.apply {
jsonObj["damageTypeMapping"] = it jsonObj["damageTypeMapping"] = it
@ -628,7 +642,7 @@ data class BaseConfig(val rootDir: File) {
} }
jsonObject jsonObject
} }
.build() .build()!!
} }
fun load(): MatterLinkConfig { fun load(): MatterLinkConfig {

View File

@ -4,9 +4,12 @@ import blue.endless.jankson.Jankson
import blue.endless.jankson.JsonObject import blue.endless.jankson.JsonObject
import blue.endless.jankson.JsonPrimitive import blue.endless.jankson.JsonPrimitive
import blue.endless.jankson.impl.SyntaxError import blue.endless.jankson.impl.SyntaxError
import matterlink.*
import matterlink.bridge.command.CommandType import matterlink.bridge.command.CommandType
import matterlink.bridge.command.CustomCommand import matterlink.bridge.command.CustomCommand
import matterlink.getOrDefault
import matterlink.logger
import matterlink.registerPrimitiveTypeAdapter
import matterlink.registerTypeAdapter
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException

View File

@ -11,7 +11,7 @@ import matterlink.logger
import matterlink.stackTraceString import matterlink.stackTraceString
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.util.* import java.util.UUID
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
typealias IdentMap = Map<String, Map<String, List<String>>> typealias IdentMap = Map<String, Map<String, List<String>>>

View File

@ -6,11 +6,10 @@ import blue.endless.jankson.impl.SyntaxError
import com.google.common.cache.Cache import com.google.common.cache.Cache
import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheBuilder
import matterlink.getReified import matterlink.getReified
import matterlink.instance
import matterlink.logger import matterlink.logger
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.util.* import java.util.UUID
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
typealias PermissionMap = Map<String, Double> typealias PermissionMap = Map<String, Double>

View File

@ -1,18 +1,23 @@
package matterlink.handlers package matterlink.handlers
import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst
import matterlink.bridge.command.BridgeCommandRegistry import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.config.cfg
import matterlink.logger import matterlink.logger
import matterlink.stripColorOut import java.util.UUID
import java.util.*
object ChatProcessor { object ChatProcessor {
/** /**
* @return cancel message flag * @return cancel message flag
*/ */
fun sendToBridge(user: String, msg: String, x: Int, y: Int, z: Int, dimension: Int?, event: ChatEvent, uuid: UUID? = null): Boolean { suspend fun sendToBridge(
user: String,
msg: String,
x: Int,
y: Int,
z: Int,
dimension: Int?,
event: ChatEvent,
uuid: UUID? = null
): Boolean {
//TODO: pass message to Locations //TODO: pass message to Locations
logger.info("position: $x $y $z dimension: $dimension") logger.info("position: $x $y $z dimension: $dimension")
val message = msg.trim() val message = msg.trim()

View File

@ -1,16 +1,14 @@
package matterlink.handlers package matterlink.handlers
import matterlink.antiping import matterlink.antiping
import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.stripColorOut import matterlink.stripColorOut
import java.util.* import java.util.Random
object DeathHandler { object DeathHandler {
private val random = Random() private val random = Random()
fun handleDeath( suspend fun handleDeath(
player: String, player: String,
deathMessage: String, deathMessage: String,
damageType: String, damageType: String,

View File

@ -1,17 +1,16 @@
package matterlink.handlers package matterlink.handlers
import matterlink.antiping import matterlink.antiping
import matterlink.api.ApiMessage
import matterlink.api.ApiMessage.Companion.JOIN_LEAVE
import matterlink.bridge.MessageHandlerInst
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.mapFormat import matterlink.mapFormat
import matterlink.stripColorOut import matterlink.stripColorOut
object JoinLeaveHandler { object JoinLeaveHandler {
fun handleJoin(player: String, suspend fun handleJoin(
player: String,
x: Int, y: Int, z: Int, x: Int, y: Int, z: Int,
dimension: Int) { dimension: Int
) {
if (cfg.outgoing.joinPart.enable) { if (cfg.outgoing.joinPart.enable) {
val msg = cfg.outgoing.joinPart.joinServer.mapFormat( val msg = cfg.outgoing.joinPart.joinServer.mapFormat(
mapOf( mapOf(
@ -29,9 +28,11 @@ object JoinLeaveHandler {
} }
} }
fun handleLeave(player: String, suspend fun handleLeave(
player: String,
x: Int, y: Int, z: Int, x: Int, y: Int, z: Int,
dimension: Int) { dimension: Int
) {
if (cfg.outgoing.joinPart.enable) { if (cfg.outgoing.joinPart.enable) {
val msg = cfg.outgoing.joinPart.partServer.mapFormat( val msg = cfg.outgoing.joinPart.partServer.mapFormat(
mapOf( mapOf(

View File

@ -5,7 +5,7 @@ import matterlink.bridge.MessageHandlerInst
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.logger import matterlink.logger
import matterlink.stripColorOut import matterlink.stripColorOut
import java.util.* import java.util.UUID
enum class ChatEvent { enum class ChatEvent {
@ -14,7 +14,7 @@ enum class ChatEvent {
object LocationHandler { object LocationHandler {
fun sendToLocations( suspend fun sendToLocations(
user: String = cfg.outgoing.systemUser, user: String = cfg.outgoing.systemUser,
msg: String, msg: String,
x: Int, y: Int, z: Int, x: Int, y: Int, z: Int,

View File

@ -1,16 +1,16 @@
package matterlink.handlers package matterlink.handlers
import matterlink.antiping import matterlink.antiping
import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.stripColorOut import matterlink.stripColorOut
object ProgressHandler { object ProgressHandler {
fun handleProgress(name: String, message: String, display: String, suspend fun handleProgress(
name: String, message: String, display: String,
x: Int, y: Int, z: Int, x: Int, y: Int, z: Int,
dimension: Int) { dimension: Int
) {
if (!cfg.outgoing.advancements) return if (!cfg.outgoing.advancements) return
val usr = name.stripColorOut.antiping val usr = name.stripColorOut.antiping
LocationHandler.sendToLocations( LocationHandler.sendToLocations(

View File

@ -7,17 +7,16 @@ import matterlink.bridge.format
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.instance import matterlink.instance
import matterlink.logger import matterlink.logger
import java.util.* import java.util.UUID
object ServerChatHandler { object ServerChatHandler {
val rcvChannel = MessageHandlerInst.broadcast.openSubscription()
/** /**
* This method must be called every server tick with no arguments. * This method must be called every server tick with no arguments.
*/ */
fun writeIncomingToChat() { suspend fun writeIncomingToChat() {
if (MessageHandlerInst.queue.isNotEmpty()) val nextMessage = rcvChannel.poll() ?: return
logger.debug("incoming: " + MessageHandlerInst.queue.toString())
val nextMessage = MessageHandlerInst.queue.poll() ?: return
val defaults = cfg.incomingDefaults val defaults = cfg.incomingDefaults
@ -101,7 +100,6 @@ object ServerChatHandler {
} }
// if (nextMessage?.gateway == cfg.connect.gateway) { // if (nextMessage?.gateway == cfg.connect.gateway) {
// if (!nextMessage.text.isBlank()) { // if (!nextMessage.text.isBlank()) {
// nextMessage.text = nextMessage.text.stripColorIn // nextMessage.text = nextMessage.text.stripColorIn

View File

@ -1,6 +1,5 @@
package matterlink.handlers package matterlink.handlers
import matterlink.bridge.MessageHandlerInst
import matterlink.update.UpdateChecker import matterlink.update.UpdateChecker
/** /**
@ -13,17 +12,17 @@ object TickHandler {
private set private set
private var accumulator = 0 private var accumulator = 0
private const val updateInterval = 12 * 60 * 60 * 20 private const val updateInterval = 12 * 60 * 60 * 20
fun handleTick() { suspend fun handleTick() {
tickCounter++ tickCounter++
if (tickCounter % 100 == 0) { // if (tickCounter % 100 == 0) {
MessageHandlerInst.checkConnection() // MessageHandlerInst.checkConnection()
} // }
ServerChatHandler.writeIncomingToChat() ServerChatHandler.writeIncomingToChat()
if (accumulator++ > updateInterval) { if (accumulator++ > updateInterval) {
accumulator -= updateInterval accumulator -= updateInterval
UpdateChecker.run() UpdateChecker.check()
} }
} }
} }

View File

@ -1,6 +1,6 @@
package matterlink.jenkins package matterlink.jenkins
import java.util.* import java.util.Date
//@JsonIgnoreProperties(ignoreUnknown = true) //@JsonIgnoreProperties(ignoreUnknown = true)
data class BuildWithDetails( data class BuildWithDetails(

View File

@ -1,32 +1,31 @@
package matterlink.update package matterlink.update
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import matterlink.api.ApiMessage import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst import matterlink.bridge.MessageHandlerInst
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.handlers.ChatEvent import matterlink.handlers.ChatEvent
import matterlink.handlers.LocationHandler import matterlink.handlers.LocationHandler
import matterlink.instance import matterlink.instance
import matterlink.logger
import matterlink.jenkins.JenkinsServer import matterlink.jenkins.JenkinsServer
import matterlink.logger
import java.io.BufferedReader import java.io.BufferedReader
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
class UpdateChecker : Thread() { object UpdateChecker : CoroutineScope {
companion object { override val coroutineContext = Job() + CoroutineName("UpdateChacker")
fun run() {
suspend fun check() {
if (cfg.update.enable) { if (cfg.update.enable) {
UpdateChecker().start() run()
}
} }
} }
init { private suspend fun run() {
name = "UpdateCheckerThread"
}
override fun run() {
if (instance.buildNumber > 0) { if (instance.buildNumber > 0) {
val server = JenkinsServer("https://ci.elytradev.com") val server = JenkinsServer("https://ci.elytradev.com")
val job = server.getJob("elytra/MatterLink/master", "MatterLink/${instance.modVersion}") val job = server.getJob("elytra/MatterLink/master", "MatterLink/${instance.modVersion}")
@ -72,7 +71,8 @@ class UpdateChecker : Thread() {
val con = url.openConnection() as HttpURLConnection val con = url.openConnection() as HttpURLConnection
with(instance) { with(instance) {
val useragent = "MatterLink/$modVersion MinecraftForge/$mcVersion-$forgeVersion (https://github.com/elytra/MatterLink)" val useragent =
"MatterLink/$modVersion MinecraftForge/$mcVersion-$forgeVersion (https://github.com/elytra/MatterLink)"
logger.debug("setting User-Agent: '$useragent'") logger.debug("setting User-Agent: '$useragent'")
con.setRequestProperty("User-Agent", useragent) con.setRequestProperty("User-Agent", useragent)
} }

View File

@ -1,10 +1,10 @@
modName = MatterLink modName = MatterLink
modVersion = 1.6.4 modVersion = 1.6.4
forgelinVersion = 1.6.0 forgelinVersion = 1.8.0
kotlinVersion = 1.2.41 kotlinVersion = 1.3.0
shadowVersion = 2.0.2 shadowVersion = 2.0.2
fuelVersion = 1.13.0 fuelVersion = 1.16.0
resultVersion = 1.4.0 resultVersion = 1.6.0
cursegradleVersion = 1.0.10 cursegradleVersion = 1.1.0
curseId = 287323 curseId = 287323
curseReleaseType = beta curseReleaseType = beta

0
scripts/start.sh Normal file → Executable file
View File

0
scripts/test12.sh Normal file → Executable file
View File

0
scripts/test7.sh Normal file → Executable file
View File

0
scripts/test9.sh Normal file → Executable file
View File