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 org.gradle.jvmargs=-Xmx4096M
minecraft_version=1.19 minecraft_version=1.19.2
loom.platform=fabric loom.platform=fabric
archives_base_name=notenoughupdates archives_base_name=notenoughupdates
@@ -12,7 +13,7 @@ architectury_version=5.10.33
fabric_loader_version=0.14.8 fabric_loader_version=0.14.8
fabric_api_version=0.58.0+1.19 fabric_api_version=0.58.0+1.19
fabric_kotlin_version=1.8.2+kotlin.1.7.10 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 libgui_version=6.0.0+1.19
rei_version=9.1.518 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.Files
import java.nio.file.Path import java.nio.file.Path
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
import moe.nea.notenoughupdates.features.FeatureManager
object NotEnoughUpdates : ModInitializer, ClientModInitializer { object NotEnoughUpdates : ModInitializer, ClientModInitializer {
const val MOD_ID = "notenoughupdates" const val MOD_ID = "notenoughupdates"
@@ -71,8 +72,9 @@ object NotEnoughUpdates : ModInitializer, ClientModInitializer {
override fun onInitialize() { override fun onInitialize() {
dbusConnection.requestBusName("moe.nea.notenoughupdates") dbusConnection.requestBusName("moe.nea.notenoughupdates")
dbusConnection.exportObject(NEUDbusObject) dbusConnection.exportObject(NEUDbusObject)
RepoManager.initialize()
ConfigHolder.registerEvents() ConfigHolder.registerEvents()
RepoManager.initialize()
FeatureManager.autoload()
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands) ClientCommandRegistrationCallback.EVENT.register(this::registerCommands)
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
runBlocking { 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 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.Mixin
import org.spongepowered.asm.mixin.injection.At import org.spongepowered.asm.mixin.injection.At
import org.spongepowered.asm.mixin.injection.Inject import org.spongepowered.asm.mixin.injection.Inject
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo 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") @Suppress("CAST_NEVER_SUCCEEDS")
@Mixin(MinecraftClient::class) @Mixin(MinecraftClient::class)
class MixinMinecraft { class MixinMinecraft {
@Inject(method = ["setScreen"], at = [At("HEAD")], cancellable = true) @Inject(method = ["setScreen"], at = [At("HEAD")], cancellable = true)
fun onScreenChange(screen: Screen?, ci: CallbackInfo) { 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() ci.cancel()
} }
} }

View File

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

View File

@@ -1,21 +1,20 @@
package moe.nea.notenoughupdates.util 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.io.IOException
import java.nio.file.Path import java.nio.file.Path
import java.util.concurrent.CopyOnWriteArrayList 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.exists
import kotlin.io.path.readText import kotlin.io.path.readText
import kotlin.io.path.writeText import kotlin.io.path.writeText
import kotlin.reflect.KClass 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>( abstract class ConfigHolder<T>(
val serializer: KSerializer<T>, val serializer: KSerializer<T>,
@@ -116,14 +115,13 @@ abstract class ConfigHolder<T>(
} }
fun registerEvents() { fun registerEvents() {
NEUScreenEvents.SCREEN_OPEN.register(NEUScreenEvents.OnScreenOpen { old, new -> ScreenOpenEvent.subscribe { event ->
performSaves() performSaves()
val p = MinecraftClient.getInstance().player val p = MinecraftClient.getInstance().player
if (p != null) { if (p != null) {
warnForResetConfigs(p) warnForResetConfigs(p)
} }
false }
})
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
performSaves() 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)
}
}