update 1.12.2 with locations

This commit is contained in:
nikky 2018-08-14 21:53:01 +02:00
parent 6cdd7ade7c
commit e30e8132ca
43 changed files with 1785 additions and 165 deletions

2
.gitignore vendored
View File

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

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "api"]
path = api
url = https://github.com/NikkyAI/MatterLinkApi.git
[submodule "Jankson"] [submodule "Jankson"]
path = Jankson path = Jankson
url = https://github.com/falkreon/Jankson.git url = https://github.com/falkreon/Jankson.git

View File

@ -34,14 +34,17 @@ dependencies {
shadowJar { shadowJar {
classifier '' classifier ''
relocate 'blue.endless', 'matterlink.repack.blue.endless'
dependencies { dependencies {
include project(':core') include project(":core")
include project(':api') include project(":api")
include project(':Jankson') include project(":Jankson")
include dependency(group: 'com.elytradev.concrete', name: 'concrete-common', version: concrete_version)
include dependency(group: 'com.elytradev.concrete', name: 'concrete-rulesengine', version: concrete_version)
} }
relocate 'blue.endless', 'matterlink.repack.blue.endless'
relocate 'com.elytradev.concrete', 'matterlink.repack.com.elytradev.concrete'
exclude 'dummyThing' exclude 'dummyThing'
} }

View File

@ -39,14 +39,17 @@ dependencies {
shadowJar { shadowJar {
classifier = '' classifier = ''
relocate 'blue.endless', 'matterlink.repack.blue.endless'
dependencies { dependencies {
include project(':core') include project(":core")
include project(':api') include project(":api")
include project(':Jankson') include project(":Jankson")
include dependency(group: 'com.elytradev.concrete', name: 'concrete-common', version: concrete_version)
include dependency(group: 'com.elytradev.concrete', name: 'concrete-rulesengine', version: concrete_version)
} }
relocate 'blue.endless', 'matterlink.repack.blue.endless'
relocate 'com.elytradev.concrete', 'matterlink.repack.com.elytradev.concrete'
exclude 'dummyThing' exclude 'dummyThing'
} }

View File

@ -37,14 +37,17 @@ dependencies {
shadowJar { shadowJar {
classifier = '' classifier = ''
relocate 'blue.endless', 'matterlink.repack.blue.endless'
dependencies { dependencies {
include project(':core') include project(":core")
include project(':api') include project(":api")
include project(':Jankson') include project(":Jankson")
include dependency(group: 'com.elytradev.concrete', name: 'concrete-common', version: concrete_version)
include dependency(group: 'com.elytradev.concrete', name: 'concrete-rulesengine', version: concrete_version)
} }
relocate 'blue.endless', 'matterlink.repack.blue.endless'
relocate 'com.elytradev.concrete', 'matterlink.repack.com.elytradev.concrete'
exclude 'dummyThing' exclude 'dummyThing'
} }

View File

@ -1,6 +1,5 @@
package matterlink package matterlink
import matterlink.api.ApiMessage.Companion.USER_ACTION
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.handlers.* import matterlink.handlers.*
import net.minecraft.command.server.CommandBroadcast import net.minecraft.command.server.CommandBroadcast
@ -28,7 +27,11 @@ object EventHandler {
ProgressHandler.handleProgress( ProgressHandler.handleProgress(
name = e.entityPlayer.displayName.unformattedText, name = e.entityPlayer.displayName.unformattedText,
message = "has made the advancement", message = "has made the advancement",
display = e.advancement.displayText.unformattedText display = e.advancement.displayText.unformattedText,
x = e.entityPlayer.posX.toInt(),
y = e.entityPlayer.posY.toInt(),
z = e.entityPlayer.posZ.toInt(),
dimension = e.entityPlayer.dimension
) )
} }
@ -36,11 +39,15 @@ object EventHandler {
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun chatEvent(e: ServerChatEvent) { fun chatEvent(e: ServerChatEvent) {
if(e.isCanceled) return if (e.isCanceled) return
e.isCanceled = ChatProcessor.sendToBridge( e.isCanceled = ChatProcessor.sendToBridge(
user = e.player.displayName.unformattedText, user = e.player.displayName.unformattedText,
msg = e.message, msg = e.message,
event = "", x = e.player.posX.toInt(),
y = e.player.posY.toInt(),
z = e.player.posZ.toInt(),
dimension = e.player.dimension,
event = ChatEvent.PLAIN,
uuid = e.player.gameProfile.id uuid = e.player.gameProfile.id
) )
} }
@ -49,18 +56,31 @@ object EventHandler {
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun commandEvent(e: CommandEvent) { fun commandEvent(e: CommandEvent) {
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
} }
val args = e.parameters.joinToString(" ") val args = e.parameters.joinToString(" ")
val type = when { val type = with(e.command) {
e.command is CommandEmote -> USER_ACTION when {
e.command.name.equals("me", true) -> USER_ACTION this is CommandEmote || name.equals("me", true) -> ChatEvent.ACTION
e.command is CommandBroadcast -> "" this is CommandBroadcast || name.equals("say", true) -> ChatEvent.BROADCAST
else -> return else -> return
}
} }
ChatProcessor.sendToBridge(user = sender, msg = args, event = type) ChatProcessor.sendToBridge(
user = sender,
msg = args,
event = type,
x = e.sender.position.x,
y = e.sender.position.y,
z = e.sender.position.z,
dimension = when {
e.sender is DedicatedServer -> null
else -> e.sender.commandSenderEntity?.dimension ?: e.sender.entityWorld.provider.dimension
}
)
} }
//FORGE-DEPENDENT //FORGE-DEPENDENT
@ -71,7 +91,11 @@ object EventHandler {
DeathHandler.handleDeath( DeathHandler.handleDeath(
player = e.entityLiving.displayName.unformattedText, player = e.entityLiving.displayName.unformattedText,
deathMessage = e.entityLiving.combatTracker.deathMessage.unformattedText, deathMessage = e.entityLiving.combatTracker.deathMessage.unformattedText,
damageType = e.source.damageType damageType = e.source.damageType,
x = e.entityLiving.posX.toInt(),
y = e.entityLiving.posY.toInt(),
z = e.entityLiving.posZ.toInt(),
dimension = e.entityLiving.dimension
) )
} }
} }
@ -80,14 +104,26 @@ object EventHandler {
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) { fun joinEvent(e: PlayerEvent.PlayerLoggedInEvent) {
JoinLeaveHandler.handleJoin(e.player.displayName.unformattedText) JoinLeaveHandler.handleJoin(
player = e.player.displayName.unformattedText,
x = e.player.posX.toInt(),
y = e.player.posY.toInt(),
z = e.player.posZ.toInt(),
dimension = e.player.dimension
)
} }
//FORGE-DEPENDENT //FORGE-DEPENDENT
@SubscribeEvent @SubscribeEvent
@JvmStatic @JvmStatic
fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) { fun leaveEvent(e: PlayerEvent.PlayerLoggedOutEvent) {
JoinLeaveHandler.handleLeave(e.player.displayName.unformattedText) JoinLeaveHandler.handleLeave(
player = e.player.displayName.unformattedText,
x = e.player.posX.toInt(),
y = e.player.posY.toInt(),
z = e.player.posZ.toInt(),
dimension = e.player.dimension
)
} }
//FORGE-DEPENDENT //FORGE-DEPENDENT

View File

@ -9,7 +9,9 @@ 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
@ -111,6 +113,14 @@ object MatterLink : IMatterLink() {
null null
} }
override fun collectPlayers(area: Area): Set<UUID> {
val players = FMLCommonHandler.instance().minecraftServerInstance.playerList.players.filter {
( area.allDimensions || area.dimensions.contains(it.dimension) )
&& area.testInBounds(it.posX.toInt(), it.posY.toInt(), it.posZ.toInt())
}
return players.map { it.uniqueID }.toSet()
}
override fun nameToUUID(username: String): UUID? = profileByName(username)?.id override fun nameToUUID(username: String): UUID? = profileByName(username)?.id
override fun uuidToName(uuid: UUID): String? = profileByUUID(uuid)?.name override fun uuidToName(uuid: UUID): String? = profileByUUID(uuid)?.name

@ -1 +1 @@
Subproject commit 93ab86ee821380584c22ac60d77737388976e531 Subproject commit 69564c34e706f5243d8ae212fb58bb982db01a81

1
api

@ -1 +0,0 @@
Subproject commit 75138cec00c66d479709f4b44d78ca3005993474

5
api/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
\.idea/
\.gradle/
out/
build/
run/

22
api/LICENSE.md Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1
api/README.md Normal file
View File

@ -0,0 +1 @@
MatterLinkApi

49
api/build.gradle Normal file
View File

@ -0,0 +1,49 @@
buildscript {
ext.kotlin_version = '1.2.41'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
group 'moe.nikky'
version '1.0-SNAPSHOT'
apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'idea'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
compileKotlin {
kotlinOptions {
languageVersion = "1.2"
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
// https://mvnrepository.com/artifact/com.google.code.gson/gson
compile group: 'com.google.code.gson', name: 'gson', version: '+'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '+'
testCompile group: 'junit', name: 'junit', version: '4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
idea {
module {
excludeDirs += [file("run")]
}
}

BIN
api/gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip

172
api/gradlew vendored Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
api/gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

2
api/settings.gradle Normal file
View File

@ -0,0 +1,2 @@
rootProject.name = 'MatterLinkApi'

View File

@ -0,0 +1,92 @@
package matterlink.api
import com.google.gson.GsonBuilder
import com.google.gson.annotations.SerializedName
/**
* Created by nikky on 07/05/18.
*
* @author Nikky
* @version 1.0
*/
class ApiMessage (
username: String? = null,
text: String? = null,
gateway: String? = null,
channel: String? = null,
userid: String? = null,
avatar: String? = null,
account: String? = null,
protocol: String? = null,
event: String? = null,
id: 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 {
return gson.toJson(this)
}
override fun toString(): String = encode()
companion object {
val USER_ACTION = "user_action"
val JOIN_LEAVE = "join_leave"
private val gson = GsonBuilder()
.create()
fun decode(json: String): ApiMessage {
return gson.fromJson(json, ApiMessage::class.java)
}
}
}

View File

@ -0,0 +1,16 @@
package matterlink.api
data class Config (
var url: String = "",
var token: String = "",
var announceConnect: Boolean = true,
var announceDisconnect: Boolean = true,
var reconnectWait: Long = 500,
var systemUser: String = "Server"
)
{
fun sync(connection: StreamConnection) {
connection.token = token
connection.host = url
}
}

View File

@ -0,0 +1,201 @@
package matterlink.api
import org.apache.logging.log4j.Logger
import java.io.BufferedReader
import java.io.DataOutputStream
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.
*
* @author Nikky
* @version 1.0
*/
open class MessageHandler {
private var enabled = false
private var connectErrors = 0
private var reconnectCooldown = 0
private var sendErrors = 0
var config: Config = Config()
set(value) {
field = value.apply {
sync(streamConnection)
}
}
//TODO: make callbacks: onConnect onDisconnect onError etc
var queue: ConcurrentLinkedQueue<ApiMessage> = ConcurrentLinkedQueue()
private set
private var streamConnection: StreamConnection = StreamConnection(queue)
var logger: Logger
get() = streamConnection.logger
set(l) {
streamConnection.logger = l
}
private var nextCheck: Long = 0
init {
streamConnection.addOnSuccess { success ->
if (success) {
logger.info("connected successfully")
connectErrors = 0
reconnectCooldown = 0
} else {
reconnectCooldown = connectErrors
connectErrors++
logger.error(String.format("connectErrors: %d", connectErrors))
}
}
}
fun stop(message: String? = null) {
if (message != null && config.announceDisconnect) {
sendStatusUpdate(message)
}
enabled = false
streamConnection.close()
}
fun start(message: String?, clear: Boolean) {
config.sync(streamConnection)
if (clear) {
clear()
}
enabled = true
streamConnection.open()
if (message != null && config.announceConnect) {
sendStatusUpdate(message)
}
}
private fun clear() {
try {
val url = URL(config.url + "/api/messages")
val conn = url.openConnection() as HttpURLConnection
if (!config.token.isEmpty()) {
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) {
e.printStackTrace()
} catch (e: ProtocolException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
open fun sendStatusUpdate(message: String) {
transmit(ApiMessage(text = message))
}
open fun transmit(msg: ApiMessage) {
if (streamConnection.isConnected || streamConnection.isConnecting) {
if (msg.username.isEmpty())
msg.username = config.systemUser
if (msg.gateway.isEmpty()) {
logger.fatal("missing gateway on message: $msg")
return
}
logger.debug("Transmitting: $msg")
transmitMessage(msg)
}
}
private fun transmitMessage(message: ApiMessage) {
try {
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()
logger.trace(postData)
conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", "application/json")
conn.setRequestProperty("charset", "utf-8")
conn.setRequestProperty("Content-Length", "" + postData.toByteArray().size)
conn.doOutput = true
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 {
sendErrors = 0
}
} catch (e: IOException) {
e.printStackTrace()
logger.error("sending message caused $e")
sendErrors++
if (sendErrors > 5) {
logger.error("Caught too many errors, closing bridge")
stop()
}
}
}
/**
* clll this method every tick / cycle to make sure it is reconnecting
*/
fun checkConnection() {
if (enabled && !streamConnection.isConnected && !streamConnection.isConnecting) {
logger.trace("check connection")
logger.trace("next: $nextCheck")
logger.trace("now: " + System.currentTimeMillis())
if (nextCheck > System.currentTimeMillis()) return
nextCheck = System.currentTimeMillis() + config.reconnectWait
if (connectErrors >= 10) {
logger.error("Caught too many errors, closing bridge")
stop("Interrupting connection to matterbridge API due to accumulated connection errors")
return
}
if (reconnectCooldown <= 0) {
logger.info("Trying to reconnect")
start("Reconnecting to matterbridge API after connection error", false)
} else {
reconnectCooldown--
}
}
}
}

View File

@ -0,0 +1,150 @@
package matterlink.api
import org.apache.logging.log4j.LogManager
import java.io.IOException
import java.io.InputStream
import java.net.ConnectException
import java.net.HttpURLConnection
import java.net.MalformedURLException
import java.net.URL
import java.util.Arrays
import java.util.LinkedList
import java.util.concurrent.ConcurrentLinkedQueue
/**
* Created by nikky on 07/05/18.
*
* @author Nikky
* @version 1.0
*/
class StreamConnection(private val rcvQueue: ConcurrentLinkedQueue<ApiMessage>) : Runnable {
private var thread: Thread = createThread()
private var urlConnection: HttpURLConnection? = null
private val onSuccessCallbacks = LinkedList<(Boolean) -> Unit>()
var logger = LogManager.getLogger("matterlink.api")
var host = ""
var token = ""
var isConnected = false
private set
var isConnecting = false
private set
var isCancelled = false
private set
private fun createThread(): Thread {
val thread = Thread(this)
thread.name = "RcvThread"
return thread
}
fun addOnSuccess(callback: (Boolean) -> Unit) {
onSuccessCallbacks.add(callback)
}
fun removeOnSuccess(callback: (Boolean) -> Unit) {
onSuccessCallbacks.remove(callback)
}
private fun onSuccess(success: Boolean) {
isConnecting = false
isConnected = success
for (callback in onSuccessCallbacks) {
callback(success)
}
}
override fun run() {
try {
val serviceURL = "$host/api/stream"
val myURL: URL
myURL = URL(serviceURL)
urlConnection = myURL.openConnection() as HttpURLConnection
urlConnection!!.requestMethod = "GET"
if (!token.isEmpty()) {
val bearerAuth = "Bearer $token"
urlConnection!!.setRequestProperty("Authorization", bearerAuth)
}
try {
urlConnection!!.inputStream.use { input ->
logger.info("connection opened")
onSuccess(true)
// BufferedInputStream bufferedInput = new BufferedInputStream(input, 8 * 1024);
val buffer = StringBuilder()
while (!isCancelled) {
val buf = ByteArray(1024)
Thread.sleep(10)
while (input.available() <= 0) {
if (isCancelled) break
Thread.sleep(10)
}
val chars = input.read(buf)
logger.trace( String.format("read %d chars", chars))
if (chars > 0) {
val added = String(Arrays.copyOfRange(buf, 0, chars))
logger.debug("DEBUG", "json: $added")
buffer.append(added)
while (buffer.toString().contains("\n")) {
val index = buffer.indexOf("\n")
val line = buffer.substring(0, index)
buffer.delete(0, index + 1)
rcvQueue.add(ApiMessage.decode(line))
}
} else if (chars < 0) {
break
}
}
}
} finally {
onClose()
}
} catch (e: MalformedURLException) {
e.printStackTrace()
} catch (e: ConnectException) {
e.printStackTrace()
onSuccess(false)
} catch (e: IOException) {
e.printStackTrace()
onSuccess(false)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
private fun onClose() {
logger.info("Bridge connection closed!")
isConnected = false
isConnecting = false
}
fun open() {
if (!thread.isAlive) {
thread = createThread()
isConnecting = true
isCancelled = false
thread.start()
logger.info("Starting Connection")
}
if (thread.isAlive) {
logger.info("Bridge is connecting")
}
}
fun close() {
try {
isCancelled = true
if (urlConnection != null) {
urlConnection!!.disconnect()
}
thread.join()
logger.info("Thread stopped")
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
}

View File

@ -0,0 +1,80 @@
package matterlink.api
import com.google.gson.Gson
import com.google.gson.stream.JsonReader
import java.io.*
import java.util.Scanner
/**
* Created by nikky on 07/05/18.
*
* @author Nikky
* @version 1.0
*/
object Main {
@Throws(IOException::class)
@JvmStatic
fun main(vararg args: String) {
val handler = MessageHandler()
val queue = handler.queue
val config: Config
val gson = Gson()
try {
val reader = JsonReader(FileReader("config.json"))
config = gson.fromJson(reader, Config::class.java)
handler.config = config
} catch (e: FileNotFoundException) {
e.printStackTrace()
FileWriter("config.json").use { writer -> gson.toJson(handler.config, writer) }
}
// handler.logger = { level, msg -> System.out.printf("[%s] %s%n", level, msg) }
handler.start("Connecting..", true)
Thread {
while (true) {
val next = queue.poll()
if (next != null) {
println(next)
}
try {
Thread.sleep(200)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
}.start()
Thread {
while (true) {
handler.checkConnection()
try {
Thread.sleep(100)
} catch (e: InterruptedException) {
e.printStackTrace()
}
}
}.start()
val sc = Scanner(System.`in`)
while (true) {
val input = sc.nextLine()
when (input) {
"start" -> {
handler.start("start", false)
}
"stop" -> {
handler.stop("stop")
}
else -> {
handler.transmit(ApiMessage(text = input))
}
}
}
}
}

View File

@ -36,8 +36,9 @@ subprojects {
repositories { repositories {
jcenter() jcenter()
maven { maven {
name = "unascribed" name = "elytradev"
url = 'http://unascribed.com/maven/releases' url = 'http://unascribed.com/maven/releases'
url = 'https://repo.elytradev.com'
} }
maven { maven {
name = "shadowfacts" name = "shadowfacts"

View File

@ -19,15 +19,15 @@ dependencies {
compile project(":Jankson") compile project(":Jankson")
// compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '+'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '+' compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '+'
// compile group: 'commons-logging', name: 'commons-logging', version: '1.1.3'
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: 'org.apache.httpcomponents', name: 'httpclient', version: '+' compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '+'
compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: project.kotlin_version // compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: project.kotlin_version
compile group: 'com.elytradev.concrete', name:'concrete-common', version: concrete_version
compile group: 'com.elytradev.concrete', name:'concrete-rulesengine', version: concrete_version
} }
compileKotlin { compileKotlin {
@ -37,10 +37,15 @@ compileKotlin {
} }
shadowJar { shadowJar {
classifier '' classifier = ''
dependencies { dependencies {
include project(":api") include project(":api")
include project(":Jankson") include project(":Jankson")
include dependency(group: 'com.elytradev.concrete', name: 'concrete-common', version: concrete_version)
include dependency(group: 'com.elytradev.concrete', name: 'concrete-rulesengine', version: concrete_version)
} }
relocate 'blue.endless', 'matterlink.repack.blue.endless'
relocate 'com.elytradev.concrete', 'matterlink.repack.com.elytradev.concrete'
} }

View File

@ -0,0 +1,184 @@
package matterlink
import blue.endless.jankson.JsonObject
import blue.endless.jankson.impl.SyntaxError
import kotlin.math.sqrt
fun JsonObject.parseDimensions(): List<Int> = getOrPutList("dimensions", emptyList(), "list of dimension ids")
fun JsonObject.parseAllDimensions(): Boolean = getOrDefault("allDimensions", false, "ignores dimension list")
sealed class Area {
abstract val type: String
abstract val dimensions: List<Int>
abstract val allDimensions: Boolean
abstract fun testInBounds(x: Int, y: Int, z: Int): Boolean
fun testForDim(dimension: Int?): Boolean {
if (allDimensions) return true
if(dimension == null) return false
return dimensions.contains(dimension)
}
companion object {
fun parse(jsonObj: JsonObject): Area {
val type: String = jsonObj.getOrDefault("type", "INFINITE", "Area type identifier")
return when (type.toUpperCase()) {
"INFINITE" -> Infinite.parse(jsonObj)
"RADIUS" -> Radius.parse(jsonObj)
"SPHERE" -> Sphere.parse(jsonObj)
"BOX" -> Box.parse(jsonObj)
"SQUARE" -> Square.parse(jsonObj)
else -> throw SyntaxError("no Area type '$type' found")
}
}
}
data class Infinite(
override val dimensions: List<Int> = listOf(),
override val allDimensions: Boolean = false
) : Area() {
override val type = "INFINITE"
override fun testInBounds(x: Int, y: Int, z: Int): Boolean {
return true
}
companion object {
fun parse(jsonObj: JsonObject): Area {
return Infinite(
dimensions = jsonObj.parseDimensions(),
allDimensions = jsonObj.parseAllDimensions()
)
}
}
}
data class Radius(
override val dimensions: List<Int> = listOf(),
override val allDimensions: Boolean = false,
val x: Int,
val z: Int,
val radius: Int?
) : Area() {
override val type = "RADIUS"
override fun testInBounds(x: Int, y: Int, z: Int): Boolean {
if (radius == null) return true
return sqrt(((this.x - x) * (this.x - x)) + ((this.z - z) * (this.z - z)).toFloat()) < this.radius
}
companion object {
fun parse(jsonObj: JsonObject): Area {
return Radius(
dimensions = jsonObj.parseDimensions(),
allDimensions = jsonObj.parseAllDimensions(),
x = jsonObj.getOrDefault("x", 0),
z = jsonObj.getOrDefault("z", 0),
radius = jsonObj.getReified("radius")
)
}
}
}
class Sphere (
override val dimensions: List<Int> = listOf(),
override val allDimensions: Boolean = false,
val x: Int,
val y: Int,
val z: Int,
val radius: Int? = null
): Area() {
override val type = "SPHERE"
override fun testInBounds(x: Int, y: Int, z: Int): Boolean {
if (radius == null) return true
return sqrt(((this.x - x) * (this.x - x)) +((this.y - y) * (this.y - y)) + ((this.z - z) * (this.z - z)).toFloat()) < this.radius
}
companion object {
fun parse(jsonObj: JsonObject): Area {
return Sphere(
dimensions = jsonObj.parseDimensions(),
allDimensions = jsonObj.parseAllDimensions(),
x = jsonObj.getOrDefault("x", 0),
y = jsonObj.getOrDefault("y", 0),
z = jsonObj.getOrDefault("z", 0),
radius = jsonObj.getReified("radius")
)
}
}
}
class Box (
override val dimensions: List<Int> = listOf(),
override val allDimensions: Boolean = false,
val x1: Int,
val x2: Int,
val y1: Int,
val y2: Int,
val z1: Int,
val z2: Int
): Area() {
override val type = "BOX"
override fun testInBounds(x: Int, y: Int, z: Int): Boolean {
return x in x1..x2 && y in y1..y2 && z in z1..z2
}
companion object {
fun parse(jsonObj: JsonObject): Area {
return Box(
dimensions = jsonObj.parseDimensions(),
allDimensions = jsonObj.parseAllDimensions(),
x1 = jsonObj.getOrDefault("x1", 0),
x2 = jsonObj.getOrDefault("x2", 0),
y1 = jsonObj.getOrDefault("y1", 0),
y2 = jsonObj.getOrDefault("y2", 0),
z1 = jsonObj.getOrDefault("z1", 0),
z2 = jsonObj.getOrDefault("z2", 0)
)
}
}
}
class Square (
override val dimensions: List<Int> = listOf(),
override val allDimensions: Boolean = false,
val x1: Int,
val x2: Int,
val z1: Int,
val z2: Int
): Area() {
override val type = "SQUARE"
override fun testInBounds(x: Int, y: Int, z: Int): Boolean {
return x in x1..x2 && z in z1..z2
}
companion object {
fun parse(jsonObj: JsonObject): Area {
return Square(
dimensions = jsonObj.parseDimensions(),
allDimensions = jsonObj.parseAllDimensions(),
x1 = jsonObj.getOrDefault("x1", 0),
x2 = jsonObj.getOrDefault("x2", 0),
z1 = jsonObj.getOrDefault("z1", 0),
z2 = jsonObj.getOrDefault("z2", 0)
)
}
}
}
//
//
// class FakePlayer (
// val x: Int,
// val y: Int,
// val z: Int,
// val name: String
// ): Area()
}

View File

@ -4,6 +4,7 @@ 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 org.apache.logging.log4j.Logger import org.apache.logging.log4j.Logger
@ -98,4 +99,6 @@ abstract class IMatterLink {
BridgeCommandRegistry.reloadCommands() BridgeCommandRegistry.reloadCommands()
} }
abstract fun collectPlayers(area: Area): Set<UUID>
} }

View File

@ -67,8 +67,10 @@ fun randomString(length: Int = 6): String =
java.util.UUID.randomUUID().toString().replace("-", "").take(length) java.util.UUID.randomUUID().toString().replace("-", "").take(length)
fun <T : Any> JsonObject.getOrDefault(key: String, default: T, comment: String? = null): T { fun <T : Any> JsonObject.getOrDefault(key: String, default: T, comment: String? = null): T {
// logger.info("type: ${default.javaClass.name} key: $key json: >>>${this.getObject(key)?.toJson()}<<< default: $default") logger.trace("type: ${default.javaClass.name} key: $key json: >>>${this.getObject(key)?.toJson()}<<< default: $default")
return putDefault(key, default, comment)!! return putDefault(key, default, comment)!!.also {
setComment(key, comment)
}
} }
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)
@ -84,7 +86,15 @@ inline fun <reified T : Any> Marshaller.registerSerializer(noinline 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): 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) }
inline fun <reified T : Any> JsonObject.getReifiedOrDelete(key: String, comment: String? = null): T? = this.get(T::class.java, key)
?.also { setComment(key, comment) }
?: run {
this.remove(key)
null
}
inline fun <reified T : Any> JsonObject.getList(key: String): List<T>? { inline fun <reified T : Any> JsonObject.getList(key: String): List<T>? {
return this[key]?.let { array -> return this[key]?.let { array ->
@ -98,3 +108,33 @@ inline fun <reified T : Any> JsonObject.getList(key: String): List<T>? {
} }
} }
} }
inline fun <reified T : Any> JsonObject.getOrPutList(key: String, default: List<T>, comment: String?): List<T> {
return this[key]?.let { array ->
when (array) {
is JsonArray -> {
array.indices.map { i ->
array.get(T::class.java, i) ?: throw NullPointerException("cannot parse ${array.get(i)}")
}
}
else -> null
}
}.also {
setComment(key, comment)
} ?: this.putDefault(key, default, comment) ?: default
}
inline fun <reified T : Any> JsonObject.getOrPutMap(key: String, default: Map<String, T>, comment: String?): Map<String, T> {
return this[key]?.let { map ->
when (map) {
is JsonObject -> {
map.mapValues { (key, element) ->
map.get(T::class.java, key) ?: throw NullPointerException("cannot parse $element")
}
}
else -> null
}
}.also {
setComment(key, comment)
} ?: this.putDefault(key, default, comment) ?: default
}

View File

@ -4,12 +4,24 @@ import matterlink.*
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.LocationHandler
object MessageHandlerInst : MessageHandler() { object MessageHandlerInst : MessageHandler() {
override fun transmit(msg: ApiMessage) { override fun transmit(msg: ApiMessage) {
transmit(msg, cause = "") transmit(msg, cause = "")
} }
override fun sendStatusUpdate(message: String) {
LocationHandler.sendToLocations(
msg = message,
x = 0, y = 0, z = 0, dimension = null,
systemuser = true,
event = ChatEvent.STATUS,
cause = "status update message"
)
}
fun transmit(msg: ApiMessage, cause: String, maxLines: Int = cfg.outgoing.inlineLimit) { 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
@ -18,8 +30,10 @@ object MessageHandlerInst : MessageHandler() {
msg.avatar = cfg.outgoing.avatar.systemUserAvatar msg.avatar = cfg.outgoing.avatar.systemUserAvatar
} }
} }
if (msg.gateway.isEmpty()) if (msg.gateway.isEmpty()) {
msg.gateway = cfg.connect.gateway logger.error("dropped message '$msg' due to missing gateway")
return
}
if (msg.text.lines().count() >= maxLines) { if (msg.text.lines().count() >= maxLines) {
try { try {
@ -38,6 +52,7 @@ object MessageHandlerInst : MessageHandler() {
msg.text = msg.text.substringBefore('\n') msg.text = msg.text.substringBefore('\n')
.take(25) + "... " + response.link .take(25) + "... " + response.link
} catch(e: Exception) { } catch(e: Exception) {
logger.error(cause)
logger.error(e.stackTraceString) logger.error(e.stackTraceString)
} }
} }

View File

@ -29,7 +29,7 @@ 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, 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}")

View File

@ -23,6 +23,7 @@ abstract class IBridgeCommand {
val name: String, val name: String,
val userId: String, val userId: String,
val platform: String, val platform: String,
val gateway: String,
override val uuid: UUID? override val uuid: UUID?
) : CommandEnvironment() { ) : CommandEnvironment() {
override val username: String? override val username: String?
@ -39,6 +40,7 @@ abstract class IBridgeCommand {
is BridgeEnv -> { is BridgeEnv -> {
MessageHandlerInst.transmit( MessageHandlerInst.transmit(
ApiMessage( ApiMessage(
gateway = this.gateway,
text = text.stripColorOut text = text.stripColorOut
), ),
cause = cause cause = cause

View File

@ -4,13 +4,12 @@ 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.bridge.MessageHandlerInst import matterlink.bridge.MessageHandlerInst
import matterlink.getOrDefault
import matterlink.logger
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
@ -26,12 +25,82 @@ data class BaseConfig(val rootDir: File) {
data class MatterLinkConfig( data class MatterLinkConfig(
val connect: ConnectOptions = ConnectOptions(), val connect: ConnectOptions = ConnectOptions(),
val outgoingDefaults: DefaultSettingsOutgoing = DefaultSettingsOutgoing(),
val incomingDefaults: DefaultSettingsIncoming = DefaultSettingsIncoming(),
val locations: List<Location> = listOf(
Location(
label = "default",
gateway = "minecraft",
area = Area.Infinite(dimensions = listOf(-1, 0, 1), allDimensions = true),
outgoing = SettingsOutgoing(
plain = true,
action = true,
join = true,
leave = true,
advancement = true,
death = true,
broadcast = true,
status = true
),
incoming = SettingsIncoming(
plain = true,
action = true,
join_leave = true,
commands = true
)
)
),
val incoming: IncomingOptions = IncomingOptions(), val incoming: IncomingOptions = IncomingOptions(),
val outgoing: OutgoingOptions = OutgoingOptions(), val outgoing: OutgoingOptions = OutgoingOptions(),
val command: CommandOptions = CommandOptions(), val command: CommandOptions = CommandOptions(),
val update: UpdateOptions = UpdateOptions() val update: UpdateOptions = UpdateOptions()
) )
data class DefaultSettingsOutgoing(
val plain: Boolean = true,
val action: Boolean = true,
val join: Boolean = false,
val leave: Boolean = false,
val advancement: Boolean = false,
val death: Boolean = false,
val broadcast: Boolean = false,
val status: Boolean = false
)
data class SettingsOutgoing(
val plain: Boolean? = null,
val action: Boolean? = null,
val join: Boolean? = null,
val leave: Boolean? = null,
val advancement: Boolean? = null,
val death: Boolean? = null,
val broadcast: Boolean? = null,
val status: Boolean? = null,
val skip: List<String> = listOf()
)
data class DefaultSettingsIncoming(
val plain: Boolean = true,
val action: Boolean = true,
val join_leave: Boolean = true,
val commands: Boolean = true
)
data class SettingsIncoming(
val plain: Boolean? = null,
val action: Boolean? = null,
val join_leave: Boolean? = null,
val commands: Boolean? = null,
val skip: List<String> = listOf()
)
data class Location(
val label: String = "unlabeled",
val gateway: String = "",
val area: Area = Area.Infinite(),
val outgoing: SettingsOutgoing = SettingsOutgoing(),
val incoming: SettingsIncoming = SettingsIncoming()
)
data class CommandOptions( data class CommandOptions(
val prefix: Char = '!', val prefix: Char = '!',
@ -45,7 +114,6 @@ data class BaseConfig(val rootDir: File) {
data class ConnectOptions( data class ConnectOptions(
val url: String = "http://localhost:4242", val url: String = "http://localhost:4242",
val authToken: String = "", val authToken: String = "",
val gateway: String = "minecraft",
val autoConnect: Boolean = true, val autoConnect: Boolean = true,
val reconnectWait: Long = 500 val reconnectWait: Long = 500
) )
@ -104,7 +172,9 @@ data class BaseConfig(val rootDir: File) {
"thrown" to arrayOf("彡°"), "thrown" to arrayOf("彡°"),
"thorns" to arrayOf("\uD83C\uDF39"), //🌹 "thorns" to arrayOf("\uD83C\uDF39"), //🌹
"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"), //🔌 ⚡
"immersiverailroading:hitByTrain" to arrayOf("\uD83D\uDE82", "\uD83D\uDE83", "\uD83D\uDE84", "\uD83D\uDE85", "\uD83D\uDE87", "\uD83D\uDE88", "\uD83D\uDE8A") //🚂 🚃 🚄 🚅 🚇 🚈 🚊
) )
) )
@ -117,8 +187,8 @@ data class BaseConfig(val rootDir: File) {
data class JoinPartOptions( data class JoinPartOptions(
val enable: Boolean = true, val enable: Boolean = true,
val joinServer: String = "{username:antiping} has connected to the platform", val joinServer: String = "{username:antiping} has connected to the server",
val partServer: String = "{username:antiping} has disconnected from the platform" val partServer: String = "{username:antiping} has disconnected from the server"
) )
data class UpdateOptions( data class UpdateOptions(
@ -129,41 +199,191 @@ data class BaseConfig(val rootDir: File) {
val jankson = Jankson val jankson = Jankson
.builder() .builder()
.registerTypeAdapter { .registerTypeAdapter {
MatterLinkConfig( with(MatterLinkConfig()) {
command = it.getOrDefault( MatterLinkConfig(
"command", command = it.getOrDefault(
CommandOptions(), "command",
"User commands" command,
), "User commands"
connect = it.getOrDefault( ),
"connect", outgoingDefaults = it.getOrDefault(
ConnectOptions(), "outgoingDefaults",
"Connection Settings" outgoingDefaults,
), "default settings for outgoing"
incoming = it.getOrDefault( ),
"incoming", incomingDefaults = it.getOrDefault(
IncomingOptions(), "incomingDefaults",
""" incomingDefaults,
Gateway -> Server "default settings for incoming"
Options all about receiving messages from the API ),
Formatting options: locations = it.getOrPutList(
Available variables: {username}, {text}, {gateway}, {channel}, {protocol}, {username:antiping} "locations",
""".trimIndent() locations,
), "list of fixed chat locations"
outgoing = it.getOrDefault( ),
"outgoing", connect = it.getOrDefault(
OutgoingOptions(), "connect",
""" connect,
Server -> Gateway "Connection Settings"
Options all about sending messages to the API ),
""".trimIndent() incoming = it.getOrDefault(
), "incoming",
update = it.getOrDefault( incoming,
"update", """
UpdateOptions(), Gateway -> Server
"Update Settings" Options all about receiving messages from the API
) Formatting options:
) Available variables: {username}, {text}, {gateway}, {channel}, {protocol}, {username:antiping}
""".trimIndent()
),
outgoing = it.getOrDefault(
"outgoing",
outgoing,
"""
Server -> Gateway
Options all about sending messages to the API
""".trimIndent()
),
update = it.getOrDefault(
"update",
update,
"Update Settings"
)
)
}
}
.registerTypeAdapter {
with(DefaultSettingsOutgoing()) {
DefaultSettingsOutgoing(
plain = it.getOrDefault(
"plain",
plain,
"plain text messages"
),
action = it.getOrDefault(
"action",
action,
"action messages"
),
join = it.getOrDefault(
"join",
join,
"handle join event"
),
leave = it.getOrDefault(
"leave",
leave,
"handle leave events"
),
advancement = it.getOrDefault(
"advancement",
advancement,
"handle advancement events"
),
death = it.getOrDefault(
"death",
death,
"handle death events"
),
broadcast = it.getOrDefault(
"broadcast",
broadcast,
"handle broadcast command"
),
status = it.getOrDefault(
"status",
status,
"handles tatus updates"
)
)
}
}
.registerTypeAdapter {
with(SettingsOutgoing()) {
SettingsOutgoing(
plain = it.getReifiedOrDelete("plain", "transmit join events"),
action = it.getReifiedOrDelete("action", "transmit join events"),
join = it.getReifiedOrDelete("join", "transmit join events"),
leave = it.getReifiedOrDelete("leave", "transmit leave events"),
advancement = it.getReifiedOrDelete("advancement", "transmit advancements"),
death = it.getReifiedOrDelete("death", "transmit death messages"),
broadcast = it.getReifiedOrDelete("say", "transmit broadcasts"),
status = it.getReifiedOrDelete("status", "transmit status updates"),
skip = it.getOrPutList(
"skip",
skip,
"list of other locations to ignore after handling this"
)
)
}
}
.registerTypeAdapter {
with(DefaultSettingsIncoming()) {
DefaultSettingsIncoming(
plain = it.getOrDefault(
"plain",
plain,
"plain text messages"
),
action = it.getOrDefault(
"action",
action,
"action messages"
),
join_leave = it.getOrDefault(
"join_leave",
join_leave,
"handle join/leave event"
),
commands = it.getOrDefault(
"commands",
join_leave,
"receive commands"
)
)
}
}
.registerTypeAdapter {
with(SettingsIncoming()) {
SettingsIncoming(
plain = it.getReifiedOrDelete("plain", "transmit join events"),
action = it.getReifiedOrDelete("action", "transmit join events"),
join_leave = it.getReifiedOrDelete("join_leave", "transmit join_leave events"),
commands = it.getReifiedOrDelete("commands", "receive commands"),
skip = it.getOrPutList(
"skip",
skip,
"list of other locations to ignore after handling this"
)
)
}
}
.registerTypeAdapter {
with(Location()) {
Location(
label = it.getOrDefault("label",
label,
"location label for identification"
),
gateway = it.getOrDefault(
"gateway",
gateway,
"matterbridge gateway identifier"
),
area = Area.parse(it.getObject("area") ?: JsonObject()),
outgoing = it.getOrDefault(
"outgoing",
outgoing,
"Location outgoing settings"
),
incoming = it.getOrDefault(
"incoming",
incoming,
"incoming settings"
)
)
}
} }
.registerTypeAdapter { .registerTypeAdapter {
with(CommandOptions()) { with(CommandOptions()) {
@ -214,15 +434,15 @@ data class BaseConfig(val rootDir: File) {
authToken, authToken,
"Auth token used to connect to the bridge platform" "Auth token used to connect to the bridge platform"
), ),
gateway = it.getOrDefault(
"gateway",
gateway,
"MatterBridge gateway"
),
autoConnect = it.getOrDefault( autoConnect = it.getOrDefault(
"autoConnect", "autoConnect",
autoConnect, autoConnect,
"Connect the relay on startup" "Connect the relay on startup"
),
reconnectWait = it.getOrDefault(
"reconnectWait",
reconnectWait,
"base delay in milliseconds between attempting reconnects"
) )
) )
} }
@ -389,6 +609,25 @@ data class BaseConfig(val rootDir: File) {
) )
} }
} }
.registerSerializer { locationSettings: SettingsOutgoing, marshaller: Marshaller ->
val jsonObject = JsonObject()
locationSettings.advancement?.let {
jsonObject["advancements"] = marshaller.serialize(it)
}
locationSettings.death?.let {
jsonObject["death"] = marshaller.serialize(it)
}
locationSettings.join?.let {
jsonObject["joins"] = marshaller.serialize(it)
}
locationSettings.leave?.let {
jsonObject["leaves"] = marshaller.serialize(it)
}
locationSettings.broadcast?.let {
jsonObject["say"] = marshaller.serialize(it)
}
jsonObject
}
.build() .build()
} }
@ -417,15 +656,15 @@ data class BaseConfig(val rootDir: File) {
logger.error("error parsing config: ${e.completeMessage} ") logger.error("error parsing config: ${e.completeMessage} ")
logger.error(e.stackTraceString) logger.error(e.stackTraceString)
cfgDirectory.resolve("error.matterlink.hjson").writeText(jsonObject.toJson(false, true)) cfgDirectory.resolve("error.matterlink.hjson").writeText(jsonObject.toJson(false, true))
MatterLinkConfig() if (::cfg.isInitialized) cfg else MatterLinkConfig()
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
logger.error(e.stackTraceString) logger.error(e.stackTraceString)
cfgDirectory.resolve("error.matterlink.hjson").writeText(jsonObject.toJson(false, true)) cfgDirectory.resolve("error.matterlink.hjson").writeText(jsonObject.toJson(false, true))
MatterLinkConfig() if (::cfg.isInitialized) cfg else MatterLinkConfig()
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
logger.error("error loading config: ${e.stackTraceString}") logger.error("error loading config: ${e.stackTraceString}")
cfgDirectory.resolve("error.matterlink.hjson").writeText(jsonObject.toJson(false, true)) cfgDirectory.resolve("error.matterlink.hjson").writeText(jsonObject.toJson(false, true))
MatterLinkConfig() if (::cfg.isInitialized) cfg else MatterLinkConfig()
} }
// val defaultJsonObject = jankson.load("{}") // val defaultJsonObject = jankson.load("{}")
@ -434,7 +673,6 @@ data class BaseConfig(val rootDir: File) {
MessageHandlerInst.config.url = tmpCfg.connect.url MessageHandlerInst.config.url = tmpCfg.connect.url
MessageHandlerInst.config.token = tmpCfg.connect.authToken MessageHandlerInst.config.token = tmpCfg.connect.authToken
MessageHandlerInst.config.gateway = tmpCfg.connect.gateway
MessageHandlerInst.config.reconnectWait = tmpCfg.connect.reconnectWait MessageHandlerInst.config.reconnectWait = tmpCfg.connect.reconnectWait
MessageHandlerInst.config.systemUser = tmpCfg.outgoing.systemUser MessageHandlerInst.config.systemUser = tmpCfg.outgoing.systemUser

View File

@ -4,7 +4,6 @@ import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst import matterlink.bridge.MessageHandlerInst
import matterlink.bridge.command.BridgeCommandRegistry import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.config.cfg import matterlink.config.cfg
import matterlink.instance
import matterlink.logger import matterlink.logger
import matterlink.stripColorOut import matterlink.stripColorOut
import java.util.* import java.util.*
@ -13,23 +12,21 @@ object ChatProcessor {
/** /**
* @return cancel message flag * @return cancel message flag
*/ */
fun sendToBridge(user: String, msg: String, event: String, uuid: UUID? = null): Boolean { 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
logger.info("position: $x $y $z dimension: $dimension")
val message = msg.trim() val message = msg.trim()
if(uuid != null && BridgeCommandRegistry.handleCommand(message, user, uuid)) return true if (uuid != null && BridgeCommandRegistry.handleCommand(message, user, uuid)) return true
when { when {
message.isNotBlank() -> MessageHandlerInst.transmit( message.isNotBlank() -> LocationHandler.sendToLocations(
ApiMessage( user = user,
username = user.stripColorOut, msg = message,
text = message.stripColorOut, x = x, y = y, z = z, dimension = dimension,
event = event event = event,
).apply {
if(cfg.outgoing.avatar.enable) {
if(uuid != null)
avatar = cfg.outgoing.avatar.urlTemplate.replace("{uuid}", uuid.toString())
}
},
cause = "Message from $user" cause = "Message from $user"
) )
else -> logger.warn("WARN: dropped blank message by '$user'") else -> logger.warn("WARN: dropped blank message by '$user'")
} }
return false return false

View File

@ -13,7 +13,9 @@ object DeathHandler {
fun handleDeath( fun handleDeath(
player: String, player: String,
deathMessage: String, deathMessage: String,
damageType: String damageType: String,
x: Int, y: Int, z: Int,
dimension: Int
) { ) {
if (cfg.outgoing.death.enable) { if (cfg.outgoing.death.enable) {
var msg = deathMessage.stripColorOut.replace(player, player.stripColorOut.antiping) var msg = deathMessage.stripColorOut.replace(player, player.stripColorOut.antiping)
@ -23,7 +25,13 @@ object DeathHandler {
val damageEmoji = emojis[random.nextInt(emojis.size)] val damageEmoji = emojis[random.nextInt(emojis.size)]
msg += " $damageEmoji" msg += " $damageEmoji"
} }
MessageHandlerInst.transmit(ApiMessage(text = msg), cause = "Death Event of $player") LocationHandler.sendToLocations(
msg = msg,
x = x, y = y, z = z, dimension = dimension,
event = ChatEvent.DEATH,
cause = "Death Event of $player",
systemuser = true
)
} }
} }
} }

View File

@ -9,7 +9,9 @@ import matterlink.mapFormat
import matterlink.stripColorOut import matterlink.stripColorOut
object JoinLeaveHandler { object JoinLeaveHandler {
fun handleJoin(player: String) { fun handleJoin(player: String,
x: Int, y: Int, z: 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(
@ -17,17 +19,19 @@ object JoinLeaveHandler {
"{username:antiping}" to player.stripColorOut.antiping "{username:antiping}" to player.stripColorOut.antiping
) )
) )
MessageHandlerInst.transmit( LocationHandler.sendToLocations(
ApiMessage( msg = msg,
text = msg, x = x, y = y, z = z, dimension = dimension,
event = JOIN_LEAVE event = ChatEvent.JOIN,
), systemuser = true,
cause = "$player joined" cause = "$player joined"
) )
} }
} }
fun handleLeave(player: String) { fun handleLeave(player: String,
x: Int, y: Int, z: 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(
@ -35,11 +39,11 @@ object JoinLeaveHandler {
"{username:antiping}" to player.stripColorOut.antiping "{username:antiping}" to player.stripColorOut.antiping
) )
) )
MessageHandlerInst.transmit( LocationHandler.sendToLocations(
ApiMessage( msg = msg,
text = msg, x = x, y = y, z = z, dimension = dimension,
event = JOIN_LEAVE event = ChatEvent.JOIN,
), systemuser = true,
cause = "$player left" cause = "$player left"
) )
} }

View File

@ -0,0 +1,107 @@
package matterlink.handlers
import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst
import matterlink.config.cfg
import matterlink.logger
import matterlink.stripColorOut
import java.util.*
enum class ChatEvent {
PLAIN, ACTION, DEATH, JOIN, LEAVE, ADVANCEMENT, BROADCAST, STATUS
}
object LocationHandler {
fun sendToLocations(
user: String = cfg.outgoing.systemUser,
msg: String,
x: Int, y: Int, z: Int,
dimension: Int?,
event: ChatEvent,
systemuser: Boolean = false,
uuid: UUID? = null,
cause: String
): Boolean {
val defaults = cfg.outgoingDefaults
var handled = false
val skips = mutableSetOf<String>()
logger.info("locations: ${cfg.locations.map { it.label }}")
for (location in cfg.locations) {
val label = location.label
if(skips.contains(label)) {
logger.info("skipping $label (contained in in $skips)")
continue
}
if(!location.area.testForDim(dimension)) {
logger.info("location: $label dropped message '$msg' from $user due to mismatched dimension")
continue
}
if(!location.area.testInBounds(x, y, z)) {
logger.info("location: $label dropped message '$msg' from $user out of coordinate bounds")
continue
}
val matchesEvent = when (event) {
ChatEvent.PLAIN -> location.outgoing.plain ?: defaults.plain
ChatEvent.ACTION -> location.outgoing.action ?: defaults.action
ChatEvent.DEATH -> location.outgoing.death ?: defaults.death
ChatEvent.JOIN -> location.outgoing.join ?: defaults.join
ChatEvent.LEAVE -> location.outgoing.leave ?: defaults.leave
ChatEvent.ADVANCEMENT -> location.outgoing.advancement ?: defaults.advancement
ChatEvent.BROADCAST -> location.outgoing.broadcast ?: defaults.broadcast
ChatEvent.STATUS -> location.outgoing.status ?: defaults.status
}
if (!matchesEvent) {
logger.info("location: $label dropped message '$msg' from user: '$user', event not enabled")
continue
}
skips.addAll(location.outgoing.skip)
val eventStr = when (event) {
ChatEvent.PLAIN -> ""
ChatEvent.ACTION -> ApiMessage.USER_ACTION
ChatEvent.DEATH -> ""
ChatEvent.JOIN -> ApiMessage.JOIN_LEAVE
ChatEvent.LEAVE -> ApiMessage.JOIN_LEAVE
ChatEvent.ADVANCEMENT -> ""
ChatEvent.BROADCAST -> ""
ChatEvent.STATUS -> ""
}
val username = when {
systemuser -> cfg.outgoing.systemUser
else -> user
}
val avatar = when {
systemuser ->
cfg.outgoing.avatar.systemUserAvatar
cfg.outgoing.avatar.enable && uuid != null ->
cfg.outgoing.avatar.urlTemplate.replace("{uuid}", uuid.toString())
else ->
null
}
when {
msg.isNotBlank() -> MessageHandlerInst.transmit(
ApiMessage(
username = username.stripColorOut,
text = msg.stripColorOut,
event = eventStr,
gateway = location.gateway
).apply {
avatar?.let {
this.avatar = it
}
},
cause = cause
)
else -> logger.warn("WARN: dropped blank message by '$user'")
}
logger.info("sent message through location: $label, cause: $cause")
handled = true
}
return handled
}
}

View File

@ -8,14 +8,17 @@ import matterlink.stripColorOut
object ProgressHandler { object ProgressHandler {
fun handleProgress(name: String, message: String, display: String) { fun handleProgress(name: String, message: String, display: String,
x: Int, y: Int, z: Int,
dimension: Int) {
if (!cfg.outgoing.advancements) return if (!cfg.outgoing.advancements) return
val usr = name.stripColorOut.antiping val usr = name.stripColorOut.antiping
MessageHandlerInst.transmit( LocationHandler.sendToLocations(
ApiMessage( msg = "$usr $message $display".stripColorOut,
text = "$usr $message $display".stripColorOut x = x, y = y, z = z, dimension = dimension,
), event = ChatEvent.ADVANCEMENT,
cause = "Progress Event by $usr" cause = "Progress Event by $usr",
systemuser = true
) )
} }
} }

View File

@ -1,12 +1,13 @@
package matterlink.handlers package matterlink.handlers
import matterlink.api.ApiMessage
import matterlink.bridge.MessageHandlerInst import matterlink.bridge.MessageHandlerInst
import matterlink.bridge.command.BridgeCommandRegistry import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.bridge.format 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 matterlink.stripColorIn import java.util.*
object ServerChatHandler { object ServerChatHandler {
@ -16,33 +17,116 @@ object ServerChatHandler {
fun writeIncomingToChat() { fun writeIncomingToChat() {
if (MessageHandlerInst.queue.isNotEmpty()) if (MessageHandlerInst.queue.isNotEmpty())
logger.debug("incoming: " + MessageHandlerInst.queue.toString()) logger.debug("incoming: " + MessageHandlerInst.queue.toString())
val nextMessage = MessageHandlerInst.queue.poll() ?: null val nextMessage = MessageHandlerInst.queue.poll() ?: return
if (nextMessage?.gateway == cfg.connect.gateway) { val defaults = cfg.incomingDefaults
if (!nextMessage.text.isBlank()) {
nextMessage.text = nextMessage.text.stripColorIn val sourceGateway = nextMessage.gateway
val message = when (nextMessage.event) {
"user_action" -> nextMessage.format(cfg.incoming.action) // find all areas to send to
"" -> {
// try to handle command and do not handle as a chat message val targetUUIDs = mutableSetOf<UUID>()
if (BridgeCommandRegistry.handleCommand(nextMessage)) return val skips = mutableSetOf<String>()
nextMessage.format(cfg.incoming.chat)
} val locations = cfg.locations.filter {
"join_leave" -> nextMessage.format(cfg.incoming.joinPart) it.gateway == sourceGateway
else -> { }
val user = nextMessage.username
val text = nextMessage.text if(nextMessage.event.isEmpty()) {
val json = nextMessage.encode() // filter command handlers
logger.debug("Threw out message with unhandled event: ${nextMessage.event}") val commandLocations = locations.filter {
logger.debug(" Message contents:") it.incoming.commands ?: cfg.incomingDefaults.commands
logger.debug(" User: $user") }
logger.debug(" Text: $text")
logger.debug(" JSON: $json") // process potential command
return for (( label, location) in commandLocations) {
} if (BridgeCommandRegistry.handleCommand(nextMessage)) return
}
instance.wrappedSendToPlayers(message)
} }
} }
for (location in locations) {
val label = location.label
if(skips.contains(label)) {
logger.debug("skipping $label")
continue
}
val matchesEvent = when (nextMessage.event) {
"" -> {
// if (location.incoming.commands ?: defaults.commands
// && BridgeCommandRegistry.handleCommand(nextMessage)) return
location.incoming.plain ?: defaults.plain
}
ApiMessage.JOIN_LEAVE -> location.incoming.join_leave ?: defaults.join_leave
ApiMessage.USER_ACTION -> location.incoming.action ?: defaults.action
else -> {
logger.fatal("unknwon event type '${nextMessage.event}' on incoming message")
return
}
}
if (!matchesEvent) {
logger.info("location: $label dropped message '$nextMessage' event not enabled")
continue
}
targetUUIDs.addAll(instance.collectPlayers(location.area))
}
val message = when (nextMessage.event) {
"user_action" -> nextMessage.format(cfg.incoming.action)
"" -> {
// try to handle command and do not handle as a chat message
if (BridgeCommandRegistry.handleCommand(nextMessage)) return
nextMessage.format(cfg.incoming.chat)
}
"join_leave" -> nextMessage.format(cfg.incoming.joinPart)
else -> {
val user = nextMessage.username
val text = nextMessage.text
val json = nextMessage.encode()
logger.debug("Threw out message with unhandled event: ${nextMessage.event}")
logger.debug(" Message contents:")
logger.debug(" User: $user")
logger.debug(" Text: $text")
logger.debug(" JSON: $json")
return
}
}
targetUUIDs.forEach {
//TODO: optimize send to all at once
instance.wrappedSendToPlayer(it, message)
}
// if (nextMessage?.gateway == cfg.connect.gateway) {
// if (!nextMessage.text.isBlank()) {
// nextMessage.text = nextMessage.text.stripColorIn
// val message = when (nextMessage.event) {
// "user_action" -> nextMessage.format(cfg.incoming.action)
// "" -> {
// // try to handle command and do not handle as a chat message
// if (BridgeCommandRegistry.handleCommand(nextMessage)) return
// nextMessage.format(cfg.incoming.chat)
// }
// "join_leave" -> nextMessage.format(cfg.incoming.joinPart)
// else -> {
// val user = nextMessage.username
// val text = nextMessage.text
// val json = nextMessage.encode()
// logger.debug("Threw out message with unhandled event: ${nextMessage.event}")
// logger.debug(" Message contents:")
// logger.debug(" User: $user")
// logger.debug(" Text: $text")
// logger.debug(" JSON: $json")
// return
// }
// }
// instance.wrappedSendToPlayers(message)
// }
// }
} }
} }

View File

@ -1,7 +1,5 @@
package matterlink.jenkins package matterlink.jenkins
import com.google.gson.annotations.SerializedName
/** /**
* Created by nikky on 03/02/18. * Created by nikky on 03/02/18.
* @author Nikky * @author Nikky

View File

@ -1,4 +1,4 @@
package voodoo.util.jenkins package matterlink.jenkins
import com.google.gson.Gson import com.google.gson.Gson
@ -6,7 +6,6 @@ import matterlink.Result
import matterlink.header import matterlink.header
import matterlink.httpGet import matterlink.httpGet
import matterlink.responseString import matterlink.responseString
import matterlink.jenkins.Job
import matterlink.logger import matterlink.logger
/** /**

View File

@ -1,4 +1,4 @@
package matterlink.jenkins; package matterlink.jenkins
/** /**
* Created by nikky on 03/02/18. * Created by nikky on 03/02/18.

View File

@ -1,13 +1,12 @@
package matterlink.update package matterlink.update
import com.google.gson.FieldNamingPolicy
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
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.instance import matterlink.instance
import matterlink.logger import matterlink.logger
import voodoo.util.jenkins.JenkinsServer import matterlink.jenkins.JenkinsServer
import java.io.BufferedReader import java.io.BufferedReader
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL

View File

@ -1,6 +1,7 @@
mod_name = MatterLink mod_name = MatterLink
mod_version = 1.6.3 mod_version = 1.6.3
forgelin_version = 1.6.0 forgelin_version = 1.6.0
concrete_version = 0.3.8-SNAPSHOT
kotlin_version = 1.2.41 kotlin_version = 1.2.41
shadow_version = 2.0.2 shadow_version = 2.0.2
cursegradle_version = 1.0.10 cursegradle_version = 1.0.10