From dc12cda505a9217aefdd1fdc2ecb1935f0b38ade Mon Sep 17 00:00:00 2001 From: mezz Date: Fri, 28 Dec 2018 18:05:05 -0800 Subject: [PATCH] Clean progress bar code and fix TextureMap patch (#5304) --- .../net/minecraft/client/Minecraft.java.patch | 4 +- .../client/audio/SoundHandler.java.patch | 4 +- .../renderer/texture/Stitcher.java.patch | 7 +- .../texture/TextureManager.java.patch | 4 +- .../renderer/texture/TextureMap.java.patch | 188 +++++++++--------- ...SimpleReloadableResourceManager.java.patch | 12 +- .../client/model/ModelLoader.java | 2 - .../net/minecraftforge/fml/SidedProvider.java | 29 ++- .../fml/client/SplashProgress.java | 13 +- .../fml/common/ProgressManager.java | 162 --------------- .../common/progress/IProgressBarTracker.java | 31 +++ .../fml/common/progress/ProgressBar.java | 98 +++++++++ .../progress/StartupProgressBarTracker.java | 129 ++++++++++++ .../progress/StartupProgressManager.java | 63 ++++++ .../minecraftforge/test/TestProgressBar.java | 176 ++++++++++++++++ 15 files changed, 632 insertions(+), 290 deletions(-) delete mode 100644 src/main/java/net/minecraftforge/fml/common/ProgressManager.java create mode 100644 src/main/java/net/minecraftforge/fml/common/progress/IProgressBarTracker.java create mode 100644 src/main/java/net/minecraftforge/fml/common/progress/ProgressBar.java create mode 100644 src/main/java/net/minecraftforge/fml/common/progress/StartupProgressBarTracker.java create mode 100644 src/main/java/net/minecraftforge/fml/common/progress/StartupProgressManager.java create mode 100644 src/test/java/net/minecraftforge/test/TestProgressBar.java diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 028fa9f59..b46499a6a 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -24,7 +24,7 @@ this.field_110451_am.func_199006_a(new GrassColorReloadListener()); this.field_110451_am.func_199006_a(new FoliageColorReloadListener()); -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar bar = net.minecraftforge.fml.common.ProgressManager.push("Rendering Setup", 5, true); ++ try (net.minecraftforge.fml.common.progress.ProgressBar bar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Rendering Setup", 5, true)) { + bar.step("GL Setup"); this.field_195558_d.func_198076_a("Startup"); GlStateManager.func_179098_w(); @@ -60,7 +60,7 @@ this.field_71452_i = new ParticleManager(this.field_71441_e, this.field_71446_o); - this.field_71456_v = new GuiIngame(this); + //net.minecraftforge.fml.client.SplashProgress.resume(); -+ net.minecraftforge.fml.common.ProgressManager.pop(bar); ++ }; // Forge: end progress bar + net.minecraftforge.fml.client.ClientModLoader.end(); + this.field_71456_v = new net.minecraftforge.client.GuiIngameForge(this); if (this.field_71475_ae != null) { diff --git a/patches/minecraft/net/minecraft/client/audio/SoundHandler.java.patch b/patches/minecraft/net/minecraft/client/audio/SoundHandler.java.patch index 73d109a01..f510d1d9d 100644 --- a/patches/minecraft/net/minecraft/client/audio/SoundHandler.java.patch +++ b/patches/minecraft/net/minecraft/client/audio/SoundHandler.java.patch @@ -21,7 +21,7 @@ } } -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar resourcesBar = net.minecraftforge.fml.common.ProgressManager.push("Loading sounds", resources.size()); ++ try (net.minecraftforge.fml.common.progress.ProgressBar resourcesBar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Loading sounds", resources.size())) { + resources.forEach(entry -> { + resourcesBar.step(entry.func_76341_a().toString()); + try { @@ -30,7 +30,7 @@ + field_147698_b.warn("Invalid sounds.json", e); + } + }); -+ net.minecraftforge.fml.common.ProgressManager.pop(resourcesBar); ++ }; // Forge: end progress bar + for(ResourceLocation resourcelocation : this.field_147697_e.func_148742_b()) { SoundEventAccessor soundeventaccessor = (SoundEventAccessor)this.field_147697_e.func_82594_a(resourcelocation); diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/Stitcher.java.patch b/patches/minecraft/net/minecraft/client/renderer/texture/Stitcher.java.patch index 18582389d..ad125b48a 100644 --- a/patches/minecraft/net/minecraft/client/renderer/texture/Stitcher.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/texture/Stitcher.java.patch @@ -13,9 +13,8 @@ public void func_94305_f() { Stitcher.Holder[] astitcher$holder = (Stitcher.Holder[])this.field_94319_a.toArray(new Stitcher.Holder[this.field_94319_a.size()]); Arrays.sort((Object[])astitcher$holder); -- -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar bar = net.minecraftforge.fml.common.ProgressManager.push("Texture stitching", astitcher$holder.length); -+ ++ try(net.minecraftforge.fml.common.progress.ProgressBar bar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Texture stitching", astitcher$holder.length)) { + for(Stitcher.Holder stitcher$holder : astitcher$holder) { + bar.step(stitcher$holder.func_98150_a().func_195668_m().toString()); if (!this.func_94310_b(stitcher$holder)) { @@ -29,7 +28,7 @@ this.field_94318_c = MathHelper.func_151236_b(this.field_94318_c); this.field_94315_d = MathHelper.func_151236_b(this.field_94315_d); -+ net.minecraftforge.fml.common.ProgressManager.pop(bar); ++ }; // Forge: end progress bar } public List func_94309_g() { diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureManager.java.patch b/patches/minecraft/net/minecraft/client/renderer/texture/TextureManager.java.patch index ac4f3e791..e3a50ee0d 100644 --- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureManager.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureManager.java.patch @@ -12,7 +12,7 @@ public void func_195410_a(IResourceManager p_195410_1_) { MissingTextureSprite.func_195676_d(); -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar bar = net.minecraftforge.fml.common.ProgressManager.push("Reloading Texture Manager", this.field_110585_a.entrySet().size(), true); ++ try (net.minecraftforge.fml.common.progress.ProgressBar bar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Reloading Texture Manager", this.field_110585_a.entrySet().size(), true)) { Iterator> iterator = this.field_110585_a.entrySet().iterator(); while(iterator.hasNext()) { @@ -26,7 +26,7 @@ this.func_110579_a(entry.getKey(), itextureobject); } } -+ net.minecraftforge.fml.common.ProgressManager.pop(bar); ++ }; // Forge: end progress bar + } + @Override diff --git a/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch b/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch index acc0a5db6..978a10a73 100644 --- a/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/texture/TextureMap.java.patch @@ -8,113 +8,40 @@ p_195426_2_.forEach((p_195423_2_) -> { this.func_199362_a(p_195426_1_, p_195423_2_); }); -@@ -56,37 +57,76 @@ - this.func_195419_g(); +@@ -57,8 +58,14 @@ int j = Integer.MAX_VALUE; int k = 1 << this.field_147636_j; -- + - for(ResourceLocation resourcelocation : this.field_195427_i) { + field_147635_d.info("Max texture size: {}", i); -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar bar = net.minecraftforge.fml.common.ProgressManager.push("Texture stitching", this.field_195427_i.size()); ++ try (net.minecraftforge.fml.common.progress.ProgressBar textureLoadingBar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Texture loading", this.field_195427_i.size())) { + loadedSprites.clear(); -+ + for(ResourceLocation resourcelocation : Sets.newHashSet(this.field_195427_i)) { -+ ResourceLocation resourcelocation1 = this.func_195420_b(resourcelocation); -+ bar.step(resourcelocation1.toString()); ++ textureLoadingBar.step(this.func_195420_b(resourcelocation).toString()); if (!this.field_94249_f.func_195668_m().equals(resourcelocation)) { -- ResourceLocation resourcelocation1 = this.func_195420_b(resourcelocation); -+ j = loadTexture(stitcher, p_195421_1_, resourcelocation, bar, j, k); -+ } -+ } -+ finishLoading(stitcher, p_195421_1_, bar, j, k); -+ } -+ -+ private int loadTexture(Stitcher stitcher, IResourceManager manager, ResourceLocation resourcelocation, net.minecraftforge.fml.common.ProgressManager.ProgressBar bar, int j, int k) { -+ if (loadedSprites.contains(resourcelocation)) { -+ return j; -+ } -+ TextureAtlasSprite textureatlassprite; -+ ResourceLocation resourcelocation1 = this.func_195420_b(resourcelocation); -+ for(ResourceLocation loading : loadingSprites) { -+ if(resourcelocation1.equals(loading)) { -+ final String error = "circular model dependencies, stack: [" + com.google.common.base.Joiner.on(", ").join(loadingSprites) + "]"; -+ net.minecraftforge.fml.client.ClientHooks.trackBrokenTexture(resourcelocation, error); -+ } -+ } -+ loadingSprites.addLast(resourcelocation1); -+ try (IResource iresource = manager.func_199002_a(resourcelocation1)) { -+ PngSizeInfo pngsizeinfo = new PngSizeInfo(iresource); -+ AnimationMetadataSection animationmetadatasection = (AnimationMetadataSection)iresource.func_199028_a(AnimationMetadataSection.field_195817_a); -+ textureatlassprite = new TextureAtlasSprite(resourcelocation, pngsizeinfo, animationmetadatasection); ++ j = loadTexture(stitcher, p_195421_1_, resourcelocation, j, k); ++ if (true) continue; // Forge: skip the rest of this if statement, we're using loadTexture instead + ResourceLocation resourcelocation1 = this.func_195420_b(resourcelocation); -- TextureAtlasSprite textureatlassprite; -- try (IResource iresource = p_195421_1_.func_199002_a(resourcelocation1)) { -- PngSizeInfo pngsizeinfo = new PngSizeInfo(iresource); -- AnimationMetadataSection animationmetadatasection = (AnimationMetadataSection)iresource.func_199028_a(AnimationMetadataSection.field_195817_a); -- textureatlassprite = new TextureAtlasSprite(resourcelocation, pngsizeinfo, animationmetadatasection); -- } catch (RuntimeException runtimeexception) { -- field_147635_d.error("Unable to parse metadata from {} : {}", resourcelocation1, runtimeexception); -- continue; -- } catch (IOException ioexception) { -- field_147635_d.error("Using missing texture, unable to load {} : {}", resourcelocation1, ioexception); -- continue; -+ for (ResourceLocation dependency : textureatlassprite.getDependencies()) { -+ if (!field_195427_i.contains(dependency.toString())) { -+ func_199362_a(manager, dependency); - } -- -- j = Math.min(j, Math.min(textureatlassprite.func_94211_a(), textureatlassprite.func_94216_b())); -- int j1 = Math.min(Integer.lowestOneBit(textureatlassprite.func_94211_a()), Integer.lowestOneBit(textureatlassprite.func_94216_b())); -- if (j1 < k) { -- field_147635_d.warn("Texture {} with size {}x{} limits mip level from {} to {}", resourcelocation1, textureatlassprite.func_94211_a(), textureatlassprite.func_94216_b(), MathHelper.func_151239_c(k), MathHelper.func_151239_c(j1)); -- k = j1; -+ j = loadTexture(stitcher, manager, dependency, bar, j, k); -+ } -+ if (textureatlassprite.hasCustomLoader(manager, resourcelocation)) { -+ if (textureatlassprite.load(manager, resourcelocation, l -> field_94252_e.get(l.toString()))) { -+ return j; - } -- -- stitcher.func_110934_a(textureatlassprite); + TextureAtlasSprite textureatlassprite; +@@ -84,9 +91,11 @@ + stitcher.func_110934_a(textureatlassprite); } -+ j = Math.min(j, Math.min(textureatlassprite.func_94211_a(), textureatlassprite.func_94216_b())); -+ int j1 = Math.min(Integer.lowestOneBit(textureatlassprite.func_94211_a()), Integer.lowestOneBit(textureatlassprite.func_94216_b())); -+ if (j1 < k) { -+ // FORGE: do not lower the mipmap level, just log the problematic textures -+ field_147635_d.warn("Texture {} with size {}x{} will have visual artifacts at mip level {}, it can only support level {}. Please report to the mod author that the texture should be some multiple of 16x16.", resourcelocation1, textureatlassprite.func_94211_a(), textureatlassprite.func_94216_b(), MathHelper.func_151239_c(k), MathHelper.func_151239_c(j1)); -+ } -+ if (func_195422_a(manager, textureatlassprite)) -+ stitcher.func_110934_a(textureatlassprite); -+ return j; -+ } catch (RuntimeException runtimeexception) { -+ net.minecraftforge.fml.client.ClientHooks.trackBrokenTexture(resourcelocation, runtimeexception.getMessage()); -+ return j; -+ } catch (IOException ioexception) { -+ net.minecraftforge.fml.client.ClientHooks.trackMissingTexture(resourcelocation); -+ return j; -+ } finally { -+ loadingSprites.removeLast(); -+ field_195427_i.add(resourcelocation1); } -- -+ } -+ -+ private void finishLoading(Stitcher stitcher, IResourceManager manager, net.minecraftforge.fml.common.ProgressManager.ProgressBar bar, int j, int k) -+ { -+ net.minecraftforge.fml.common.ProgressManager.pop(bar); ++ } // Forge: end progress bar + int l = Math.min(j, k); int i1 = MathHelper.func_151239_c(l); + if (false) // FORGE: do not lower the mipmap level if (i1 < this.field_147636_j) { field_147635_d.warn("{}: dropping miplevel from {} to {}, because of minimum power of two: {}", this.field_94254_c, this.field_147636_j, i1, l); this.field_147636_j = i1; -@@ -94,18 +134,26 @@ +@@ -94,18 +103,25 @@ this.field_94249_f.func_147963_d(this.field_147636_j); stitcher.func_110934_a(this.field_94249_f); -- -+ bar = net.minecraftforge.fml.common.ProgressManager.push("Texture creation", 2); -+ ++ try (net.minecraftforge.fml.common.progress.ProgressBar bar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Texture creation", 2)) { + try { + bar.step("Stitching"); stitcher.func_94305_f(); @@ -125,28 +52,27 @@ field_147635_d.info("Created: {}x{} {}-atlas", stitcher.func_110935_a(), stitcher.func_110936_b(), this.field_94254_c); + bar.step("Allocating GL texture"); TextureUtil.func_180600_a(this.func_110552_b(), this.field_147636_j, stitcher.func_110935_a(), stitcher.func_110936_b()); -+ -+ net.minecraftforge.fml.common.ProgressManager.pop(bar); -+ bar = net.minecraftforge.fml.common.ProgressManager.push("Texture mipmap and upload", stitcher.func_94309_g().size()); ++ }; // Forge: end progress bar ++ try (net.minecraftforge.fml.common.progress.ProgressBar bar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Texture mipmap and upload", stitcher.func_94309_g().size())) { for(TextureAtlasSprite textureatlassprite1 : stitcher.func_94309_g()) { - if (textureatlassprite1 == this.field_94249_f || this.func_195422_a(p_195421_1_, textureatlassprite1)) { + bar.step(textureatlassprite1.func_195668_m().toString()); + // FORGE: Sprite loading is now done during stitching, short-circuit this check -+ if (true || textureatlassprite1 == this.field_94249_f || this.func_195422_a(manager, textureatlassprite1)) { ++ if (true || textureatlassprite1 == this.field_94249_f || this.func_195422_a(p_195421_1_, textureatlassprite1)) { this.field_94252_e.put(textureatlassprite1.func_195668_m(), textureatlassprite1); try { -@@ -124,6 +172,8 @@ +@@ -124,6 +140,8 @@ } } + net.minecraftforge.client.ForgeHooksClient.onTextureStitchedPost(this); -+ net.minecraftforge.fml.common.ProgressManager.pop(bar); ++ }; // Forge: end progress bar } private boolean func_195422_a(IResourceManager p_195422_1_, TextureAtlasSprite p_195422_2_) { -@@ -132,6 +182,7 @@ +@@ -132,6 +150,7 @@ label62: { boolean flag; @@ -154,7 +80,7 @@ try { iresource = p_195422_1_.func_199002_a(resourcelocation); p_195422_2_.func_195664_a(iresource, this.field_147636_j + 1); -@@ -216,4 +267,21 @@ +@@ -216,4 +235,91 @@ this.field_94252_e.clear(); this.field_94258_i.clear(); } @@ -174,5 +100,75 @@ + public int getMipmapLevels() + { + return field_147636_j; ++ } ++ ++ private int loadTexture(Stitcher stitcher, IResourceManager manager, ResourceLocation resourcelocation, int j, int k) ++ { ++ if (loadedSprites.contains(resourcelocation)) ++ { ++ return j; ++ } ++ TextureAtlasSprite textureatlassprite; ++ ResourceLocation resourcelocation1 = this.func_195420_b(resourcelocation); ++ for (ResourceLocation loading : loadingSprites) ++ { ++ if (resourcelocation1.equals(loading)) ++ { ++ final String error = "circular model dependencies, stack: [" + com.google.common.base.Joiner.on(", ").join(loadingSprites) + "]"; ++ net.minecraftforge.fml.client.ClientHooks.trackBrokenTexture(resourcelocation, error); ++ } ++ } ++ loadingSprites.addLast(resourcelocation1); ++ try (IResource iresource = manager.func_199002_a(resourcelocation1)) ++ { ++ PngSizeInfo pngsizeinfo = new PngSizeInfo(iresource); ++ AnimationMetadataSection animationmetadatasection = iresource.func_199028_a(AnimationMetadataSection.field_195817_a); ++ textureatlassprite = new TextureAtlasSprite(resourcelocation, pngsizeinfo, animationmetadatasection); ++ ++ for (ResourceLocation dependency : textureatlassprite.getDependencies()) ++ { ++ if (!field_195427_i.contains(dependency)) ++ { ++ func_199362_a(manager, dependency); ++ } ++ j = loadTexture(stitcher, manager, dependency, j, k); ++ } ++ if (textureatlassprite.hasCustomLoader(manager, resourcelocation)) ++ { ++ if (textureatlassprite.load(manager, resourcelocation, field_94252_e::get)) ++ { ++ return j; ++ } ++ } ++ j = Math.min(j, Math.min(textureatlassprite.func_94211_a(), textureatlassprite.func_94216_b())); ++ int j1 = Math.min(Integer.lowestOneBit(textureatlassprite.func_94211_a()), Integer.lowestOneBit(textureatlassprite.func_94216_b())); ++ if (j1 < k) ++ { ++ // FORGE: do not lower the mipmap level, just log the problematic textures ++ field_147635_d.warn("Texture {} with size {}x{} will have visual artifacts at mip level {}, it can only support level {}." + ++ "Please report to the mod author that the texture should be some multiple of 16x16.", ++ resourcelocation1, textureatlassprite.func_94211_a(), textureatlassprite.func_94216_b(), MathHelper.func_151239_c(k), MathHelper.func_151239_c(j1)); ++ } ++ if (func_195422_a(manager, textureatlassprite)) ++ { ++ stitcher.func_110934_a(textureatlassprite); ++ } ++ return j; ++ } ++ catch (RuntimeException runtimeexception) ++ { ++ net.minecraftforge.fml.client.ClientHooks.trackBrokenTexture(resourcelocation, runtimeexception.getMessage()); ++ return j; ++ } ++ catch (IOException ioexception) ++ { ++ net.minecraftforge.fml.client.ClientHooks.trackMissingTexture(resourcelocation); ++ return j; ++ } ++ finally ++ { ++ loadingSprites.removeLast(); ++ field_195427_i.add(resourcelocation1); ++ } + } } diff --git a/patches/minecraft/net/minecraft/resources/SimpleReloadableResourceManager.java.patch b/patches/minecraft/net/minecraft/resources/SimpleReloadableResourceManager.java.patch index e64edafe4..0910c722e 100644 --- a/patches/minecraft/net/minecraft/resources/SimpleReloadableResourceManager.java.patch +++ b/patches/minecraft/net/minecraft/resources/SimpleReloadableResourceManager.java.patch @@ -12,7 +12,7 @@ } public void func_199005_a(List p_199005_1_) { -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar resReload = net.minecraftforge.fml.common.ProgressManager.push("Loading Resources", p_199005_1_.size() + 1, true); ++ try (net.minecraftforge.fml.common.progress.ProgressBar resReload = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Loading Resources", p_199005_1_.size() + 1, true)) { this.func_199008_b(); field_199012_a.info("Reloading ResourceManager: {}", p_199005_1_.stream().map(IResourcePack::func_195762_a).collect(Collectors.joining(", "))); @@ -27,12 +27,12 @@ } else { this.func_199010_c(); } -+ net.minecraftforge.fml.common.ProgressManager.pop(resReload); ++ }; // Forge: end progress bar } public void func_199006_a(IResourceManagerReloadListener p_199006_1_) { -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar resReload = net.minecraftforge.fml.common.ProgressManager.push("Loading Resource", 1); ++ try (net.minecraftforge.fml.common.progress.ProgressBar resReload = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Loading Resource", 1)) { + resReload.step(p_199006_1_.getClass()); this.field_199015_d.add(p_199006_1_); if (field_199012_a.isDebugEnabled()) { @@ -40,18 +40,18 @@ } else { p_199006_1_.func_195410_a(this); } -+ net.minecraftforge.fml.common.ProgressManager.pop(resReload); ++ }; // Forge: end progress bar } private void func_199010_c() { -+ net.minecraftforge.fml.common.ProgressManager.ProgressBar resReload = net.minecraftforge.fml.common.ProgressManager.push("Reloading", this.field_199015_d.size()); ++ try (net.minecraftforge.fml.common.progress.ProgressBar resReload = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Reloading", this.field_199015_d.size())) { for(IResourceManagerReloadListener iresourcemanagerreloadlistener : this.field_199015_d) { + resReload.step(iresourcemanagerreloadlistener.getClass()); + if (!net.minecraftforge.resource.SelectiveReloadStateHandler.INSTANCE.test(iresourcemanagerreloadlistener)) continue; // Forge: Selective reloading for vanilla listeners iresourcemanagerreloadlistener.func_195410_a(this); } -+ net.minecraftforge.fml.common.ProgressManager.pop(resReload); ++ }; // Forge: end progress bar } diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoader.java b/src/main/java/net/minecraftforge/client/model/ModelLoader.java index e1b84d971..560d20ef1 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoader.java @@ -89,8 +89,6 @@ import net.minecraftforge.common.property.IExtendedBlockState; import net.minecraftforge.common.property.Properties; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fml.client.ClientModLoader; -import net.minecraftforge.fml.common.ProgressManager; -import net.minecraftforge.fml.common.ProgressManager.ProgressBar; import net.minecraftforge.logging.ModelLoaderErrorMessage; import net.minecraftforge.registries.IRegistryDelegate; diff --git a/src/main/java/net/minecraftforge/fml/SidedProvider.java b/src/main/java/net/minecraftforge/fml/SidedProvider.java index 51953309d..b03ca9395 100644 --- a/src/main/java/net/minecraftforge/fml/SidedProvider.java +++ b/src/main/java/net/minecraftforge/fml/SidedProvider.java @@ -34,13 +34,23 @@ import java.util.function.Supplier; public enum SidedProvider { // All of these need to be careful not to directly dereference the client and server elements in their signatures - DATAFIXER(c->c.get().getDataFixer(), s->s.get().getDataFixer()), - SIDEDINIT((Function, Function>)c-> mc->new FMLClientInitEvent(c, mc), - (Function, Function>)s-> mc->new FMLServerInitEvent(s, mc)), - STRIPCHARS((Function, Function>)c-> ClientHooks::stripSpecialChars, - (Function, Function>)s-> str->str), + DATAFIXER( + c->c.get().getDataFixer(), + s->s.get().getDataFixer(), + ()-> { throw new UnsupportedOperationException(); }), + SIDEDINIT( + (Function, Function>)c-> mc->new FMLClientInitEvent(c, mc), + s-> mc->new FMLServerInitEvent(s, mc), + ()-> { throw new UnsupportedOperationException(); }), + STRIPCHARS( + (Function, Function>)c-> ClientHooks::stripSpecialChars, + s-> str->str, + ()-> str->str), @SuppressWarnings("Convert2MethodRef") // need to not be methodrefs to avoid classloading all of StartupQuery's data (supplier is coming from StartupQuery) - STARTUPQUERY(c->StartupQuery.QueryWrapper.clientQuery(c), s->StartupQuery.QueryWrapper.dedicatedServerQuery(s)); + STARTUPQUERY( + c->StartupQuery.QueryWrapper.clientQuery(c), + s->StartupQuery.QueryWrapper.dedicatedServerQuery(s), + ()-> { throw new UnsupportedOperationException(); }); private static Supplier client; private static Supplier server; @@ -56,12 +66,13 @@ public enum SidedProvider private final Function, ?> clientSide; private final Function, ?> serverSide; + private final Supplier testSide; - - SidedProvider(Function,?> clientSide, Function,?> serverSide) + SidedProvider(Function, T> clientSide, Function, T> serverSide, Supplier testSide) { this.clientSide = clientSide; this.serverSide = serverSide; + this.testSide = testSide; } @SuppressWarnings("unchecked") @@ -73,7 +84,7 @@ public enum SidedProvider return (T)this.serverSide.apply(server); } else { - throw new IllegalArgumentException("THREE SIDES? WUT?"); + return (T)this.testSide.get(); } } } diff --git a/src/main/java/net/minecraftforge/fml/client/SplashProgress.java b/src/main/java/net/minecraftforge/fml/client/SplashProgress.java index 1771af788..1765a8f26 100644 --- a/src/main/java/net/minecraftforge/fml/client/SplashProgress.java +++ b/src/main/java/net/minecraftforge/fml/client/SplashProgress.java @@ -125,8 +125,10 @@ public class SplashProgress private static final int TIMING_FRAME_THRESHOLD = TIMING_FRAME_COUNT * 5 * 1000000; // 5 ms per frame, scaled to nanos private static final Semaphore mutex = new Semaphore(1); + */ - public static Void processMessages() { + public static void processMessages() { + /* // workaround for windows requiring messages being processed on the main thread if (LWJGLUtil.getPlatform() != LWJGLUtil.PLATFORM_WINDOWS) return null; // If we can't grab the mutex, the update call is blocked, probably in native code, just skip it and carry on @@ -134,9 +136,9 @@ public class SplashProgress if (!SplashProgress.mutex.tryAcquire()) return null; Display.processMessages(); SplashProgress.mutex.release(); - return null; + */ } - + /* private static String getString(String name, String def) { String value = config.getProperty(name, def); @@ -448,9 +450,10 @@ public class SplashProgress drawBox(barWidth - 2, barHeight - 2); // slidy part setColor(barColor); - drawBox((barWidth - 2) * (b.getStep() + 1) / (b.getSteps() + 1), barHeight - 2); // Step can sometimes be 0. + int step = b.getStep(); + drawBox((barWidth - 2) * (step + 1) / (b.getTotalSteps() + 1), barHeight - 2); // Step can sometimes be 0. // progress text - String progress = "" + b.getStep() + "/" + b.getSteps(); + String progress = "" + step + "/" + b.getTotalSteps(); glTranslatef(((float)barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0); setColor(fontColor); glScalef(2, 2, 1); diff --git a/src/main/java/net/minecraftforge/fml/common/ProgressManager.java b/src/main/java/net/minecraftforge/fml/common/ProgressManager.java deleted file mode 100644 index b463b1447..000000000 --- a/src/main/java/net/minecraftforge/fml/common/ProgressManager.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Minecraft Forge - * Copyright (c) 2016-2018. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package net.minecraftforge.fml.common; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Function; -import java.util.stream.Collectors; - -import net.minecraftforge.fml.SidedProvider; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.message.MessageFormatMessage; - -import static net.minecraftforge.fml.Logging.SPLASH; - -/** - * Not a fully fleshed out API, may change in future MC versions. - * However feel free to use and suggest additions. - */ -public class ProgressManager -{ - private static final Logger LOGGER = LogManager.getLogger(); - private static final List bars = new CopyOnWriteArrayList(); - - /** - * Not a fully fleshed out API, may change in future MC versions. - * However feel free to use and suggest additions. - */ - public static ProgressBar push(String title, int steps) - { - return push(title, steps, false); - } - /** - * Not a fully fleshed out API, may change in future MC versions. - * However feel free to use and suggest additions. - */ - public static ProgressBar push(String title, int steps, boolean timeEachStep) - { - ProgressBar bar = new ProgressBar(title, steps); - bars.add(bar); - if (timeEachStep) - { - bar.timeEachStep(); - } -// DistExecutor.runWhenOn(Dist.CLIENT, ()->SplashProgress::processMessages); - return bar; - } - - /** - * Not a fully fleshed out API, may change in future MC versions. - * However feel free to use and suggest additions. - */ - public static void pop(ProgressBar bar) - { - if(bar.getSteps() != bar.getStep()) throw new IllegalStateException("can't pop unfinished ProgressBar " + bar.getTitle()); - bars.remove(bar); - if (bar.getSteps() != 0) - { - long newTime = System.nanoTime(); - if (bar.timeEachStep) - LOGGER.debug(SPLASH, () -> new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6)); - if (bar.getSteps() == 1) - LOGGER.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} - {1} took {2,number,0.000}ms", bar.getTitle(), bar.getMessage(), (newTime - bar.lastTime) / 1.0e6)); - else - LOGGER.debug(SPLASH, () -> new MessageFormatMessage("Bar Finished: {0} took {1,number,0.000}ms", bar.getTitle(), (newTime - bar.lastTime) / 1.0e6)); - } -// DistExecutor.runWhenOn(Dist.CLIENT, ()->SplashProgress::processMessages); - } - - /* - * Internal use only. - */ - public static Iterator barIterator() - { - return bars.iterator(); - } - - - /** - * Not a fully fleshed out API, may change in future MC versions. - * However feel free to use and suggest additions. - */ - public static class ProgressBar - { - private final String title; - private final int steps; - private volatile int step = 0; - private volatile String message = ""; - private boolean timeEachStep = false; - private long startTime = System.nanoTime(); - private long lastTime = startTime; - - private ProgressBar(String title, int steps) - { - this.title = title; - this.steps = steps; - } - - public void step(Class classToName, String... extra) - { - step(ClassNameUtils.shortName(classToName)+ String.join(" ", extra)); - } - - public void step(String message) - { - if(step >= steps) throw new IllegalStateException("too much steps for ProgressBar " + title); - if (timeEachStep && step != 0) - { - long newTime = System.nanoTime(); - LOGGER.debug(SPLASH,new MessageFormatMessage("Bar Step: {0} - {1} took {2,number,0.000}ms", getTitle(), getMessage(), (newTime - lastTime) / 1.0e6)); - lastTime = newTime; - } - step += 1; - this.message = SidedProvider.STRIPCHARS.>get().apply(message); - } - - public String getTitle() - { - return title; - } - - public int getSteps() - { - return steps; - } - - public int getStep() - { - return step; - } - - public String getMessage() - { - return message; - } - - public void timeEachStep() - { - this.timeEachStep = true; - } - } -} diff --git a/src/main/java/net/minecraftforge/fml/common/progress/IProgressBarTracker.java b/src/main/java/net/minecraftforge/fml/common/progress/IProgressBarTracker.java new file mode 100644 index 000000000..92156b380 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/progress/IProgressBarTracker.java @@ -0,0 +1,31 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.fml.common.progress; + +public interface IProgressBarTracker +{ + default void onBarCreated(ProgressBar bar) {} + + default void onStepStarted(ProgressBar bar, int step, String message) {} + + default void onStepFinished(ProgressBar bar, int step, String message) {} + + default void onBarFinished(ProgressBar bar, int step, String message) {} +} diff --git a/src/main/java/net/minecraftforge/fml/common/progress/ProgressBar.java b/src/main/java/net/minecraftforge/fml/common/progress/ProgressBar.java new file mode 100644 index 000000000..b5890a060 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/progress/ProgressBar.java @@ -0,0 +1,98 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.fml.common.progress; + +import net.minecraftforge.fml.common.ClassNameUtils; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.function.Function; + +/** + * Not a fully fleshed out API, may change in future MC versions. + * However feel free to use and suggest additions. + */ +public final class ProgressBar implements AutoCloseable +{ + private final String title; + private final int totalSteps; + private final Function stripChars; + private final IProgressBarTracker tracker; + private volatile int step = 0; + private volatile String message = ""; + + public ProgressBar(String title, int totalSteps, Function stripChars, IProgressBarTracker tracker) + { + this.title = title; + this.totalSteps = totalSteps; + this.stripChars = stripChars; + this.tracker = tracker; + this.tracker.onBarCreated(this); + } + + public void step(Class classToName, String... extra) + { + step(ClassNameUtils.shortName(classToName) + String.join(" ", extra)); + } + + public synchronized void step(String newMessage) + { + if (step > 0) + { + tracker.onStepFinished(this, step, message); + } + step++; + message = stripChars.apply(newMessage); + tracker.onStepStarted(this, step, message);; + } + + /** + * Get the current step and message. + */ + public synchronized Pair getStepAndMessage() + { + return Pair.of(step, message); + } + + /** + * Get the total number of steps. + */ + public int getTotalSteps() + { + return totalSteps; + } + + /** + * Get the current title. + */ + public String getTitle() + { + return title; + } + + @Override + public synchronized void close() + { + if (step > 0) + { + tracker.onStepFinished(this, step, message); + } + tracker.onBarFinished(this, step, message); + } +} diff --git a/src/main/java/net/minecraftforge/fml/common/progress/StartupProgressBarTracker.java b/src/main/java/net/minecraftforge/fml/common/progress/StartupProgressBarTracker.java new file mode 100644 index 000000000..27e34c55a --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/progress/StartupProgressBarTracker.java @@ -0,0 +1,129 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.fml.common.progress; + +import com.google.common.base.Stopwatch; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.client.SplashProgress; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.message.MessageFormatMessage; + +import javax.annotation.Nullable; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import static net.minecraftforge.fml.Logging.SPLASH; + +class StartupProgressBarTracker implements IProgressBarTracker +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static final List bars = new CopyOnWriteArrayList<>(); + + private final boolean timeEachStep; + private final int steps; + private final Stopwatch stopwatch; + @Nullable + private Stopwatch stepStopwatch; + private String logPrefix = ""; + + StartupProgressBarTracker(boolean timeEachStep, int steps) + { + this.timeEachStep = timeEachStep; + this.steps = steps; + this.stopwatch = Stopwatch.createUnstarted(); + } + + @Override + public void onBarCreated(ProgressBar bar) + { + int depth = bars.size(); + logPrefix = StringUtils.repeat(" ", depth); + bars.add(bar); + DistExecutor.runWhenOn(Dist.CLIENT, ()-> SplashProgress::processMessages); + } + + @Override + public void onStepStarted(ProgressBar bar, int step, String message) + { + if (step == 1) + { + if (steps > 1) + { + LOGGER.debug(SPLASH, () -> new MessageFormatMessage("{0}Bar Starting: {1}", logPrefix, bar.getTitle())); + if (timeEachStep) + { + stepStopwatch = Stopwatch.createStarted(); + } + } + else + { + LOGGER.debug(SPLASH, () -> new MessageFormatMessage("{0}Bar Starting: {1} - {2}", logPrefix, bar.getTitle(), message)); + } + stopwatch.start(); + } + if (stepStopwatch != null) + { + LOGGER.debug(SPLASH, () -> new MessageFormatMessage("{0} Bar Step: {1} - {2} - starting", logPrefix, bar.getTitle(), message)); + stepStopwatch.reset(); + stepStopwatch.start(); + } + } + + @Override + public void onStepFinished(ProgressBar bar, int step, String message) + { + if (stepStopwatch != null) + { + stepStopwatch.stop(); + LOGGER.debug(SPLASH, () -> new MessageFormatMessage("{0} Bar Step: {1} - {2} - took {3}", logPrefix, bar.getTitle(), message, stepStopwatch)); + } + } + + @Override + public void onBarFinished(ProgressBar bar, int step, String message) + { + if (steps > 0) + { + stopwatch.stop(); + bars.remove(bar); + if (steps > 1) + { + LOGGER.debug(SPLASH, () -> new MessageFormatMessage("{0}Bar Finished: {1} - took {2}", logPrefix, bar.getTitle(), stopwatch)); + } + else + { + LOGGER.debug(SPLASH, () -> new MessageFormatMessage("{0}Bar Finished: {1} - {2} - took {3}", logPrefix, bar.getTitle(), message, stopwatch)); + } + DistExecutor.runWhenOn(Dist.CLIENT, () -> SplashProgress::processMessages); + } + } + + /** + * Internal use only. + */ + public static Iterator barIterator() + { + return bars.iterator(); + } +} diff --git a/src/main/java/net/minecraftforge/fml/common/progress/StartupProgressManager.java b/src/main/java/net/minecraftforge/fml/common/progress/StartupProgressManager.java new file mode 100644 index 000000000..2126a556c --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/progress/StartupProgressManager.java @@ -0,0 +1,63 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.fml.common.progress; + +import net.minecraftforge.fml.SidedProvider; + +import java.util.Iterator; +import java.util.function.Consumer; +import java.util.function.Function; + +public class StartupProgressManager +{ + private static final Function stripChars = SidedProvider.STRIPCHARS.get(); + + public static void start(String title, int steps, Consumer task) + { + start(title, steps, false, task); + } + + public static void start(String title, int steps, boolean timeEachStep, Consumer task) + { + try (ProgressBar bar = start(title, steps, timeEachStep)) + { + task.accept(bar); + } + } + + public static ProgressBar start(String title, int steps) + { + return start(title, steps, false); + } + + public static ProgressBar start(String title, int steps, boolean timeEachStep) + { + StartupProgressBarTracker tracker = new StartupProgressBarTracker(timeEachStep, steps); + return new ProgressBar(title, steps, stripChars, tracker); + } + + /** + * Internal use only. + */ + public static Iterator barIterator() + { + return StartupProgressBarTracker.barIterator(); + } +} diff --git a/src/test/java/net/minecraftforge/test/TestProgressBar.java b/src/test/java/net/minecraftforge/test/TestProgressBar.java new file mode 100644 index 000000000..b58feb3bc --- /dev/null +++ b/src/test/java/net/minecraftforge/test/TestProgressBar.java @@ -0,0 +1,176 @@ +package net.minecraftforge.test; + +import net.minecraftforge.fml.common.progress.IProgressBarTracker; +import net.minecraftforge.fml.common.progress.ProgressBar; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +public class TestProgressBar +{ + private static String getStepMessage(int step) + { + if (step == 0) + { + return ""; + } + return "testStep" + step; + } + + private static void checkBarState(int step, String message, int expectedStepValue, int totalSteps) + { + if (step != expectedStepValue) + { + throw new IllegalStateException("Got step " + step + " but expected " + expectedStepValue); + } + if (step > totalSteps) + { + throw new IllegalStateException("ProgressBar stepped past the total: " + step + "/" + totalSteps); + } + String expectedMessage = getStepMessage(expectedStepValue); + if (!message.equals(expectedMessage)) + { + throw new IllegalStateException("Got message '" + message + "' but expected '" + expectedMessage + "'"); + } + } + + @Test + public void testProgressBar() + { + String title = "testTitle"; + final int totalSteps = 20; + + IProgressBarTracker tracker = new TestProgressBarTracker(totalSteps, title); + + try (ProgressBar progressBar = new ProgressBar(title, totalSteps, s -> s, tracker)) + { + String barTitle = progressBar.getTitle(); + if (!title.equals(barTitle)) + { + throw new IllegalStateException("Got title " + barTitle + " but expected " + title); + } + for (int i = 1; i <= totalSteps; i++) { + progressBar.step(getStepMessage(i)); + } + } + } + + @Test + public void testThreadedProgressBar() + { + String title = "testTitle"; + final int totalSteps = 10; + + TestProgressBarTracker tracker = new TestProgressBarTracker(totalSteps, title); + + AtomicBoolean threadSawBar = new AtomicBoolean(false); + Thread thread = new Thread(() -> + { + List bars = TestProgressBarTracker.getBars(); + while (bars.isEmpty()) + { + Thread.yield(); + bars = TestProgressBarTracker.getBars(); + } + while (!bars.isEmpty()) + { + for (ProgressBar bar : bars) + { + Pair stepAndMessage = bar.getStepAndMessage(); + int step = stepAndMessage.getLeft(); + String message = stepAndMessage.getRight(); + checkBarState(step, message, step, totalSteps); + threadSawBar.set(true); + } + Thread.yield(); + bars = TestProgressBarTracker.getBars(); + } + }); + thread.start(); + + try (ProgressBar progressBar = new ProgressBar(title, totalSteps, s -> s, tracker)) + { + String barTitle = progressBar.getTitle(); + if (!title.equals(barTitle)) + { + throw new IllegalStateException("Got title " + barTitle + " but expected " + title); + } + for (int i = 1; i <= totalSteps; i++) { + progressBar.step(getStepMessage(i)); + try + { + Thread.sleep(1); + } + catch (InterruptedException ignored) + { + + } + } + } + + if (!threadSawBar.get()) + { + throw new IllegalStateException("Thread never saw any progress bars"); + } + } + + private static class TestProgressBarTracker implements IProgressBarTracker + { + private static final List bars = new CopyOnWriteArrayList<>(); + private final AtomicInteger stepped = new AtomicInteger(0); + private final int totalSteps; + private final String title; + + public TestProgressBarTracker(int totalSteps, String title) + { + this.totalSteps = totalSteps; + this.title = title; + } + + @Override + public void onBarCreated(ProgressBar bar) + { + bars.add(bar); + int expectedStepCount = 0; + Pair stepAndMessage = bar.getStepAndMessage(); + Integer step = stepAndMessage.getLeft(); + String message = stepAndMessage.getRight(); + checkBarState(step, message, expectedStepCount, totalSteps); + } + + @Override + public void onStepStarted(ProgressBar bar, int step, String message) + { + int expectedStepCount = stepped.incrementAndGet(); + checkBarState(step, message, expectedStepCount, totalSteps); + } + + @Override + public void onStepFinished(ProgressBar bar, int step, String message) + { + int expectedStepCount = stepped.get(); + checkBarState(step, message, expectedStepCount, totalSteps); + } + + @Override + public void onBarFinished(ProgressBar bar, int step, String message) + { + bars.remove(bar); + int expectedStepCount = stepped.get(); + checkBarState(step, message, expectedStepCount, totalSteps); + if (step != totalSteps) + { + throw new IllegalStateException("ProgressBar did not finish: " + title + ".\nSteps: " + step + "/" + totalSteps); + } + } + + public static List getBars() + { + return bars; + } + } +}