diff options
Diffstat (limited to 'src/main/kotlin')
12 files changed, 146 insertions, 42 deletions
diff --git a/src/main/kotlin/moe/nea/notenoughupdates/NotEnoughUpdates.kt b/src/main/kotlin/moe/nea/notenoughupdates/NotEnoughUpdates.kt index 4868fbf..a2949a7 100644 --- a/src/main/kotlin/moe/nea/notenoughupdates/NotEnoughUpdates.kt +++ b/src/main/kotlin/moe/nea/notenoughupdates/NotEnoughUpdates.kt @@ -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 { diff --git a/src/main/kotlin/moe/nea/notenoughupdates/events/NEUEvent.kt b/src/main/kotlin/moe/nea/notenoughupdates/events/NEUEvent.kt new file mode 100644 index 0000000..278282e --- /dev/null +++ b/src/main/kotlin/moe/nea/notenoughupdates/events/NEUEvent.kt @@ -0,0 +1,7 @@ +package moe.nea.notenoughupdates.events + +abstract class NEUEvent { + abstract class Cancellable : NEUEvent() { + var cancelled: Boolean = false + } +} diff --git a/src/main/kotlin/moe/nea/notenoughupdates/events/NEUEventBus.kt b/src/main/kotlin/moe/nea/notenoughupdates/events/NEUEventBus.kt new file mode 100644 index 0000000..eba71bc --- /dev/null +++ b/src/main/kotlin/moe/nea/notenoughupdates/events/NEUEventBus.kt @@ -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 + } + +} diff --git a/src/main/kotlin/moe/nea/notenoughupdates/events/NEUScreenEvents.kt b/src/main/kotlin/moe/nea/notenoughupdates/events/NEUScreenEvents.kt deleted file mode 100644 index 64edda0..0000000 --- a/src/main/kotlin/moe/nea/notenoughupdates/events/NEUScreenEvents.kt +++ /dev/null @@ -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) } - } - } - -} diff --git a/src/main/kotlin/moe/nea/notenoughupdates/events/ScreenOpenEvent.kt b/src/main/kotlin/moe/nea/notenoughupdates/events/ScreenOpenEvent.kt new file mode 100644 index 0000000..793f066 --- /dev/null +++ b/src/main/kotlin/moe/nea/notenoughupdates/events/ScreenOpenEvent.kt @@ -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>() +} diff --git a/src/main/kotlin/moe/nea/notenoughupdates/features/FeatureManager.kt b/src/main/kotlin/moe/nea/notenoughupdates/features/FeatureManager.kt new file mode 100644 index 0000000..766cf1f --- /dev/null +++ b/src/main/kotlin/moe/nea/notenoughupdates/features/FeatureManager.kt @@ -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() + } + +} diff --git a/src/main/kotlin/moe/nea/notenoughupdates/features/NEUFeature.kt b/src/main/kotlin/moe/nea/notenoughupdates/features/NEUFeature.kt new file mode 100644 index 0000000..1d3628e --- /dev/null +++ b/src/main/kotlin/moe/nea/notenoughupdates/features/NEUFeature.kt @@ -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() + +} diff --git a/src/main/kotlin/moe/nea/notenoughupdates/features/world/FairySouls.kt b/src/main/kotlin/moe/nea/notenoughupdates/features/world/FairySouls.kt new file mode 100644 index 0000000..b928f3d --- /dev/null +++ b/src/main/kotlin/moe/nea/notenoughupdates/features/world/FairySouls.kt @@ -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() { + + } +} diff --git a/src/main/kotlin/moe/nea/notenoughupdates/mixins/MixinMinecraft.kt b/src/main/kotlin/moe/nea/notenoughupdates/mixins/MixinMinecraft.kt index 21834e9..3bc1a5f 100644 --- a/src/main/kotlin/moe/nea/notenoughupdates/mixins/MixinMinecraft.kt +++ b/src/main/kotlin/moe/nea/notenoughupdates/mixins/MixinMinecraft.kt @@ -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() } } diff --git a/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt b/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt index c354392..2d700c1 100644 --- a/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt +++ b/src/main/kotlin/moe/nea/notenoughupdates/repo/RepoDownloadManager.kt @@ -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) diff --git a/src/main/kotlin/moe/nea/notenoughupdates/util/ConfigHolder.kt b/src/main/kotlin/moe/nea/notenoughupdates/util/ConfigHolder.kt index 7827708..50a3d9b 100644 --- a/src/main/kotlin/moe/nea/notenoughupdates/util/ConfigHolder.kt +++ b/src/main/kotlin/moe/nea/notenoughupdates/util/ConfigHolder.kt @@ -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() }) diff --git a/src/main/kotlin/moe/nea/notenoughupdates/util/MinecraftDispatcher.kt b/src/main/kotlin/moe/nea/notenoughupdates/util/MinecraftDispatcher.kt new file mode 100644 index 0000000..366b81a --- /dev/null +++ b/src/main/kotlin/moe/nea/notenoughupdates/util/MinecraftDispatcher.kt @@ -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) + } +} |