From 59566bcab8a5861e0cb78e8c207884006828bd63 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Wed, 13 Nov 2024 15:44:04 +0100 Subject: fix: Improve exception logging for entity widgets --- .../moe/nea/firmament/compat/rei/EntityWidget.kt | 7 ++- .../compat/rei/recipes/SBMobDropRecipe.kt | 66 +++++++++++----------- src/main/kotlin/gui/entity/EntityRenderer.kt | 19 +++---- src/main/kotlin/util/ErrorUtil.kt | 25 ++++++++ 4 files changed, 68 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt index 7a464c3..d8238be 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt @@ -10,9 +10,10 @@ import net.minecraft.client.gui.Element import net.minecraft.client.gui.ParentElement import net.minecraft.entity.LivingEntity import moe.nea.firmament.gui.entity.EntityRenderer +import moe.nea.firmament.util.ErrorUtil -class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBounds() { +class EntityWidget(val entity: LivingEntity?, val point: Point) : WidgetWithBounds() { override fun children(): List { return emptyList() } @@ -22,9 +23,9 @@ class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBound override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { try { if (!hasErrored) - EntityRenderer.renderEntity(entity, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat()) + EntityRenderer.renderEntity(entity!!, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat()) } catch (ex: Exception) { - EntityRenderer.logger.error("Failed to render constructed entity: $entity", ex) + ErrorUtil.softError("Failed to render constructed entity: $entity", ex) hasErrored = true } if (hasErrored) { diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt index 81ec41b..b05c3c7 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt @@ -39,44 +39,42 @@ class SBMobDropRecipe(override val neuRecipe: NEUMobDropRecipe) : SBRecipe() { } else { EntityRenderer.applyModifiers(source, listOf()) } - if (entity != null) { - val level = display.neuRecipe.level - val fullMobName = - if (level > 0) Text.translatable("firmament.recipe.mobs.name", level, display.neuRecipe.name) - else Text.translatable("firmament.recipe.mobs.name.nolevel", display.neuRecipe.name) - val tt = mutableListOf() - tt.add((fullMobName)) - tt.add(Text.literal("")) - if (display.neuRecipe.coins > 0) { - tt.add(Text.stringifiedTranslatable("firmament.recipe.mobs.coins", display.neuRecipe.coins)) - } - if (display.neuRecipe.combatExperience > 0) { - tt.add( - Text.stringifiedTranslatable( - "firmament.recipe.mobs.combat", - display.neuRecipe.combatExperience - ) - ) - } - if (display.neuRecipe.enchantingExperience > 0) { - tt.add( - Text.stringifiedTranslatable( - "firmament.recipe.mobs.exp", - display.neuRecipe.enchantingExperience - ) + val level = display.neuRecipe.level + val fullMobName = + if (level > 0) Text.translatable("firmament.recipe.mobs.name", level, display.neuRecipe.name) + else Text.translatable("firmament.recipe.mobs.name.nolevel", display.neuRecipe.name) + val tt = mutableListOf() + tt.add((fullMobName)) + tt.add(Text.literal("")) + if (display.neuRecipe.coins > 0) { + tt.add(Text.stringifiedTranslatable("firmament.recipe.mobs.coins", display.neuRecipe.coins)) + } + if (display.neuRecipe.combatExperience > 0) { + tt.add( + Text.stringifiedTranslatable( + "firmament.recipe.mobs.combat", + display.neuRecipe.combatExperience ) - } - if (display.neuRecipe.extra != null) - display.neuRecipe.extra.mapTo(tt) { Text.literal(it) } - if (tt.size == 2) - tt.removeAt(1) - add( - Widgets.withTooltip( - EntityWidget(entity, Point(bounds.minX + 5, bounds.minY + 15)), - tt + ) + } + if (display.neuRecipe.enchantingExperience > 0) { + tt.add( + Text.stringifiedTranslatable( + "firmament.recipe.mobs.exp", + display.neuRecipe.enchantingExperience ) ) } + if (display.neuRecipe.extra != null) + display.neuRecipe.extra.mapTo(tt) { Text.literal(it) } + if (tt.size == 2) + tt.removeAt(1) + add( + Widgets.withTooltip( + EntityWidget(entity, Point(bounds.minX + 5, bounds.minY + 15)), + tt + ) + ) add( Widgets.createLabel(Point(bounds.minX + 15, bounds.minY + 5), Text.literal(display.neuRecipe.name)) .leftAligned() diff --git a/src/main/kotlin/gui/entity/EntityRenderer.kt b/src/main/kotlin/gui/entity/EntityRenderer.kt index ddb862f..022b9a3 100644 --- a/src/main/kotlin/gui/entity/EntityRenderer.kt +++ b/src/main/kotlin/gui/entity/EntityRenderer.kt @@ -3,7 +3,6 @@ package moe.nea.firmament.gui.entity import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject -import org.apache.logging.log4j.LogManager import org.joml.Quaternionf import org.joml.Vector3f import kotlin.math.atan @@ -15,8 +14,8 @@ import net.minecraft.entity.LivingEntity import net.minecraft.entity.SpawnReason import net.minecraft.util.Identifier import net.minecraft.world.World +import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.MC -import moe.nea.firmament.util.assertNotNullOr import moe.nea.firmament.util.iterate import moe.nea.firmament.util.openFirmamentResource import moe.nea.firmament.util.render.enableScissorWithTranslation @@ -76,18 +75,15 @@ object EntityRenderer { "name" to ModifyName, ) - val logger = LogManager.getLogger("Firmament.Entity") fun applyModifiers(entityId: String, modifiers: List): LivingEntity? { - val entityType = assertNotNullOr(entityIds[entityId]) { - logger.error("Could not create entity with id $entityId") + val entityType = ErrorUtil.notNullOr(entityIds[entityId], "Could not create entity with id $entityId") { return null } - var entity = entityType() + var entity = ErrorUtil.catch("") { entityType() }.or { return null } for (modifierJson in modifiers) { - val modifier = assertNotNullOr(modifierJson["type"]?.asString?.let(entityModifiers::get)) { - logger.error("Unknown modifier $modifierJson") - return null - } + val modifier = ErrorUtil.notNullOr( + modifierJson["type"]?.asString?.let(entityModifiers::get), + "Could not create entity with id $entityId. Failed to apply modifier $modifierJson") { return null } entity = modifier.apply(entity, modifierJson) } return entity @@ -95,8 +91,7 @@ object EntityRenderer { fun constructEntity(info: JsonObject): LivingEntity? { val modifiers = (info["modifiers"] as JsonArray?)?.map { it.asJsonObject } ?: emptyList() - val entityType = assertNotNullOr(info["entity"]?.asString) { - logger.error("Missing entity type on entity object") + val entityType = ErrorUtil.notNullOr(info["entity"]?.asString, "Missing entity type on entity object") { return null } return applyModifiers(entityType, modifiers) diff --git a/src/main/kotlin/util/ErrorUtil.kt b/src/main/kotlin/util/ErrorUtil.kt index 5dc44d3..190381d 100644 --- a/src/main/kotlin/util/ErrorUtil.kt +++ b/src/main/kotlin/util/ErrorUtil.kt @@ -37,6 +37,31 @@ object ErrorUtil { else Firmament.logger.error(message) } + class Catch private constructor(val value: T?, val exc: Throwable?) { + inline fun or(block: (exc: Throwable) -> T): T { + contract { + callsInPlace(block, InvocationKind.AT_MOST_ONCE) + } + if (exc != null) return block(exc) + @Suppress("UNCHECKED_CAST") + return value as T + } + + companion object { + fun fail(exception: Throwable): Catch = Catch(null, exception) + fun succeed(value: T): Catch = Catch(value, null) + } + } + + inline fun catch(message: String, block: () -> T): Catch { + try { + return Catch.succeed(block()) + } catch (exc: Throwable) { + softError(message, exc) + return Catch.fail(exc) + } + } + inline fun notNullOr(nullable: T?, message: String, orElse: () -> T): T { contract { callsInPlace(orElse, InvocationKind.AT_MOST_ONCE) -- cgit