Move Eventhandling around.

I still want to use fabric still "array backed" events, but these here are just a bit easier to use from kotlin.
This commit is contained in:
nea
2022-09-10 03:48:03 +02:00
parent d9353ff54c
commit ec66c82198
13 changed files with 149 additions and 44 deletions

View File

@@ -1,6 +1,7 @@
# suppress inspection "UnusedProperty" for whole file
org.gradle.jvmargs=-Xmx4096M
minecraft_version=1.19
minecraft_version=1.19.2
loom.platform=fabric
archives_base_name=notenoughupdates
@@ -12,7 +13,7 @@ architectury_version=5.10.33
fabric_loader_version=0.14.8
fabric_api_version=0.58.0+1.19
fabric_kotlin_version=1.8.2+kotlin.1.7.10
yarn_version=1.19.2+build.8
yarn_version=1.19.2+build.9
libgui_version=6.0.0+1.19
rei_version=9.1.518

View File

@@ -25,6 +25,7 @@ import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
import java.nio.file.Files
import java.nio.file.Path
import kotlin.coroutines.EmptyCoroutineContext
import moe.nea.notenoughupdates.features.FeatureManager
object NotEnoughUpdates : ModInitializer, ClientModInitializer {
const val MOD_ID = "notenoughupdates"
@@ -71,8 +72,9 @@ object NotEnoughUpdates : ModInitializer, ClientModInitializer {
override fun onInitialize() {
dbusConnection.requestBusName("moe.nea.notenoughupdates")
dbusConnection.exportObject(NEUDbusObject)
RepoManager.initialize()
ConfigHolder.registerEvents()
RepoManager.initialize()
FeatureManager.autoload()
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands)
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
runBlocking {

View File

@@ -0,0 +1,7 @@
package moe.nea.notenoughupdates.events
abstract class NEUEvent {
abstract class Cancellable : NEUEvent() {
var cancelled: Boolean = false
}
}

View File

@@ -0,0 +1,26 @@
package moe.nea.notenoughupdates.events
import java.util.concurrent.CopyOnWriteArrayList
open class NEUEventBus<T : NEUEvent> {
data class Handler<T>(val invocation: (T) -> Unit, val receivesCancelled: Boolean)
private val toHandle: MutableList<Handler<T>> = CopyOnWriteArrayList()
fun subscribe(handle: (T) -> Unit) {
subscribe(handle, false)
}
fun subscribe(handle: (T) -> Unit, receivesCancelled: Boolean) {
toHandle.add(Handler(handle, receivesCancelled))
}
fun publish(event: T): T {
for (function in toHandle) {
if (function.receivesCancelled || event !is NEUEvent.Cancellable || !event.cancelled) {
function.invocation(event)
}
}
return event
}
}

View File

@@ -1,23 +0,0 @@
package moe.nea.notenoughupdates.events
import moe.nea.notenoughupdates.events.NEUScreenEvents.OnScreenOpen
import net.fabricmc.fabric.api.event.EventFactory
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.MinecraftClient
object NEUScreenEvents {
fun interface OnScreenOpen {
/**
* Called when a new Screen is opened via [MinecraftClient.setScreen]. If [new] is null, this corresponds to closing a [Screen].
* @return true to prevent this event from happening.
*/
fun onScreenOpen(old: Screen?, new: Screen?): Boolean
}
val SCREEN_OPEN = EventFactory.createArrayBacked(OnScreenOpen::class.java) { arr ->
OnScreenOpen { old, new ->
return@OnScreenOpen arr.asSequence().any { it.onScreenOpen(old, new) }
}
}
}

View File

@@ -0,0 +1,7 @@
package moe.nea.notenoughupdates.events
import net.minecraft.client.gui.screen.Screen
data class ScreenOpenEvent(val old: Screen?, val new: Screen?) : NEUEvent.Cancellable() {
companion object : NEUEventBus<ScreenOpenEvent>()
}

View File

@@ -0,0 +1,36 @@
package moe.nea.notenoughupdates.features
import kotlinx.serialization.serializer
import moe.nea.notenoughupdates.NotEnoughUpdates
import moe.nea.notenoughupdates.features.world.FairySouls
import moe.nea.notenoughupdates.util.ConfigHolder
object FeatureManager : ConfigHolder<FeatureManager.Config>(serializer(), "features", ::Config) {
data class Config(
val enabledFeatures: MutableMap<String, Boolean> = mutableMapOf()
)
private val features = mutableMapOf<String, NEUFeature>()
fun autoload() {
loadFeature(FairySouls)
}
fun loadFeature(feature: NEUFeature) {
if (feature.identifier in features) {
NotEnoughUpdates.logger.error("Double registering feature ${feature.identifier}. Ignoring second instance $feature")
return
}
features[feature.identifier] = feature
}
fun isEnabled(identifier: String): Boolean? =
config.enabledFeatures[identifier]
fun setEnabled(identifier: String, value: Boolean) {
config.enabledFeatures[identifier] = value
markDirty()
}
}

View File

@@ -0,0 +1,16 @@
package moe.nea.notenoughupdates.features
interface NEUFeature {
val name: String
val identifier: String
val defaultEnabled: Boolean
get() = true
var isEnabled: Boolean
get() = FeatureManager.isEnabled(identifier) ?: defaultEnabled
set(value) {
FeatureManager.setEnabled(identifier, value)
}
fun onLoad()
}

View File

@@ -0,0 +1,12 @@
package moe.nea.notenoughupdates.features.world
import moe.nea.notenoughupdates.features.NEUFeature
object FairySouls : NEUFeature {
override val name: String get() = "Fairy Souls"
override val identifier: String get() = "fairy-souls"
override fun onLoad() {
}
}

View File

@@ -1,19 +1,20 @@
package moe.nea.notenoughupdates.mixins
import moe.nea.notenoughupdates.events.NEUScreenEvents
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.Screen
import org.spongepowered.asm.mixin.Mixin
import org.spongepowered.asm.mixin.injection.At
import org.spongepowered.asm.mixin.injection.Inject
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.Screen
import moe.nea.notenoughupdates.events.ScreenOpenEvent
@Suppress("CAST_NEVER_SUCCEEDS")
@Mixin(MinecraftClient::class)
class MixinMinecraft {
@Inject(method = ["setScreen"], at = [At("HEAD")], cancellable = true)
fun onScreenChange(screen: Screen?, ci: CallbackInfo) {
if (NEUScreenEvents.SCREEN_OPEN.invoker().onScreenOpen((this as MinecraftClient).currentScreen, screen))
val event = ScreenOpenEvent((this as MinecraftClient).currentScreen, screen)
if (ScreenOpenEvent.publish(event).cancelled)
ci.cancel()
}
}

View File

@@ -76,7 +76,7 @@ object RepoDownloadManager {
return@withContext false
}
val currentSha = loadSavedVersionHash()
if (latestSha != currentSha) {
if (latestSha != currentSha || force) {
val requestUrl = "https://github.com/${RepoManager.config.user}/${RepoManager.config.repo}/archive/$latestSha.zip"
logger.info("Planning to upgrade repository from $currentSha to $latestSha from $requestUrl")
val zipFile = downloadGithubArchive(requestUrl)

View File

@@ -1,21 +1,20 @@
package moe.nea.notenoughupdates.util
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException
import moe.nea.notenoughupdates.NotEnoughUpdates
import moe.nea.notenoughupdates.events.NEUScreenEvents
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
import net.minecraft.client.MinecraftClient
import net.minecraft.command.CommandSource
import net.minecraft.server.command.CommandOutput
import net.minecraft.text.Text
import java.io.IOException
import java.nio.file.Path
import java.util.concurrent.CopyOnWriteArrayList
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException
import kotlin.io.path.exists
import kotlin.io.path.readText
import kotlin.io.path.writeText
import kotlin.reflect.KClass
import net.minecraft.client.MinecraftClient
import net.minecraft.server.command.CommandOutput
import net.minecraft.text.Text
import moe.nea.notenoughupdates.NotEnoughUpdates
import moe.nea.notenoughupdates.events.ScreenOpenEvent
abstract class ConfigHolder<T>(
val serializer: KSerializer<T>,
@@ -108,7 +107,7 @@ abstract class ConfigHolder<T>(
player.sendMessage(
Text.literal(
"The following configs have been reset: ${badLoads.joinToString(", ")}. " +
"This can be intentional, but probably isn't."
"This can be intentional, but probably isn't."
)
)
badLoads.clear()
@@ -116,14 +115,13 @@ abstract class ConfigHolder<T>(
}
fun registerEvents() {
NEUScreenEvents.SCREEN_OPEN.register(NEUScreenEvents.OnScreenOpen { old, new ->
ScreenOpenEvent.subscribe { event ->
performSaves()
val p = MinecraftClient.getInstance().player
if (p != null) {
warnForResetConfigs(p)
}
false
})
}
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
performSaves()
})

View File

@@ -0,0 +1,22 @@
package moe.nea.notenoughupdates.util
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Runnable
import kotlin.coroutines.CoroutineContext
import net.minecraft.client.MinecraftClient
object MinecraftDispatcher : CoroutineDispatcher() {
@ExperimentalCoroutinesApi
override fun limitedParallelism(parallelism: Int): CoroutineDispatcher {
throw UnsupportedOperationException("limitedParallelism is not supported for MinecraftDispatcher")
}
override fun isDispatchNeeded(context: CoroutineContext): Boolean =
!MinecraftClient.getInstance().isOnThread
override fun dispatch(context: CoroutineContext, block: Runnable) {
MinecraftClient.getInstance().execute(block)
}
}