diff --git a/README.md b/README.md
index 23e6536e..872abdf5 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@ Include the dependency to MCCoroutine
com.github.shynixn.mccoroutine
mccoroutine-bukkit-api
- 0.0.4
+ 0.0.5
provided
```
@@ -52,7 +52,7 @@ Include the dependency to MCCoroutine
```xml
dependencies {
- compileOnly("com.github.shynixn.mccoroutine:mccoroutine-bukkit-api:0.0.4")
+ compileOnly("com.github.shynixn.mccoroutine:mccoroutine-bukkit-api:0.0.5")
}
```
@@ -198,12 +198,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlin.coroutines.CoroutineContext
-fun launch(f: suspend CoroutineScope.() -> Unit) {
- JavaPlugin.getPlugin(YourPluginClass::class.java).launch(f)
+fun launch(f: suspend CoroutineScope.() -> Unit): Job {
+ return JavaPlugin.getPlugin(YourPluginClass::class.java).launch(f)
}
-fun launchAsync(f: suspend CoroutineScope.() -> Unit) {
- JavaPlugin.getPlugin(YourPluginClass::class.java).launchAsync(f)
+fun launchAsync(f: suspend CoroutineScope.() -> Unit): Job {
+ return JavaPlugin.getPlugin(YourPluginClass::class.java).launchAsync(f)
}
val Dispatchers.minecraft: CoroutineContext
@@ -486,7 +486,7 @@ class PlaceHolderApiConnector(private val cache : UserDataCache) {
com.github.shynixn.mccoroutine
mccoroutine-bukkit-core
- 0.0.4
+ 0.0.5
compile
@@ -512,7 +512,7 @@ class PlaceHolderApiConnector(private val cache : UserDataCache) {
```xml
dependencies {
- implementation("com.github.shynixn.mccoroutine:mccoroutine-bukkit-core:0.0.4")
+ implementation("com.github.shynixn.mccoroutine:mccoroutine-bukkit-core:0.0.5")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.x.x")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.x.x")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.x.x")
diff --git a/build.gradle b/build.gradle
index 888d6d25..3eb87421 100644
--- a/build.gradle
+++ b/build.gradle
@@ -41,7 +41,7 @@ allprojects {
subprojects {
group 'com.github.shynixn.mccoroutine'
- version '0.0.4'
+ version '0.0.5'
sourceCompatibility = 1.8
diff --git a/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/Extension.kt b/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/Extension.kt
index fd61b0f9..125854da 100644
--- a/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/Extension.kt
+++ b/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/Extension.kt
@@ -2,6 +2,7 @@ package com.github.shynixn.mccoroutine
import com.github.shynixn.mccoroutine.contract.MCCoroutine
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import org.bukkit.command.PluginCommand
import org.bukkit.event.Listener
import org.bukkit.plugin.Plugin
@@ -68,9 +69,10 @@ val Plugin.scope: CoroutineScope
* for example that event cancelling or modifying return values is still possible.
* @param dispatcher Coroutine context. The default context is minecraft dispatcher.
* @param f callback function inside a coroutine scope.
+ * @return Cancelable coroutine job.
*/
-fun Plugin.launch(dispatcher: CoroutineContext, f: suspend CoroutineScope.() -> Unit) {
- mcCoroutine.getCoroutineSession(this).launch(dispatcher, f)
+fun Plugin.launch(dispatcher: CoroutineContext, f: suspend CoroutineScope.() -> Unit): Job {
+ return mcCoroutine.getCoroutineSession(this).launch(dispatcher, f)
}
/**
@@ -79,9 +81,10 @@ fun Plugin.launch(dispatcher: CoroutineContext, f: suspend CoroutineScope.() ->
* calling this function Bukkit.isPrimaryThread() is true. This means
* for example that event cancelling or modifying return values is still possible.
* @param f callback function inside a coroutine scope.
+ * @return Cancelable coroutine job.
*/
-fun Plugin.launch(f: suspend CoroutineScope.() -> Unit) {
- mcCoroutine.getCoroutineSession(this).launch(minecraftDispatcher, f)
+fun Plugin.launch(f: suspend CoroutineScope.() -> Unit): Job {
+ return mcCoroutine.getCoroutineSession(this).launch(minecraftDispatcher, f)
}
/**
@@ -90,9 +93,10 @@ fun Plugin.launch(f: suspend CoroutineScope.() -> Unit) {
* calling this function Bukkit.isPrimaryThread() is false. This means
* for example that event cancelling or modifying return values is still possible.
* @param f callback function inside a coroutine scope.
+ * @return Cancelable coroutine job.
*/
-fun Plugin.launchAsync(f: suspend CoroutineScope.() -> Unit) {
- mcCoroutine.getCoroutineSession(this).launch(this.asyncDispatcher, f)
+fun Plugin.launchAsync(f: suspend CoroutineScope.() -> Unit): Job {
+ return mcCoroutine.getCoroutineSession(this).launch(this.asyncDispatcher, f)
}
/**
diff --git a/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/contract/CoroutineSession.kt b/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/contract/CoroutineSession.kt
index a789d684..f48d8962 100644
--- a/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/contract/CoroutineSession.kt
+++ b/mccoroutine-bukkit-api/src/main/java/com/github/shynixn/mccoroutine/contract/CoroutineSession.kt
@@ -1,6 +1,7 @@
package com.github.shynixn.mccoroutine.contract
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
interface CoroutineSession {
@@ -31,8 +32,9 @@ interface CoroutineSession {
/**
* Launches the given function on the plugin coroutine scope.
+ * @return Cancelable coroutine job.
*/
- fun launch(dispatcher: CoroutineContext, f: suspend CoroutineScope.() -> Unit)
+ fun launch(dispatcher: CoroutineContext, f: suspend CoroutineScope.() -> Unit) : Job
/**
* Disposes the session.
diff --git a/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/CoroutineSessionImpl.kt b/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/CoroutineSessionImpl.kt
index d32d7cf8..8a5e34d8 100644
--- a/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/CoroutineSessionImpl.kt
+++ b/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/CoroutineSessionImpl.kt
@@ -60,18 +60,17 @@ internal class CoroutineSessionImpl(private val plugin: Plugin) : CoroutineSessi
/**
* Launches the given function on the plugin coroutine scope.
*/
- override fun launch(dispatcher: CoroutineContext, f: suspend CoroutineScope.() -> Unit) {
+ override fun launch(dispatcher: CoroutineContext, f: suspend CoroutineScope.() -> Unit) : Job {
if (disposed) {
- return
+ return Job()
}
if (dispatcher == Dispatchers.Unconfined) {
// If the dispatcher is unconfined. Always schedule immediately.
- launchInternal(dispatcher, CoroutineStart.UNDISPATCHED, f)
- return
+ return launchInternal(dispatcher, CoroutineStart.UNDISPATCHED, f)
}
- launchInternal(dispatcher, CoroutineStart.DEFAULT, f)
+ return launchInternal(dispatcher, CoroutineStart.DEFAULT, f)
}
/**
@@ -81,9 +80,9 @@ internal class CoroutineSessionImpl(private val plugin: Plugin) : CoroutineSessi
dispatcher: CoroutineContext,
coroutineStart: CoroutineStart,
f: suspend CoroutineScope.() -> Unit
- ) {
+ ) : Job {
// Launch a new coroutine on the current thread thread on the plugin scope.
- scope.launch(dispatcher, coroutineStart) {
+ return scope.launch(dispatcher, coroutineStart) {
try {
// The user may or may not launch multiple sub suspension operations. If
// one of those fails, only this scope should fail instead of the plugin scope.
diff --git a/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/EventServiceImpl.kt b/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/EventServiceImpl.kt
index eb81ca9c..5452997c 100644
--- a/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/EventServiceImpl.kt
+++ b/mccoroutine-bukkit-core/src/main/java/com/github/shynixn/mccoroutine/service/EventServiceImpl.kt
@@ -3,26 +3,17 @@ package com.github.shynixn.mccoroutine.service
import com.github.shynixn.mccoroutine.contract.CoroutineSession
import com.github.shynixn.mccoroutine.contract.EventService
import com.github.shynixn.mccoroutine.extension.invokeSuspend
-import com.github.shynixn.mccoroutine.launch
-import com.github.shynixn.mccoroutine.minecraftDispatcher
import kotlinx.coroutines.Dispatchers
import org.bukkit.Warning
import org.bukkit.event.*
import org.bukkit.plugin.*
-import org.bukkit.plugin.java.JavaPluginLoader
import java.lang.Deprecated
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
-import java.util.*
import java.util.logging.Level
-import kotlin.Any
-import kotlin.Exception
import kotlin.IllegalArgumentException
-import kotlin.Int
import kotlin.String
import kotlin.Throwable
-import kotlin.collections.HashMap
-import kotlin.collections.HashSet
internal class EventServiceImpl(private val plugin: Plugin, private val coroutineSession: CoroutineSession) :
EventService {
@@ -37,119 +28,96 @@ internal class EventServiceImpl(private val plugin: Plugin, private val coroutin
method.isAccessible = true
for (entry in registeredListeners.entries) {
- val clazz = entry.key as Class<*>
+ val clazz = entry.key
val handlerList = method.invoke(plugin.server.pluginManager, clazz) as HandlerList
handlerList.registerAll(entry.value as MutableCollection)
}
}
/**
- * Ugly coroutine listener hacking.
+ * Creates a listener according to the spigot implementation.
*/
- private fun createCoroutineListener(listener: Listener, plugin: Plugin): HashMap<*, *> {
- val ret: HashMap, Set> = HashMap()
+ private fun createCoroutineListener(
+ listener: Listener,
+ plugin: Plugin
+ ): Map, MutableSet> {
+ val eventMethods = HashSet()
- val methods: HashSet<*>
try {
- val publicMethods = listener.javaClass.methods
- val privateMethods = listener.javaClass.declaredMethods
- methods = HashSet(publicMethods.size + privateMethods.size, 1.0f)
- var var11 = publicMethods
- var var10 = publicMethods.size
- var method: Method?
- var var9: Int
- var9 = 0
- while (var9 < var10) {
- method = var11[var9]
- methods.add(method)
- ++var9
+ // Adds public methods of the current class and inherited classes
+ eventMethods.addAll(listener.javaClass.methods)
+ // Adds all methods of the current class
+ eventMethods.addAll(listener.javaClass.declaredMethods)
+ } catch (e: NoClassDefFoundError) {
+ plugin.logger.severe("Plugin " + plugin.description.fullName + " has failed to register events for " + listener.javaClass + " because " + e.message + " does not exist.")
+ return emptyMap()
+ }
+
+ val result = mutableMapOf, MutableSet>()
+
+ for (method in eventMethods) {
+ val annotation = method.getAnnotation(EventHandler::class.java)
+
+ if (annotation == null || method.isBridge || method.isSynthetic) {
+ continue
}
- var11 = privateMethods
- var10 = privateMethods.size
- var9 = 0
- while (var9 < var10) {
- method = var11[var9]
- methods.add(method)
- ++var9
+
+ val eventClass = method.parameterTypes[0].asSubclass(Event::class.java)
+ method.isAccessible = true
+
+ if (!result.containsKey(eventClass)) {
+ result[eventClass] = HashSet()
}
- } catch (var15: NoClassDefFoundError) {
- plugin.logger.severe("Plugin " + plugin.description.fullName + " has failed to register events for " + listener.javaClass + " because " + var15.message + " does not exist.")
- return ret
- }
- val var17: Iterator<*> = methods.iterator()
-
- while (true) {
- while (true) {
- var method: Method
- var eh: EventHandler?
- do {
- do {
- do {
- if (!var17.hasNext()) {
- return ret
- }
- method = var17.next() as Method
- eh = method.getAnnotation(EventHandler::class.java)
- } while (eh == null)
- } while (method.isBridge)
- } while (method.isSynthetic)
-
- var checkClass: Class<*> = method.getParameterTypes()[0]
- val eventClass = checkClass.asSubclass(Event::class.java)
- method.isAccessible = true
-
- var eventSet: MutableSet? = ret[eventClass] as MutableSet?
-
- if (eventSet == null) {
- eventSet = HashSet()
- ret[eventClass] = eventSet
- }
+ var clazz: Class<*> = eventClass
- var clazz: Class<*> = eventClass
-
- while (Event::class.java.isAssignableFrom(clazz)) {
- if (clazz.getAnnotation(Deprecated::class.java) != null) {
- val warning = clazz.getAnnotation(Warning::class.java)
- val warningState: Warning.WarningState = plugin.server.getWarningState()
- if (warningState.printFor(warning)) {
- plugin.logger.log(
- Level.WARNING,
- String.format(
- "\"%s\" has registered a listener for %s on method \"%s\", but the event is Deprecated. \"%s\"; please notify the authors %s.",
- plugin.description.fullName,
- clazz.name,
- method.toGenericString(),
- if (warning != null && warning.reason.length != 0) warning.reason else "Server performance will be affected",
- Arrays.toString(plugin.description.authors.toTypedArray())
- ),
- if (warningState == Warning.WarningState.ON) AuthorNagException(null as String?) else null
- )
- }
- break
- }
+ while (Event::class.java.isAssignableFrom(clazz)) {
+ if (clazz.getAnnotation(Deprecated::class.java) == null) {
clazz = clazz.superclass
+ continue
+ }
+
+ val warning = clazz.getAnnotation(Warning::class.java)
+ val warningState = plugin.server.warningState
+
+ if (!warningState.printFor(warning)) {
+ break
}
- val executor = createEventExecutor(plugin, eventClass, method)
- eventSet!!.add(
- RegisteredListener(
- listener,
- executor,
- eh!!.priority,
- plugin,
- eh!!.ignoreCancelled
- )
+ plugin.logger.log(
+ Level.WARNING,
+ """"%s" has registered a listener for %s on method "%s", but the event is Deprecated. "%s"; please notify the authors %s.""".format(
+ plugin.description.fullName,
+ clazz.name,
+ method.toGenericString(),
+ if (warning?.reason?.isNotEmpty() == true) warning.reason else "Server performance will be affected",
+ plugin.description.authors.toTypedArray().contentToString()
+ ),
+ if (warningState == Warning.WarningState.ON) {
+ AuthorNagException(null as String?)
+ } else null
)
}
+
+ val executor = createEventExecutor(eventClass, method)
+ result[eventClass]!!.add(
+ RegisteredListener(
+ listener,
+ executor,
+ annotation.priority,
+ plugin,
+ annotation.ignoreCancelled
+ )
+ )
}
+
+ return result
}
/**
* Creates a single event executor.
*/
private fun createEventExecutor(
- plugin: Plugin,
eventClass: Class<*>,
method: Method
): EventExecutor {
diff --git a/mccoroutine-bukkit-core/src/test/java/helper/MockedCoroutineSession.kt b/mccoroutine-bukkit-core/src/test/java/helper/MockedCoroutineSession.kt
index 14f42515..1350e57f 100644
--- a/mccoroutine-bukkit-core/src/test/java/helper/MockedCoroutineSession.kt
+++ b/mccoroutine-bukkit-core/src/test/java/helper/MockedCoroutineSession.kt
@@ -3,10 +3,7 @@ package helper
import com.github.shynixn.mccoroutine.contract.CommandService
import com.github.shynixn.mccoroutine.contract.CoroutineSession
import com.github.shynixn.mccoroutine.contract.EventService
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.*
import org.mockito.Mockito
import kotlin.coroutines.CoroutineContext
@@ -48,8 +45,8 @@ class MockedCoroutineSession : CoroutineSession {
/**
* Launches the given function on the plugin coroutine scope.
*/
- override fun launch(dispatcher: CoroutineContext, f: suspend kotlinx.coroutines.CoroutineScope.() -> Unit) {
- GlobalScope.launch(dispatcher) {
+ override fun launch(dispatcher: CoroutineContext, f: suspend kotlinx.coroutines.CoroutineScope.() -> Unit) : Job {
+ return GlobalScope.launch(dispatcher) {
f.invoke(this)
}
}
diff --git a/mccoroutine-bukkit-sample/build.gradle.kts b/mccoroutine-bukkit-sample/build.gradle.kts
index 0d080ef7..11c57568 100644
--- a/mccoroutine-bukkit-sample/build.gradle.kts
+++ b/mccoroutine-bukkit-sample/build.gradle.kts
@@ -15,7 +15,7 @@ tasks.withType {
archiveName = "$baseName-$version.$extension"
// Change the output folder of the plugin.
- destinationDir = File("D:\\Benutzer\\Temp\\plugins")
+ // destinationDir = File("D:\\Benutzer\\Temp\\plugins")
}
repositories {
diff --git a/mccoroutine-bukkit-sample/src/main/resources/plugin.yml b/mccoroutine-bukkit-sample/src/main/resources/plugin.yml
index 7f198c5a..8756359f 100644
--- a/mccoroutine-bukkit-sample/src/main/resources/plugin.yml
+++ b/mccoroutine-bukkit-sample/src/main/resources/plugin.yml
@@ -1,5 +1,5 @@
name: MCCoroutine-Sample
-version: 0.0.4
+version: 0.0.5
author: Shynixn
main: com.github.shynixn.mccoroutine.sample.MCCoroutineSamplePlugin
commands: