Skip to content

Commit

Permalink
fix: Handle exceptions in coroutine scope dialogs (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucyydotp authored Aug 10, 2024
1 parent 43962cd commit 5f4c11e
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 5 deletions.
3 changes: 2 additions & 1 deletion api/src/main/resources/assets/sheeplib/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"sheeplib.progress.complete": "Complete",
"sheeplib.progress.failed": "Failed",

"sheeplib.error": "[SheepLib] An error occurred while opening a dialog.\nCheck your game log for more information."
"sheeplib.error": "[SheepLib] An error occurred while opening a dialog.\nCheck your game log for more information.",
"sheeplib.error.coroutine": "[SheepLib] An error occurred in a dialog, so it was closed.\nCheck your game log for more information."
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,40 @@ package com.noxcrew.sheeplib.coroutines
import com.noxcrew.sheeplib.dialog.Dialog
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import net.minecraft.ChatFormatting
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.MustBeInvokedByOverriders
import org.slf4j.LoggerFactory
import kotlin.coroutines.CoroutineContext
import kotlin.reflect.jvm.jvmName

/** A dialog with its own [CoroutineContext], which is cancelled when the dialog is closed. */
@ApiStatus.Experimental
public abstract class CoroutineScopeDialog(
x: Int,
y: Int,
dispatcher: CoroutineDispatcher = MinecraftDispatchers.Background
dispatcher: CoroutineDispatcher = MinecraftDispatchers.Background,
) : Dialog(x, y),
CoroutineScope {

override val coroutineContext: CoroutineContext by lazy { SupervisorJob() + CoroutineName("$this") + dispatcher }
override val coroutineContext: CoroutineContext by lazy {
SupervisorJob() +
CoroutineName("$this") +
dispatcher +
CoroutineExceptionHandler { _, ex ->
Minecraft.getInstance().gui.chat.addMessage(
Component.translatable("sheeplib.error.coroutine").withStyle { it.withColor(ChatFormatting.RED) }
)
LoggerFactory.getLogger("SheepLib").error("Exception caught in dialog coroutine scope (${this::class.jvmName}):\n" + ex.stackTraceToString())
close()
}
}

/** Cancels the coroutine context. Must be invoked by overriders. */
@MustBeInvokedByOverriders
Expand All @@ -30,4 +46,4 @@ public abstract class CoroutineScopeDialog(
}

/** A cancellation exception that indicates that a job's [CoroutineScopeDialog] was closed. */
public object DialogClosedCancellationException: CancellationException()
public object DialogClosedCancellationException : CancellationException()
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.noxcrew.sheeplib.testmod

import com.noxcrew.sheeplib.coroutines.CoroutineScopeDialog
import com.noxcrew.sheeplib.layout.grid
import com.noxcrew.sheeplib.theme.DefaultTheme
import com.noxcrew.sheeplib.theme.Themed
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.components.StringWidget
import net.minecraft.client.gui.layouts.Layout
import net.minecraft.network.chat.Component
import kotlin.time.Duration.Companion.seconds

/**
* A coroutine scope dialog that throws an exception in a coroutine.
*/
public class ExceptionCoroutineDialog(x: Int, y: Int) : CoroutineScopeDialog(x, y), Themed by DefaultTheme {
override fun layout(): Layout = grid {
launch {
delay(1.seconds)
error("Test exception from the exception coroutine dialog. This is not a bug.")
}

StringWidget(Component.literal("This dialog will error shortly"), Minecraft.getInstance().font).atBottom(0)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public object SheepLibTestMod : ClientModInitializer {
"progress" to ::ProgressDialog,
"buttons" to ::ButtonCollectionsDialog,
"exception" to ::ExceptionDialog,
"exception-coroutine" to ::ExceptionCoroutineDialog,
"z-index" to ::AdjustableZIndexDialog
)

Expand Down

0 comments on commit 5f4c11e

Please sign in to comment.