Commit 3c957d788ff474d8a80aad15c5c096c01eb2c9e2
1 parent
bd15e763
check for mod transformer injection errors and treat as critical errors
Showing
8 changed files
with
217 additions
and
24 deletions
java/client/com/mumfrey/liteloader/client/ClientEvents.java
| @@ -481,7 +481,7 @@ public class ClientEvents extends Events<Minecraft, IntegratedServer> | @@ -481,7 +481,7 @@ public class ClientEvents extends Events<Minecraft, IntegratedServer> | ||
| 481 | catch (Throwable th) | 481 | catch (Throwable th) |
| 482 | { | 482 | { |
| 483 | this.mods.onLateInitFailed(initMod, th); | 483 | this.mods.onLateInitFailed(initMod, th); |
| 484 | - LiteLoaderLogger.warning(th, "Error initialising mod %s", initMod.getName()); | 484 | + LiteLoaderLogger.warning(th, "Error calling late init for mod %s", initMod.getName()); |
| 485 | } | 485 | } |
| 486 | } | 486 | } |
| 487 | } | 487 | } |
java/client/com/mumfrey/liteloader/client/LiteLoaderPanelManager.java
| @@ -191,6 +191,12 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | @@ -191,6 +191,12 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | ||
| 191 | { | 191 | { |
| 192 | return this.mods.getStartupErrorCount(); | 192 | return this.mods.getStartupErrorCount(); |
| 193 | } | 193 | } |
| 194 | + | ||
| 195 | + @Override | ||
| 196 | + public int getCriticalErrorCount() | ||
| 197 | + { | ||
| 198 | + return this.mods.getCriticalErrorCount(); | ||
| 199 | + } | ||
| 194 | 200 | ||
| 195 | private boolean isPanelSupportedOnScreen(GuiScreen guiScreen) | 201 | private boolean isPanelSupportedOnScreen(GuiScreen guiScreen) |
| 196 | { | 202 | { |
java/client/com/mumfrey/liteloader/client/gui/GuiLiteLoaderPanel.java
| @@ -121,7 +121,7 @@ public class GuiLiteLoaderPanel extends GuiScreen | @@ -121,7 +121,7 @@ public class GuiLiteLoaderPanel extends GuiScreen | ||
| 121 | 121 | ||
| 122 | private boolean mouseOverLogo = false; | 122 | private boolean mouseOverLogo = false; |
| 123 | 123 | ||
| 124 | - private int startupErrorCount = 0; | 124 | + private int startupErrorCount = 0, criticalErrorCount = 0; |
| 125 | 125 | ||
| 126 | /** | 126 | /** |
| 127 | * @param minecraft | 127 | * @param minecraft |
| @@ -144,6 +144,7 @@ public class GuiLiteLoaderPanel extends GuiScreen | @@ -144,6 +144,7 @@ public class GuiLiteLoaderPanel extends GuiScreen | ||
| 144 | this.settingsPanel = new GuiPanelSettings(this, minecraft); | 144 | this.settingsPanel = new GuiPanelSettings(this, minecraft); |
| 145 | 145 | ||
| 146 | this.startupErrorCount = mods.getStartupErrorCount(); | 146 | this.startupErrorCount = mods.getStartupErrorCount(); |
| 147 | + this.criticalErrorCount = mods.getCriticalErrorCount(); | ||
| 147 | } | 148 | } |
| 148 | 149 | ||
| 149 | /** | 150 | /** |
| @@ -465,7 +466,7 @@ public class GuiLiteLoaderPanel extends GuiScreen | @@ -465,7 +466,7 @@ public class GuiLiteLoaderPanel extends GuiScreen | ||
| 465 | 466 | ||
| 466 | private void drawErrorTooltip(int left, int top) | 467 | private void drawErrorTooltip(int left, int top) |
| 467 | { | 468 | { |
| 468 | - GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, I18n.format("gui.error.tooltip", this.startupErrorCount), left, top, this.width, this.height, 0xFF5555, 0xB0330000); | 469 | + GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, I18n.format("gui.error.tooltip", this.startupErrorCount, this.criticalErrorCount), left, top, this.width, this.height, 0xFF5555, 0xB0330000); |
| 469 | } | 470 | } |
| 470 | 471 | ||
| 471 | /* (non-Javadoc) | 472 | /* (non-Javadoc) |
java/common/com/mumfrey/liteloader/core/Events.java
| @@ -99,6 +99,9 @@ public abstract class Events<TClient, TServer extends MinecraftServer> implement | @@ -99,6 +99,9 @@ public abstract class Events<TClient, TServer extends MinecraftServer> implement | ||
| 99 | */ | 99 | */ |
| 100 | protected void onStartupComplete() | 100 | protected void onStartupComplete() |
| 101 | { | 101 | { |
| 102 | + LoadingProgress.setMessage("Checking mods..."); | ||
| 103 | + this.mods.onStartupComplete(); | ||
| 104 | + | ||
| 102 | LoadingProgress.setMessage("Initialising CoreProviders..."); | 105 | LoadingProgress.setMessage("Initialising CoreProviders..."); |
| 103 | this.loader.onStartupComplete(); | 106 | this.loader.onStartupComplete(); |
| 104 | 107 |
java/common/com/mumfrey/liteloader/core/LiteLoaderMods.java
| @@ -7,6 +7,7 @@ import java.util.HashMap; | @@ -7,6 +7,7 @@ import java.util.HashMap; | ||
| 7 | import java.util.LinkedList; | 7 | import java.util.LinkedList; |
| 8 | import java.util.List; | 8 | import java.util.List; |
| 9 | import java.util.Map; | 9 | import java.util.Map; |
| 10 | +import java.util.Set; | ||
| 10 | 11 | ||
| 11 | import javax.activity.InvalidActivityException; | 12 | import javax.activity.InvalidActivityException; |
| 12 | 13 | ||
| @@ -18,6 +19,9 @@ import com.mumfrey.liteloader.common.LoadingProgress; | @@ -18,6 +19,9 @@ import com.mumfrey.liteloader.common.LoadingProgress; | ||
| 18 | import com.mumfrey.liteloader.interfaces.LoaderEnumerator; | 19 | import com.mumfrey.liteloader.interfaces.LoaderEnumerator; |
| 19 | import com.mumfrey.liteloader.interfaces.Loadable; | 20 | import com.mumfrey.liteloader.interfaces.Loadable; |
| 20 | import com.mumfrey.liteloader.interfaces.LoadableMod; | 21 | import com.mumfrey.liteloader.interfaces.LoadableMod; |
| 22 | +import com.mumfrey.liteloader.interfaces.TweakContainer; | ||
| 23 | +import com.mumfrey.liteloader.launch.ClassTransformerManager; | ||
| 24 | +import com.mumfrey.liteloader.launch.LiteLoaderTweaker; | ||
| 21 | import com.mumfrey.liteloader.launch.LoaderEnvironment; | 25 | import com.mumfrey.liteloader.launch.LoaderEnvironment; |
| 22 | import com.mumfrey.liteloader.launch.LoaderProperties; | 26 | import com.mumfrey.liteloader.launch.LoaderProperties; |
| 23 | import com.mumfrey.liteloader.modconfig.ConfigManager; | 27 | import com.mumfrey.liteloader.modconfig.ConfigManager; |
| @@ -88,7 +92,7 @@ public class LiteLoaderMods | @@ -88,7 +92,7 @@ public class LiteLoaderMods | ||
| 88 | */ | 92 | */ |
| 89 | protected final LinkedList<NonMod> disabledMods = new LinkedList<NonMod>(); | 93 | protected final LinkedList<NonMod> disabledMods = new LinkedList<NonMod>(); |
| 90 | 94 | ||
| 91 | - private int startupErrorCount; | 95 | + private int startupErrorCount, criticalErrorCount; |
| 92 | 96 | ||
| 93 | LiteLoaderMods(LiteLoader loader, LoaderEnvironment environment, LoaderProperties properties, ConfigManager configManager) | 97 | LiteLoaderMods(LiteLoader loader, LoaderEnvironment environment, LoaderProperties properties, ConfigManager configManager) |
| 94 | { | 98 | { |
| @@ -162,6 +166,11 @@ public class LiteLoaderMods | @@ -162,6 +166,11 @@ public class LiteLoaderMods | ||
| 162 | return this.startupErrorCount; | 166 | return this.startupErrorCount; |
| 163 | } | 167 | } |
| 164 | 168 | ||
| 169 | + public int getCriticalErrorCount() | ||
| 170 | + { | ||
| 171 | + return this.criticalErrorCount; | ||
| 172 | + } | ||
| 173 | + | ||
| 165 | public ModInfo<?> getModInfo(LiteMod instance) | 174 | public ModInfo<?> getModInfo(LiteMod instance) |
| 166 | { | 175 | { |
| 167 | for (Mod mod : this.allMods) | 176 | for (Mod mod : this.allMods) |
| @@ -670,6 +679,47 @@ public class LiteLoaderMods | @@ -670,6 +679,47 @@ public class LiteLoaderMods | ||
| 670 | return String.format("version.%s", modName.toLowerCase().replaceAll("[^a-z0-9_\\-\\.]", "")); | 679 | return String.format("version.%s", modName.toLowerCase().replaceAll("[^a-z0-9_\\-\\.]", "")); |
| 671 | } | 680 | } |
| 672 | 681 | ||
| 682 | + void onStartupComplete() | ||
| 683 | + { | ||
| 684 | + this.validateModTransformers(); | ||
| 685 | + } | ||
| 686 | + | ||
| 687 | + /** | ||
| 688 | + * Check that all specified mod transformers were injected successfully, tag mods with failed transformers | ||
| 689 | + * as critically errored | ||
| 690 | + */ | ||
| 691 | + private void validateModTransformers() | ||
| 692 | + { | ||
| 693 | + ClassTransformerManager transformerManager = LiteLoaderTweaker.getTransformerManager(); | ||
| 694 | + Set<String> injectedTransformers = transformerManager.getInjectedTransformers(); | ||
| 695 | + | ||
| 696 | + for (Mod mod : this.loadedMods) | ||
| 697 | + { | ||
| 698 | + if (mod.hasClassTransformers()) | ||
| 699 | + { | ||
| 700 | + List<String> modTransformers = ((TweakContainer<?>)mod.getContainer()).getClassTransformerClassNames(); | ||
| 701 | + for (String modTransformer : modTransformers) | ||
| 702 | + { | ||
| 703 | + if (!injectedTransformers.contains(modTransformer)) | ||
| 704 | + { | ||
| 705 | + List<Throwable> throwables = transformerManager.getTransformerStartupErrors(modTransformer); | ||
| 706 | + if (throwables != null) | ||
| 707 | + { | ||
| 708 | + for (Throwable th : throwables) | ||
| 709 | + { | ||
| 710 | + this.registerModStartupError(mod, th, true); | ||
| 711 | + } | ||
| 712 | + } | ||
| 713 | + else | ||
| 714 | + { | ||
| 715 | + this.registerModStartupError(mod, new RuntimeException("Missing class transformer " + modTransformer), true); | ||
| 716 | + } | ||
| 717 | + } | ||
| 718 | + } | ||
| 719 | + } | ||
| 720 | + } | ||
| 721 | + } | ||
| 722 | + | ||
| 673 | /** | 723 | /** |
| 674 | * @param instance | 724 | * @param instance |
| 675 | * @param th | 725 | * @param th |
| @@ -685,7 +735,33 @@ public class LiteLoaderMods | @@ -685,7 +735,33 @@ public class LiteLoaderMods | ||
| 685 | 735 | ||
| 686 | private void registerModStartupError(ModInfo<?> mod, Throwable th) | 736 | private void registerModStartupError(ModInfo<?> mod, Throwable th) |
| 687 | { | 737 | { |
| 738 | + // This is a critical error if a mod has already injected a transformer, since it may have injected | ||
| 739 | + // callbacks which it is not in a position to handle! | ||
| 740 | + boolean critical = this.hasModInjectedTransformers(mod); | ||
| 741 | + | ||
| 742 | + this.registerModStartupError(mod, th, critical); | ||
| 743 | + } | ||
| 744 | + | ||
| 745 | + private boolean hasModInjectedTransformers(ModInfo<?> mod) | ||
| 746 | + { | ||
| 747 | + if (!mod.hasClassTransformers()) return false; | ||
| 748 | + | ||
| 749 | + Set<String> injectedTransformers = LiteLoaderTweaker.getTransformerManager().getInjectedTransformers(); | ||
| 750 | + List<String> modTransformers = ((TweakContainer<?>)mod.getContainer()).getClassTransformerClassNames(); | ||
| 751 | + | ||
| 752 | + for (String modTransformer : modTransformers) | ||
| 753 | + { | ||
| 754 | + if (injectedTransformers.contains(modTransformer)) | ||
| 755 | + return true; | ||
| 756 | + } | ||
| 757 | + | ||
| 758 | + return false; | ||
| 759 | + } | ||
| 760 | + | ||
| 761 | + private void registerModStartupError(ModInfo<?> mod, Throwable th, boolean critical) | ||
| 762 | + { | ||
| 688 | this.startupErrorCount++; | 763 | this.startupErrorCount++; |
| 764 | + if (critical) this.criticalErrorCount++; | ||
| 689 | mod.registerStartupError(th); | 765 | mod.registerStartupError(th); |
| 690 | } | 766 | } |
| 691 | 767 |
java/common/com/mumfrey/liteloader/interfaces/PanelManager.java
| @@ -54,4 +54,9 @@ public interface PanelManager<TParentScreen> extends TickObserver, PostRenderObs | @@ -54,4 +54,9 @@ public interface PanelManager<TParentScreen> extends TickObserver, PostRenderObs | ||
| 54 | * @return | 54 | * @return |
| 55 | */ | 55 | */ |
| 56 | public abstract int getStartupErrorCount(); | 56 | public abstract int getStartupErrorCount(); |
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * @return | ||
| 60 | + */ | ||
| 61 | + public abstract int getCriticalErrorCount(); | ||
| 57 | } | 62 | } |
java/common/com/mumfrey/liteloader/launch/ClassTransformerManager.java
| 1 | package com.mumfrey.liteloader.launch; | 1 | package com.mumfrey.liteloader.launch; |
| 2 | 2 | ||
| 3 | -import java.util.Arrays; | ||
| 4 | -import java.util.Collection; | ||
| 5 | -import java.util.HashMap; | ||
| 6 | -import java.util.HashSet; | ||
| 7 | -import java.util.Iterator; | ||
| 8 | -import java.util.List; | ||
| 9 | -import java.util.Map; | ||
| 10 | -import java.util.Set; | ||
| 11 | -import java.util.TreeSet; | 3 | +import java.lang.reflect.Field; |
| 4 | +import java.util.*; | ||
| 12 | import java.util.Map.Entry; | 5 | import java.util.Map.Entry; |
| 13 | 6 | ||
| 7 | +import org.apache.logging.log4j.Logger; | ||
| 8 | +import org.apache.logging.log4j.core.LogEvent; | ||
| 9 | +import org.apache.logging.log4j.core.appender.AbstractAppender; | ||
| 10 | + | ||
| 14 | import net.minecraft.launchwrapper.IClassTransformer; | 11 | import net.minecraft.launchwrapper.IClassTransformer; |
| 15 | import net.minecraft.launchwrapper.LaunchClassLoader; | 12 | import net.minecraft.launchwrapper.LaunchClassLoader; |
| 13 | +import net.minecraft.launchwrapper.LogWrapper; | ||
| 16 | 14 | ||
| 17 | import com.mumfrey.liteloader.transformers.PacketTransformer; | 15 | import com.mumfrey.liteloader.transformers.PacketTransformer; |
| 18 | import com.mumfrey.liteloader.util.SortableValue; | 16 | import com.mumfrey.liteloader.util.SortableValue; |
| @@ -33,7 +31,7 @@ public class ClassTransformerManager | @@ -33,7 +31,7 @@ public class ClassTransformerManager | ||
| 33 | /** | 31 | /** |
| 34 | * Transformers to inject | 32 | * Transformers to inject |
| 35 | */ | 33 | */ |
| 36 | - private Set<String> injectedTransformers = new HashSet<String>(); | 34 | + private Set<String> pendingTransformers = new HashSet<String>(); |
| 37 | 35 | ||
| 38 | /** | 36 | /** |
| 39 | * Transformers to inject after preInit but before the game starts, necessary for anything that needs to be downstream of forge | 37 | * Transformers to inject after preInit but before the game starts, necessary for anything that needs to be downstream of forge |
| @@ -51,11 +49,60 @@ public class ClassTransformerManager | @@ -51,11 +49,60 @@ public class ClassTransformerManager | ||
| 51 | private final List<String> requiredTransformers; | 49 | private final List<String> requiredTransformers; |
| 52 | 50 | ||
| 53 | /** | 51 | /** |
| 52 | + * Transformers successfully injected by us | ||
| 53 | + */ | ||
| 54 | + private final Set<String> injectedTransformers = new HashSet<String>(); | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Catalogue of transformer startup failures | ||
| 58 | + */ | ||
| 59 | + private final Map<String, List<Throwable>> transformerStartupErrors = new HashMap<String, List<Throwable>>(); | ||
| 60 | + | ||
| 61 | + private Logger attachedLog; | ||
| 62 | + | ||
| 63 | + private String pendingTransformer; | ||
| 64 | + | ||
| 65 | + class ThrowableObserver extends AbstractAppender | ||
| 66 | + { | ||
| 67 | + public ThrowableObserver() | ||
| 68 | + { | ||
| 69 | + super("Throwable Observer", null, null); | ||
| 70 | + this.start(); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Override | ||
| 74 | + public void append(LogEvent event) | ||
| 75 | + { | ||
| 76 | + ClassTransformerManager.this.observeThrowable(event.getThrown()); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + /** | ||
| 54 | * @param requiredTransformers | 81 | * @param requiredTransformers |
| 55 | */ | 82 | */ |
| 56 | public ClassTransformerManager(List<String> requiredTransformers) | 83 | public ClassTransformerManager(List<String> requiredTransformers) |
| 57 | { | 84 | { |
| 58 | this.requiredTransformers = requiredTransformers; | 85 | this.requiredTransformers = requiredTransformers; |
| 86 | + | ||
| 87 | + this.appendObserver(); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + private void appendObserver() | ||
| 91 | + { | ||
| 92 | + try | ||
| 93 | + { | ||
| 94 | + Field fLogger = LogWrapper.class.getDeclaredField("myLog"); | ||
| 95 | + fLogger.setAccessible(true); | ||
| 96 | + this.attachedLog = (Logger)fLogger.get(LogWrapper.log); | ||
| 97 | + if (this.attachedLog instanceof org.apache.logging.log4j.core.Logger) | ||
| 98 | + { | ||
| 99 | + ((org.apache.logging.log4j.core.Logger)this.attachedLog).addAppender(new ThrowableObserver()); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + catch (Exception ex) | ||
| 103 | + { | ||
| 104 | + LiteLoaderLogger.warning("Failed to append ThrowableObserver to LogWrapper, transformer startup exceptions may not be logged"); | ||
| 105 | + } | ||
| 59 | } | 106 | } |
| 60 | 107 | ||
| 61 | /** | 108 | /** |
| @@ -66,7 +113,7 @@ public class ClassTransformerManager | @@ -66,7 +113,7 @@ public class ClassTransformerManager | ||
| 66 | { | 113 | { |
| 67 | if (!this.gameStarted) | 114 | if (!this.gameStarted) |
| 68 | { | 115 | { |
| 69 | - this.injectedTransformers.add(transformerClass); | 116 | + this.pendingTransformers.add(transformerClass); |
| 70 | return true; | 117 | return true; |
| 71 | } | 118 | } |
| 72 | 119 | ||
| @@ -81,7 +128,7 @@ public class ClassTransformerManager | @@ -81,7 +128,7 @@ public class ClassTransformerManager | ||
| 81 | { | 128 | { |
| 82 | if (!this.gameStarted) | 129 | if (!this.gameStarted) |
| 83 | { | 130 | { |
| 84 | - this.injectedTransformers.addAll(transformerClasses); | 131 | + this.pendingTransformers.addAll(transformerClasses); |
| 85 | return true; | 132 | return true; |
| 86 | } | 133 | } |
| 87 | 134 | ||
| @@ -96,7 +143,7 @@ public class ClassTransformerManager | @@ -96,7 +143,7 @@ public class ClassTransformerManager | ||
| 96 | { | 143 | { |
| 97 | if (!this.gameStarted) | 144 | if (!this.gameStarted) |
| 98 | { | 145 | { |
| 99 | - this.injectedTransformers.addAll(Arrays.asList(transformerClasses)); | 146 | + this.pendingTransformers.addAll(Arrays.asList(transformerClasses)); |
| 100 | return true; | 147 | return true; |
| 101 | } | 148 | } |
| 102 | 149 | ||
| @@ -108,12 +155,12 @@ public class ClassTransformerManager | @@ -108,12 +155,12 @@ public class ClassTransformerManager | ||
| 108 | */ | 155 | */ |
| 109 | void injectUpstreamTransformers(LaunchClassLoader classLoader) | 156 | void injectUpstreamTransformers(LaunchClassLoader classLoader) |
| 110 | { | 157 | { |
| 111 | - this.sieveAndSortPacketTransformers(classLoader, this.injectedTransformers); | 158 | + this.sieveAndSortPacketTransformers(classLoader, this.pendingTransformers); |
| 112 | 159 | ||
| 113 | for (String requiredTransformerClassName : this.requiredTransformers) | 160 | for (String requiredTransformerClassName : this.requiredTransformers) |
| 114 | { | 161 | { |
| 115 | LiteLoaderLogger.info("Injecting required class transformer '%s'", requiredTransformerClassName); | 162 | LiteLoaderLogger.info("Injecting required class transformer '%s'", requiredTransformerClassName); |
| 116 | - classLoader.registerTransformer(requiredTransformerClassName); | 163 | + this.injectTransformer(classLoader, requiredTransformerClassName); |
| 117 | } | 164 | } |
| 118 | 165 | ||
| 119 | for (Entry<String, TreeSet<SortableValue<String>>> packetClassTransformers : this.packetTransformers.entrySet()) | 166 | for (Entry<String, TreeSet<SortableValue<String>>> packetClassTransformers : this.packetTransformers.entrySet()) |
| @@ -121,14 +168,15 @@ public class ClassTransformerManager | @@ -121,14 +168,15 @@ public class ClassTransformerManager | ||
| 121 | for (SortableValue<String> transformerInfo : packetClassTransformers.getValue()) | 168 | for (SortableValue<String> transformerInfo : packetClassTransformers.getValue()) |
| 122 | { | 169 | { |
| 123 | String packetClass = packetClassTransformers.getKey(); | 170 | String packetClass = packetClassTransformers.getKey(); |
| 171 | + String transformerClassName = transformerInfo.getValue(); | ||
| 124 | if (packetClass.lastIndexOf('.') != -1) packetClass = packetClass.substring(packetClass.lastIndexOf('.') + 1); | 172 | if (packetClass.lastIndexOf('.') != -1) packetClass = packetClass.substring(packetClass.lastIndexOf('.') + 1); |
| 125 | - LiteLoaderLogger.info("Injecting packet class transformer '%s' for packet class '%s' with priority %d", transformerInfo.getValue(), packetClass, transformerInfo.getPriority()); | ||
| 126 | - classLoader.registerTransformer(transformerInfo.getValue()); | 173 | + LiteLoaderLogger.info("Injecting packet class transformer '%s' for packet class '%s' with priority %d", transformerClassName, packetClass, transformerInfo.getPriority()); |
| 174 | + this.injectTransformer(classLoader, transformerClassName); | ||
| 127 | } | 175 | } |
| 128 | } | 176 | } |
| 129 | 177 | ||
| 130 | // inject any transformers received after this point directly into the downstreamTransformers set | 178 | // inject any transformers received after this point directly into the downstreamTransformers set |
| 131 | - this.injectedTransformers = this.downstreamTransformers; | 179 | + this.pendingTransformers = this.downstreamTransformers; |
| 132 | } | 180 | } |
| 133 | 181 | ||
| 134 | /** | 182 | /** |
| @@ -142,7 +190,7 @@ public class ClassTransformerManager | @@ -142,7 +190,7 @@ public class ClassTransformerManager | ||
| 142 | for (String transformerClassName : this.downstreamTransformers) | 190 | for (String transformerClassName : this.downstreamTransformers) |
| 143 | { | 191 | { |
| 144 | LiteLoaderLogger.info("Injecting additional class transformer class '%s'", transformerClassName); | 192 | LiteLoaderLogger.info("Injecting additional class transformer class '%s'", transformerClassName); |
| 145 | - classLoader.registerTransformer(transformerClassName); | 193 | + this.injectTransformer(classLoader, transformerClassName); |
| 146 | } | 194 | } |
| 147 | 195 | ||
| 148 | this.downstreamTransformers.clear(); | 196 | this.downstreamTransformers.clear(); |
| @@ -211,4 +259,58 @@ public class ClassTransformerManager | @@ -211,4 +259,58 @@ public class ClassTransformerManager | ||
| 211 | 259 | ||
| 212 | LiteLoaderLogger.info("Added %d packet transformer classes to the transformer list", registeredTransformers); | 260 | LiteLoaderLogger.info("Added %d packet transformer classes to the transformer list", registeredTransformers); |
| 213 | } | 261 | } |
| 262 | + | ||
| 263 | + private synchronized void injectTransformer(LaunchClassLoader classLoader, String transformerClassName) | ||
| 264 | + { | ||
| 265 | + // Assign pendingTransformer so that logged errors during transformer init can be put in the map | ||
| 266 | + this.pendingTransformer = transformerClassName; | ||
| 267 | + | ||
| 268 | + // Register the transformer | ||
| 269 | + classLoader.registerTransformer(transformerClassName); | ||
| 270 | + | ||
| 271 | + // Unassign pending transformer now init is completed | ||
| 272 | + this.pendingTransformer = null; | ||
| 273 | + | ||
| 274 | + // Check whether the transformer was successfully injected, look for it in the transformer list | ||
| 275 | + if (this.findTransformer(classLoader, transformerClassName) != null) | ||
| 276 | + { | ||
| 277 | + this.injectedTransformers.add(transformerClassName); | ||
| 278 | + } | ||
| 279 | + } | ||
| 280 | + | ||
| 281 | + public void observeThrowable(Throwable th) | ||
| 282 | + { | ||
| 283 | + if (th != null && this.pendingTransformer != null) | ||
| 284 | + { | ||
| 285 | + List<Throwable> transformerErrors = this.transformerStartupErrors.get(this.pendingTransformer); | ||
| 286 | + if (transformerErrors == null) | ||
| 287 | + { | ||
| 288 | + transformerErrors = new ArrayList<Throwable>(); | ||
| 289 | + this.transformerStartupErrors.put(this.pendingTransformer, transformerErrors); | ||
| 290 | + } | ||
| 291 | + transformerErrors.add(th); | ||
| 292 | + } | ||
| 293 | + } | ||
| 294 | + | ||
| 295 | + private IClassTransformer findTransformer(LaunchClassLoader classLoader, String transformerClassName) | ||
| 296 | + { | ||
| 297 | + for (IClassTransformer transformer : classLoader.getTransformers()) | ||
| 298 | + { | ||
| 299 | + if (transformer.getClass().getName().equals(transformerClassName)) | ||
| 300 | + return transformer; | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + return null; | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + public Set<String> getInjectedTransformers() | ||
| 307 | + { | ||
| 308 | + return Collections.unmodifiableSet(this.injectedTransformers); | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + public List<Throwable> getTransformerStartupErrors(String transformerClassName) | ||
| 312 | + { | ||
| 313 | + List<Throwable> errorList = this.transformerStartupErrors.get(transformerClassName); | ||
| 314 | + return errorList != null ? Collections.unmodifiableList(errorList) : null; | ||
| 315 | + } | ||
| 214 | } | 316 | } |
resources/assets/liteloader/lang/en_US.lang
| @@ -70,4 +70,4 @@ gui.log.closedialog=Close | @@ -70,4 +70,4 @@ gui.log.closedialog=Close | ||
| 70 | 70 | ||
| 71 | gui.error.title=Startup errors for %s | 71 | gui.error.title=Startup errors for %s |
| 72 | 72 | ||
| 73 | -gui.error.tooltip=%d mod startup error(s) detected | ||
| 74 | \ No newline at end of file | 73 | \ No newline at end of file |
| 74 | +gui.error.tooltip=%d mod startup error(s) detected (%d critical) | ||
| 75 | \ No newline at end of file | 75 | \ No newline at end of file |