From 088cc1a336e0178cf8fc9c6bb6035ad910c1cb5d Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Sat, 31 Aug 2024 12:07:33 -0700 Subject: [PATCH] Prevent entries added through CopperRegistries from crashing the game Most reported issues of this happening are actually caused by a different issue during registration that is suppressed due to the crash. Now that the crash can't happen, the underlying exception will be properly reported. This change also allows using Create with the Compressed mod, but if Compressed loads before Create, Create's additions to the CopperRegistries will fail to apply. --- .../foundation/block/CopperRegistries.java | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/simibubi/create/foundation/block/CopperRegistries.java b/src/main/java/com/simibubi/create/foundation/block/CopperRegistries.java index c64d80124..ba4e1010a 100644 --- a/src/main/java/com/simibubi/create/foundation/block/CopperRegistries.java +++ b/src/main/java/com/simibubi/create/foundation/block/CopperRegistries.java @@ -1,8 +1,12 @@ package com.simibubi.create.foundation.block; import java.lang.reflect.Field; +import java.util.function.BiConsumer; import java.util.function.Supplier; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; + import com.google.common.base.Suppliers; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; @@ -51,9 +55,11 @@ public class CopperRegistries { weatheringMemoized = true; ImmutableBiMap.Builder builder = ImmutableBiMap.builder(); builder.putAll(originalWeatheringMapDelegate.get()); - WEATHERING.forEach((original, weathered) -> { + ErrorHandlingBiConsumer, Supplier> consumer = new ErrorHandlingBiConsumer<>((original, weathered) -> { builder.put(original.get(), weathered.get()); }); + WEATHERING.forEach(consumer); + consumer.reportExceptions(Create.LOGGER, "weathering"); return builder.build(); }; // Replace the memoized supplier's delegate, since interface fields cannot be reassigned @@ -67,11 +73,51 @@ public class CopperRegistries { waxableMemoized = true; ImmutableBiMap.Builder builder = ImmutableBiMap.builder(); builder.putAll(originalWaxableMapSupplier.get()); - WAXABLE.forEach((original, waxed) -> { + ErrorHandlingBiConsumer, Supplier> consumer = new ErrorHandlingBiConsumer<>((original, waxed) -> { builder.put(original.get(), waxed.get()); }); + WAXABLE.forEach(consumer); + consumer.reportExceptions(Create.LOGGER, "waxable"); return builder.build(); }); HoneycombItem.WAXABLES = waxableMapSupplier; } + + // Create itself only ever adds BlockEntry objects to these registries, which throw if they are not populated with their + // Block object. Normally this shouldn't happen as the weathering/waxable maps shouldn't be accessed before block + // registration is complete, but internal Forge code or other mods may cause this to happen. It is better to catch the + // exception rather than letting it crash the game. + private static class ErrorHandlingBiConsumer implements BiConsumer { + private final BiConsumer delegate; + private int exceptionCount = 0; + @Nullable + private Throwable firstException; + + public ErrorHandlingBiConsumer(BiConsumer delegate) { + this.delegate = delegate; + } + + @Override + public void accept(T t, U u) { + try { + delegate.accept(t, u); + } catch (Throwable throwable) { + exceptionCount++; + + if (firstException == null) { + firstException = throwable; + } + } + } + + public void reportExceptions(Logger logger, String type) { + if (exceptionCount != 0) { + logger.error("Adding " + type + " copper entries from CopperRegistries encountered " + exceptionCount + " exception(s)!"); + + if (firstException != null) { + logger.error("The first exception that was thrown is logged below.", firstException); + } + } + } + } }