diff --git a/1.11.2/build.gradle b/1.11.2/build.gradle new file mode 100644 index 0000000..50e452c --- /dev/null +++ b/1.11.2/build.gradle @@ -0,0 +1,49 @@ + +buildscript { + repositories { + jcenter() + maven { url = "http://files.minecraftforge.net/maven" } + mavenCentral() + } + dependencies { + classpath "net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT" + } +} + +apply plugin: 'net.minecraftforge.gradle.forge' + +minecraft { + version = mc_version + "-" + forge_version + runDir = "../run" + + mappings = mcp_mappings + + replaceIn 'MatterLink.kt' + replace '@VERSION@', mod_version +} + +processResources { + // this will ensure that this task is redone when the versions change. + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // replace stuff in mcmod.info, nothing else + from(project(":core").sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace version and mcversion + expand 'version': project.version, 'mcversion': project.minecraft.version + } + + // copy everything else except the mcmod.info + from(project(":core").sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } + +} + +reobf { + shadowJar { mappingType = 'SEARGE' } +} + +tasks.reobfShadowJar.mustRunAfter shadowJar \ No newline at end of file diff --git a/1.11.2/gradle.properties b/1.11.2/gradle.properties new file mode 100644 index 0000000..4bc3c4c --- /dev/null +++ b/1.11.2/gradle.properties @@ -0,0 +1,4 @@ +mc_version = 1.11.2 +mcp_mappings = stable_32 +forge_version = 13.20.1.2386 +forgegradle_version = 2.3-SNAPSHOT \ No newline at end of file diff --git a/1.11.2/src/main/kotlin/matterlink/EventWrapper.kt b/1.11.2/src/main/kotlin/matterlink/EventWrapper.kt new file mode 100644 index 0000000..c987464 --- /dev/null +++ b/1.11.2/src/main/kotlin/matterlink/EventWrapper.kt @@ -0,0 +1,98 @@ +package matterlink + +import matterlink.bridge.ServerChatHandler +import matterlink.bridge.USER_ACTION +import matterlink.config.cfg +import matterlink.handlers.* +import net.minecraft.command.server.CommandBroadcast +import net.minecraft.command.server.CommandEmote +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.server.dedicated.DedicatedServer +import net.minecraft.tileentity.TileEntityCommandBlock +import net.minecraftforge.event.CommandEvent +import net.minecraftforge.event.ServerChatEvent +import net.minecraftforge.event.entity.living.LivingDeathEvent +import net.minecraftforge.event.entity.player.AdvancementEvent +import net.minecraftforge.fml.common.FMLCommonHandler +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.PlayerEvent +import net.minecraftforge.fml.common.gameevent.TickEvent + +//FORGE-DEPENDENT +@Mod.EventBusSubscriber +object EventWrapper { + + //MC-VERSION & FORGE DEPENDENT + @SubscribeEvent + @JvmStatic + fun progressEvent(e: AdvancementEvent) { + if (e.advancement.display == null) return + val name = e.entityPlayer.name + val text = "has made the advancement ${e.advancement.displayText.unformattedText}" + ProgressHandler.handleProgress(name, text) + } + + //FORGE-DEPENDENT + @SubscribeEvent + @JvmStatic + fun chatEvent(e: ServerChatEvent) { + val user = e.username + val msg = e.message + ChatHandler.handleChat(user, msg) + } + + //FORGE-DEPENDENT + @SubscribeEvent + @JvmStatic + fun commandEvent(e: CommandEvent) { + val sender = + when { + e.sender is EntityPlayer -> e.sender.name + e.sender is DedicatedServer -> cfg!!.relay.systemUser + e.sender is TileEntityCommandBlock -> "CommandBlock" + else -> return + } + val args = e.parameters.joinToString(" ") + val type = when { + e.command is CommandEmote -> USER_ACTION + e.command is CommandBroadcast -> "" + else -> return + } + CommandHandler.handleCommand(sender, args, type) + + } + + //FORGE-DEPENDENT + @SubscribeEvent + @JvmStatic + fun deathEvent(e: LivingDeathEvent) { + if (e.entityLiving is EntityPlayer) { + DeathHandler.handleDeath( + e.entityLiving.name, + e.entityLiving.combatTracker.deathMessage.unformattedText + ) + } + } + + //FORGE-DEPENDENT + @SubscribeEvent + @JvmStatic + fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) { + JoinLeaveHandler.handleJoin(e.player.name) + } + + //FORGE-DEPENDENT + @SubscribeEvent + @JvmStatic + fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) { + JoinLeaveHandler.handleLeave(e.player.name) + } + + //FORGE-DEPENDENT + @SubscribeEvent + @JvmStatic + fun serverTickEvent(e: TickEvent.ServerTickEvent) { + ServerChatHandler.writeIncomingToChat(FMLCommonHandler.instance().minecraftServerInstance.tickCounter) + } +} \ No newline at end of file diff --git a/1.11.2/src/main/kotlin/matterlink/MatterLink.kt b/1.11.2/src/main/kotlin/matterlink/MatterLink.kt new file mode 100644 index 0000000..fe431de --- /dev/null +++ b/1.11.2/src/main/kotlin/matterlink/MatterLink.kt @@ -0,0 +1,71 @@ +package matterlink + +import matterlink.bridge.MessageHandler +import matterlink.bridge.command.BridgeCommandRegistry +import matterlink.bridge.command.HelpCommand +import matterlink.bridge.command.PlayerListCommand +import matterlink.command.CommandMatterlink +import net.minecraft.util.text.TextComponentString +import net.minecraftforge.fml.common.FMLCommonHandler +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.event.* + +const val MODID = "matterlink" +const val NAME = "MatterLink" +const val VERSION = "@VERSION@" + +@Mod( + modid = MODID, + name = NAME, version = VERSION, + serverSideOnly = true, + useMetadata = true, + acceptableRemoteVersions = "*", + modLanguageAdapter = "net.shadowfacts.forgelin.KotlinAdapter" +) +object MatterLink : IMatterLink() { + init { + instance = this + } + + @Mod.EventHandler + fun preInit(event: FMLPreInitializationEvent) { + logger = event.modLog + logger.info("Building bridge!") + + MatterLinkConfig(event.suggestedConfigurationFile) + } + + @Mod.EventHandler + fun init(event: FMLInitializationEvent) { + BridgeCommandRegistry.registerAll(PlayerListCommand, HelpCommand) + } + + @Mod.EventHandler + fun serverAboutToStart(event: FMLServerAboutToStartEvent) { + MessageHandler.start(clear = true) + } + + @Mod.EventHandler + fun serverStarting(event: FMLServerStartingEvent) { + logger.debug("Registering server commands") + event.registerServerCommand(CommandMatterlink()) + + connect() + } + + @Mod.EventHandler + fun serverStopping(event: FMLServerStoppingEvent) { + disconnect() + } + + //FORGE-DEPENDENT + override fun wrappedSendToPlayers(msg: String) { + FMLCommonHandler.instance().minecraftServerInstance.playerList.sendMessage(TextComponentString(msg)) + } + + //FORGE-DEPENDENT + override fun wrappedPlayerList(): Array { + return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames + } + +} diff --git a/1.11.2/src/main/kotlin/matterlink/MatterLinkConfig.kt b/1.11.2/src/main/kotlin/matterlink/MatterLinkConfig.kt new file mode 100644 index 0000000..3214c79 --- /dev/null +++ b/1.11.2/src/main/kotlin/matterlink/MatterLinkConfig.kt @@ -0,0 +1,128 @@ +package matterlink + +import matterlink.config.IMatterLinkConfig +import matterlink.config.cfg +import net.minecraftforge.common.config.Configuration +import java.io.File +import java.util.regex.Pattern + +class MatterLinkConfig(file: File) : IMatterLinkConfig() { + init { + logger.info("Reading bridge blueprints... from {}", file) + val config = Configuration(file) + + config.addCustomCategoryComment(CATEGORY_RELAY_OPTIONS, "Relay options") + relay = RelayOptions( + + systemUser = config.getString( + "systemUser", + CATEGORY_RELAY_OPTIONS, + relay.systemUser, + "Name of the server user (used by death and advancement messages and the /say command)" + ), + deathEvents = config.getBoolean( + "deathEvents", + CATEGORY_RELAY_OPTIONS, + relay.deathEvents, + "Relay player death messages" + ), + advancements = config.getBoolean( + "advancements", + CATEGORY_RELAY_OPTIONS, + relay.advancements, + "Relay player advancements" + ), + joinLeave = config.getBoolean( + "joinLeave", + CATEGORY_RELAY_OPTIONS, + relay.joinLeave, + "Relay when a player joins or leaves the game" + ) + ) + + config.addCustomCategoryComment(CATEGORY_COMMAND, "User commands") + command = CommandOptions( + enable = config.getBoolean( + "enable", + CATEGORY_COMMAND, + command.enable, + "Enable MC bridge commands" + ), + prefix = config.getString( + "prefix", + CATEGORY_COMMAND, + command.prefix, + "Prefix for MC bridge commands. Accepts a single character (not alphanumeric or /)", + Pattern.compile("^[^0-9A-Za-z/]$") + ) + ) + + config.addCustomCategoryComment(CATEGORY_FORMATTING_INCOMING, "Gateway -> Server" + + "Formatting options: " + + "Available variables: {username}, {text}, {gateway}, {channel}, {protocol}, {username:antiping}") + formatting = FormattingOptions( + chat = config.getString( + "chat", + CATEGORY_FORMATTING_INCOMING, + formatting.chat, + "Generic chat event, just talking" + ), + joinLeave = config.getString( + "joinLeave", + CATEGORY_FORMATTING_INCOMING, + formatting.joinLeave, + "Join and leave events from other gateways" + ), + action = config.getString( + "action", + CATEGORY_FORMATTING_INCOMING, + formatting.action, + "User actions (/me) sent by users from other gateways" + ) + ) + + config.addCustomCategoryComment(CATEGORY_FORMATTING_JOIN_LEAVE, "Server -> Gateway" + + "Formatting options: " + + "Available variables: {username}, {username:antiping}") + formattingJoinLeave = FormattingJoinLeave( + joinServer = config.getString( + "joinServer", + CATEGORY_FORMATTING_JOIN_LEAVE, + formattingJoinLeave.joinServer, + "user join message sent to other gateways, available variables: {username}, {username:antiping}" + ), + leaveServer = config.getString( + "leaveServer", + CATEGORY_FORMATTING_JOIN_LEAVE, + formattingJoinLeave.leaveServer, + "user leave message sent to other gateways, available variables: {username}, {username:antiping}" + ) + ) + + config.addCustomCategoryComment(CATEGORY_CONNECTION, "Connection settings") + connect = ConnectOptions( + url = config.getString( + "connectURL", + CATEGORY_CONNECTION, + connect.url, + "The URL or IP address of the bridge server" + ), + authToken = config.getString( + "authToken", + CATEGORY_CONNECTION, + connect.authToken, + "Auth token used to connect to the bridge server" + ), + gateway = config.getString( + "gateway", + CATEGORY_CONNECTION, + connect.gateway, + "MatterBridge gateway" + ) + ) + + if (config.hasChanged()) config.save() + + cfg = this + } +} \ No newline at end of file diff --git a/1.11.2/src/main/kotlin/matterlink/command/CommandMatterlink.kt b/1.11.2/src/main/kotlin/matterlink/command/CommandMatterlink.kt new file mode 100644 index 0000000..50b5131 --- /dev/null +++ b/1.11.2/src/main/kotlin/matterlink/command/CommandMatterlink.kt @@ -0,0 +1,53 @@ +package matterlink.command + +import com.google.common.collect.Lists +import matterlink.MODID +import matterlink.bridge.MessageHandler +import matterlink.bridge.ServerChatHandler +import matterlink.instance +import matterlink.logger +import net.minecraft.command.CommandBase +import net.minecraft.command.ICommandSender +import net.minecraft.server.MinecraftServer + + +class CommandMatterlink : CommandBase() { + private val aliases: List + + init { + aliases = Lists.newArrayList(MODID, "bridge", "BRIDGE") + } + + override fun getName(): String { + return "bridge" + } + + override fun getUsage(sender: ICommandSender): String { + return "bridge " + } + + override fun getAliases(): List { + return aliases + } + + override fun execute(server: MinecraftServer, sender: ICommandSender, args: Array) /*throws CommandException*/ { + if (args.isEmpty()) { + //throw new WrongUsageException("") + return + } + //TODO: check if sender is OP or test if normal users cannot send this + + + val cmd = args[0].toLowerCase() + when (cmd) { + "connect" -> { + instance.connect() + } + "disconnect" -> { + instance.disconnect() + } + } + } + + +} diff --git a/1.12.2/build.gradle b/1.12.2/build.gradle index e69de29..1e495cd 100644 --- a/1.12.2/build.gradle +++ b/1.12.2/build.gradle @@ -0,0 +1,49 @@ + +buildscript { + repositories { + jcenter() + maven { url = "http://files.minecraftforge.net/maven" } + mavenCentral() + } + dependencies { + classpath "net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT" + } +} + +apply plugin: 'net.minecraftforge.gradle.forge' + +minecraft { + version = mc_version + "-" + forge_version + runDir = "../run" + + mappings = mcp_mappings + + replaceIn 'MatterLink.kt' + replace '@VERSION@', mod_version +} + +processResources { + // this will ensure that this task is redone when the versions change. + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // replace stuff in mcmod.info, nothing else + from(project(":core").sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace version and mcversion + expand 'version': project.version, 'mcversion': project.minecraft.version + } + + // copy everything else except the mcmod.info + from(project(":core").sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } + +} + +reobf { + shadowJar { mappingType = 'SEARGE' } +} + +tasks.reobfShadowJar.mustRunAfter shadowJar \ No newline at end of file diff --git a/1.12.2/gradle.properties b/1.12.2/gradle.properties index c4c2571..9be039d 100644 --- a/1.12.2/gradle.properties +++ b/1.12.2/gradle.properties @@ -1,4 +1,4 @@ -group = matterbridge mc_version = 1.12.2 mcp_mappings = snapshot_20171003 -forge_version = 14.23.1.2599 \ No newline at end of file +forge_version = 14.23.1.2599 +forgegradle_version = 2.3-SNAPSHOT \ No newline at end of file diff --git a/1.12.2/src/main/kotlin/matterlink/EventWrapper.kt b/1.12.2/src/main/kotlin/matterlink/EventWrapper.kt index 1a5ce30..c987464 100644 --- a/1.12.2/src/main/kotlin/matterlink/EventWrapper.kt +++ b/1.12.2/src/main/kotlin/matterlink/EventWrapper.kt @@ -13,6 +13,7 @@ import net.minecraftforge.event.CommandEvent import net.minecraftforge.event.ServerChatEvent import net.minecraftforge.event.entity.living.LivingDeathEvent import net.minecraftforge.event.entity.player.AdvancementEvent +import net.minecraftforge.fml.common.FMLCommonHandler import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.gameevent.PlayerEvent @@ -92,6 +93,6 @@ object EventWrapper { @SubscribeEvent @JvmStatic fun serverTickEvent(e: TickEvent.ServerTickEvent) { - ServerChatHandler.writeIncomingToChat() + ServerChatHandler.writeIncomingToChat(FMLCommonHandler.instance().minecraftServerInstance.tickCounter) } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index 6327722..c8a1efb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,3 @@ -buildscript { - repositories { - jcenter() - maven { url = "http://files.minecraftforge.net/maven" } - mavenCentral() - } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' - } -} plugins { id "org.jetbrains.kotlin.jvm" version '1.2.21' id "com.github.johnrengelman.shadow" version "1.2.4" @@ -25,7 +15,6 @@ subprojects { } if(name != "core") { - apply plugin: 'net.minecraftforge.gradle.forge' apply plugin: 'com.github.johnrengelman.shadow' version = mc_version + "-" + mod_version @@ -37,35 +26,6 @@ subprojects { sourceCompatibility = targetCompatibility = '1.8' } - minecraft { - version = mc_version + "-" + forge_version - runDir = "../run" - - mappings = mcp_mappings - - replaceIn 'MatterLink.kt' - replace '@VERSION@', mod_version - } - - processResources { - // this will ensure that this task is redone when the versions change. - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version - - // replace stuff in mcmod.info, nothing else - from(project(":core").sourceSets.main.resources.srcDirs) { - include 'mcmod.info' - - // replace version and mcversion - expand 'version':project.version, 'mcversion':project.minecraft.version - } - - // copy everything else except the mcmod.info - from(project(":core").sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' - } - } - repositories { jcenter() maven { @@ -96,12 +56,5 @@ subprojects { exclude 'dummyThing' } - - - reobf { - shadowJar { mappingType = 'SEARGE' } - } - - tasks.reobfShadowJar.mustRunAfter shadowJar } } \ No newline at end of file diff --git a/core/src/main/kotlin/matterlink/IMatterLink.kt b/core/src/main/kotlin/matterlink/IMatterLink.kt index f6494e9..36e107f 100644 --- a/core/src/main/kotlin/matterlink/IMatterLink.kt +++ b/core/src/main/kotlin/matterlink/IMatterLink.kt @@ -7,6 +7,8 @@ lateinit var instance: IMatterLink lateinit var logger: Logger abstract class IMatterLink { + var interrupted: Boolean = false + abstract fun wrappedSendToPlayers(msg: String) abstract fun wrappedPlayerList(): Array @@ -22,4 +24,16 @@ abstract class IMatterLink { fun disconnect () { MessageHandler.stop() } + + + fun reconnect(tick: Int) { + if(tick % 20 == 0 && interrupted) { + logger.info("Trying to reconnect") + if (MessageHandler.start(clear = false)) { + logger.info("Reconnected to matterbridge relay") + } else { + logger.error("Reconnection to matterbridge relay failed.") + } + } + } } \ No newline at end of file diff --git a/core/src/main/kotlin/matterlink/bridge/HttpStreamConnection.kt b/core/src/main/kotlin/matterlink/bridge/HttpStreamConnection.kt index 68e4ef6..5f73f09 100644 --- a/core/src/main/kotlin/matterlink/bridge/HttpStreamConnection.kt +++ b/core/src/main/kotlin/matterlink/bridge/HttpStreamConnection.kt @@ -1,5 +1,6 @@ package matterlink.bridge; +import matterlink.instance import matterlink.logger import org.apache.http.client.methods.HttpGet import org.apache.http.impl.client.HttpClients @@ -19,7 +20,8 @@ class HttpStreamConnection(getClosure: () -> HttpGet, clearClosure: () -> HttpGe override fun run() { - if(clear) { + instance.interrupted = false + if (clear) { val r = client.execute(clearGet) r.entity.content.bufferedReader().forEachLine { logger.debug("skipping $it") @@ -49,7 +51,11 @@ class HttpStreamConnection(getClosure: () -> HttpGet, clearClosure: () -> HttpGe } } } catch (e: SocketException) { -// MatterLink.logger.error("Bridge Connection interrupted...") + if (!cancelled) { + logger.error("Bridge Connection interrupted...") + instance.interrupted = true + //TODO: mark connection as interrupted and try to reconnect + } } logger.debug("closing stream") content.close() diff --git a/core/src/main/kotlin/matterlink/bridge/ServerChatHandler.kt b/core/src/main/kotlin/matterlink/bridge/ServerChatHandler.kt index 536b49a..f0187f2 100644 --- a/core/src/main/kotlin/matterlink/bridge/ServerChatHandler.kt +++ b/core/src/main/kotlin/matterlink/bridge/ServerChatHandler.kt @@ -10,7 +10,8 @@ object ServerChatHandler { /** * This method must be called every server tick with no arguments. */ - fun writeIncomingToChat() { + fun writeIncomingToChat(tick: Int) { + instance.reconnect(tick) if (MessageHandler.rcvQueue.isNotEmpty()) logger.debug("incoming: " + MessageHandler.rcvQueue.toString()) val nextMessage = MessageHandler.rcvQueue.poll() diff --git a/settings.gradle b/settings.gradle index 5cc28de..de5082c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name = 'MatterLink' -include 'core', '1.12.2' \ No newline at end of file +include 'core', '1.12.2', '1.11.2' \ No newline at end of file