Remove legacy StartupProgress.

Implement properly scalable progress thanks to @gigaherz. Closes #5863.
Implement API for pushing messages to the startup screen from mods.
Add memory display.

Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
cpw 2019-06-30 23:48:54 -04:00
parent 943fedb073
commit c8e5007913
No known key found for this signature in database
GPG key ID: 8EB3DF749553B1B7
26 changed files with 348 additions and 1526 deletions

View file

@ -1,14 +0,0 @@
--- a/com/mojang/blaze3d/platform/TextureUtil.java
+++ b/com/mojang/blaze3d/platform/TextureUtil.java
@@ -44,7 +44,10 @@
}
public static void prepareImage(NativeImage.PixelFormatGLCode p_prepareImage_0_, int p_prepareImage_1_, int p_prepareImage_2_, int p_prepareImage_3_, int p_prepareImage_4_) {
- bind(p_prepareImage_1_);
+ synchronized (net.minecraftforge.fml.client.SplashProgress.class)
+ {
+ bind(p_prepareImage_1_);
+ }
if (p_prepareImage_2_ >= 0) {
GlStateManager.texParameter(3553, 33085, p_prepareImage_2_);
GlStateManager.texParameter(3553, 33082, 0);

View file

@ -1,42 +1,6 @@
--- a/net/minecraft/client/audio/SoundHandler.java --- a/net/minecraft/client/audio/SoundHandler.java
+++ b/net/minecraft/client/audio/SoundHandler.java +++ b/net/minecraft/client/audio/SoundHandler.java
@@ -61,6 +61,7 @@ @@ -210,6 +210,11 @@
SoundHandler.Loader soundhandler$loader = new SoundHandler.Loader();
p_212854_2_.func_219894_a();
+ java.util.List<net.minecraft.util.Tuple<ResourceLocation, Runnable>> resources = new java.util.LinkedList<>();
for(String s : p_212854_1_.func_199001_a()) {
p_212854_2_.func_76320_a(s);
@@ -74,7 +75,9 @@
p_212854_2_.func_219895_b("register");
for(Entry<String, SoundList> entry : map.entrySet()) {
+ resources.add(new net.minecraft.util.Tuple<>(new ResourceLocation(s, entry.getKey()), () -> {
soundhandler$loader.func_217944_a(new ResourceLocation(s, entry.getKey()), entry.getValue(), p_212854_1_);
+ }));
}
p_212854_2_.func_76319_b();
@@ -91,6 +94,17 @@
p_212854_2_.func_76319_b();
}
+ net.minecraftforge.fml.common.progress.StartupProgressManager.start("Loading sounds", resources.size(), bar -> {
+ resources.forEach(entry -> {
+ bar.step(entry.func_76341_a().toString());
+ try {
+ entry.func_76340_b().run();
+ } catch (RuntimeException e) {
+ field_147698_b.warn("Invalid sounds.json", e);
+ }
+ });
+ });
+
p_212854_2_.func_219897_b();
return soundhandler$loader;
}
@@ -210,6 +224,11 @@
this.field_147694_f.func_195855_a(p_195478_1_, p_195478_2_); this.field_147694_f.func_195855_a(p_195478_1_, p_195478_2_);
} }

View file

@ -1,10 +1,10 @@
--- a/net/minecraft/client/gui/ResourceLoadProgressGui.java --- a/net/minecraft/client/gui/ResourceLoadProgressGui.java
+++ b/net/minecraft/client/gui/ResourceLoadProgressGui.java +++ b/net/minecraft/client/gui/ResourceLoadProgressGui.java
@@ -83,6 +83,7 @@ @@ -79,6 +79,7 @@
this.blit(k1, i1, 0, 0, 256, 256);
float f3 = this.field_212975_c.func_219555_b();
this.field_212978_f = this.field_212978_f * 0.95F + f3 * 0.050000012F;
+ net.minecraftforge.fml.client.ClientModLoader.renderProgressText();
if (f < 1.0F) {
this.func_212972_a(i / 2 - 150, j / 4 * 3, i / 2 + 150, j / 4 * 3 + 10, this.field_212978_f, 1.0F - MathHelper.func_76131_a(f, 0.0F, 1.0F)); this.func_212972_a(i / 2 - 150, j / 4 * 3, i / 2 + 150, j / 4 * 3 + 10, this.field_212978_f, 1.0F - MathHelper.func_76131_a(f, 0.0F, 1.0F));
} }
+ net.minecraftforge.fml.client.ClientModLoader.renderProgressText();
if (f >= 2.0F) {
this.field_212974_b.func_213268_a((LoadingGui)null);
}

View file

@ -9,28 +9,19 @@
private static final Comparator<Stitcher.Holder> field_217797_a = Comparator.<Stitcher.Holder, Integer>comparing((p_217793_0_) -> { private static final Comparator<Stitcher.Holder> field_217797_a = Comparator.<Stitcher.Holder, Integer>comparing((p_217793_0_) -> {
return -p_217793_0_.field_94201_d; return -p_217793_0_.field_94201_d;
}).thenComparing((p_217795_0_) -> { }).thenComparing((p_217795_0_) -> {
@@ -50,15 +52,21 @@ @@ -53,6 +55,12 @@
public void func_94305_f() {
List<Stitcher.Holder> list = Lists.newArrayList(this.field_94319_a);
list.sort(field_217797_a);
+ try(net.minecraftforge.fml.common.progress.ProgressBar bar = net.minecraftforge.fml.common.progress.StartupProgressManager.start("Texture stitching", list.size())) {
for(Stitcher.Holder stitcher$holder : list) { for(Stitcher.Holder stitcher$holder : list) {
+ bar.step(stitcher$holder.field_98151_a.func_195668_m().toString());
if (!this.func_94310_b(stitcher$holder)) { if (!this.func_94310_b(stitcher$holder)) {
+ LOGGER.info(String.format("Unable to fit: %s - size: %dx%d - Maybe try a lower resolution resourcepack?", stitcher$holder.field_98151_a.func_195668_m(), stitcher$holder.field_98151_a.func_94211_a(), stitcher$holder.field_98151_a.func_94216_b())); + LOGGER.info(new net.minecraftforge.fml.loading.AdvancedLogMessageAdapter(sb->{
+ for (Stitcher.Holder h : list) + sb.append("Unable to fit: ").append(stitcher$holder.field_98151_a.func_195668_m());
+ LOGGER.info(" {}", h); + sb.append(" - size: ").append(stitcher$holder.field_98151_a.func_94211_a()).append("x").append(stitcher$holder.field_98151_a.func_94216_b());
+ sb.append(" - Maybe try a lower resolution resourcepack?\n");
+ list.forEach(h-> sb.append("\t").append(h).append("\n"));
+ }));
throw new StitcherException(stitcher$holder.field_98151_a); throw new StitcherException(stitcher$holder.field_98151_a);
} }
} }
this.field_94318_c = MathHelper.func_151236_b(this.field_94318_c);
this.field_94315_d = MathHelper.func_151236_b(this.field_94315_d);
+ }; // Forge: end progress bar
}
public List<TextureAtlasSprite> func_94309_g() {
@@ -104,7 +112,7 @@ @@ -104,7 +112,7 @@
boolean flag4 = flag2 && j != l; boolean flag4 = flag2 && j != l;
boolean flag; boolean flag;

View file

@ -16,7 +16,7 @@
public boolean func_219533_b(ResourceLocation p_219533_1_) { public boolean func_219533_b(ResourceLocation p_219533_1_) {
IResourceManager iresourcemanager = this.field_199014_c.get(p_219533_1_.func_110624_b()); IResourceManager iresourcemanager = this.field_199014_c.get(p_219533_1_.func_110624_b());
return iresourcemanager != null ? iresourcemanager.func_219533_b(p_219533_1_) : false; return iresourcemanager != null ? iresourcemanager.func_219533_b(p_219533_1_) : false;
@@ -118,18 +116,20 @@ @@ -118,7 +116,6 @@
return iasyncreloader; return iasyncreloader;
} }
@ -24,17 +24,3 @@
public IAsyncReloader func_219535_a(Executor p_219535_1_, Executor p_219535_2_, CompletableFuture<Unit> p_219535_3_) { public IAsyncReloader func_219535_a(Executor p_219535_1_, Executor p_219535_2_, CompletableFuture<Unit> p_219535_3_) {
return this.func_219538_b(p_219535_1_, p_219535_2_, this.field_219539_d, p_219535_3_); return this.func_219538_b(p_219535_1_, p_219535_2_, this.field_219539_d, p_219535_3_);
} }
public IAsyncReloader func_219537_a(Executor p_219537_1_, Executor p_219537_2_, CompletableFuture<Unit> p_219537_3_, List<IResourcePack> p_219537_4_) {
+ net.minecraftforge.fml.common.progress.StartupProgressManager.start("Loading Resources", p_219537_4_.size(), true, bar -> {
this.func_199008_b();
field_199012_a.info("Reloading ResourceManager: {}", p_219537_4_.stream().map(IResourcePack::func_195762_a).collect(Collectors.joining(", ")));
for(IResourcePack iresourcepack : p_219537_4_) {
+ bar.step(iresourcepack.func_195762_a());
this.func_199021_a(iresourcepack);
}
+ });
return this.func_219538_b(p_219537_1_, p_219537_2_, this.field_199015_d, p_219537_3_);
}

View file

@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.loading; package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import cpw.mods.modlauncher.api.LamdbaExceptionUtils;

View file

@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.client.model; package net.minecraftforge.client.model;
import net.minecraft.client.renderer.texture.ISprite; import net.minecraft.client.renderer.texture.ISprite;

View file

@ -20,11 +20,7 @@
package net.minecraftforge.common; package net.minecraftforge.common;
import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.ExtensionPoint; import net.minecraftforge.fml.*;
import net.minecraftforge.fml.FMLWorldPersistenceHook;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.WorldPersistenceHooks;
import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
@ -103,6 +99,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
modEventBus.register(ForgeConfig.class); modEventBus.register(ForgeConfig.class);
// Forge does not display problems when the remote is not matching. // Forge does not display problems when the remote is not matching.
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, ()-> Pair.of(()->"ANY", (remote, isServer)-> true)); ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, ()-> Pair.of(()->"ANY", (remote, isServer)-> true));
StartupMessageManager.addModMessage("Forge version "+ForgeVersion.getVersion());
} }
/* /*

View file

@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.common.extensions; package net.minecraftforge.common.extensions;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;

View file

@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.common.extensions; package net.minecraftforge.common.extensions;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;

View file

@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.common.extensions; package net.minecraftforge.common.extensions;
import javax.annotation.Nullable; import javax.annotation.Nullable;

View file

@ -41,7 +41,7 @@ public enum LifecycleEventProvider
GATHERDATA(()->new GatherDataLifecycleEvent(ModLoadingStage.GATHERDATA), ModList.inlineDispatcher); GATHERDATA(()->new GatherDataLifecycleEvent(ModLoadingStage.GATHERDATA), ModList.inlineDispatcher);
private final Supplier<? extends LifecycleEvent> event; private final Supplier<? extends LifecycleEvent> event;
private final EventHandler<LifecycleEvent, Consumer<List<ModLoadingException>>,Executor> eventDispatcher; private final EventHandler<LifecycleEvent, Consumer<List<ModLoadingException>>,Executor, Runnable> eventDispatcher;
private Supplier<Event> customEventSupplier; private Supplier<Event> customEventSupplier;
private LifecycleEvent.Progression progression = LifecycleEvent.Progression.NEXT; private LifecycleEvent.Progression progression = LifecycleEvent.Progression.NEXT;
@ -50,7 +50,7 @@ public enum LifecycleEventProvider
this(e, ModList.parallelDispatcher); this(e, ModList.parallelDispatcher);
} }
LifecycleEventProvider(Supplier<? extends LifecycleEvent> e, EventHandler<LifecycleEvent, Consumer<List<ModLoadingException>>,Executor> eventDispatcher) LifecycleEventProvider(Supplier<? extends LifecycleEvent> e, EventHandler<LifecycleEvent, Consumer<List<ModLoadingException>>,Executor, Runnable> eventDispatcher)
{ {
this.event = e; this.event = e;
this.eventDispatcher = eventDispatcher; this.eventDispatcher = eventDispatcher;
@ -64,11 +64,11 @@ public enum LifecycleEventProvider
this.progression = progression; this.progression = progression;
} }
public void dispatch(Consumer<List<ModLoadingException>> errorHandler, final Executor executor) { public void dispatch(Consumer<List<ModLoadingException>> errorHandler, final Executor executor, final Runnable ticker) {
final LifecycleEvent lifecycleEvent = this.event.get(); final LifecycleEvent lifecycleEvent = this.event.get();
lifecycleEvent.setCustomEventSupplier(this.customEventSupplier); lifecycleEvent.setCustomEventSupplier(this.customEventSupplier);
lifecycleEvent.changeProgression(this.progression); lifecycleEvent.changeProgression(this.progression);
this.eventDispatcher.dispatchEvent(lifecycleEvent, errorHandler, executor); this.eventDispatcher.dispatchEvent(lifecycleEvent, errorHandler, executor, ticker);
} }
@ -148,7 +148,7 @@ public enum LifecycleEventProvider
} }
} }
public interface EventHandler<T extends LifecycleEvent, U extends Consumer<? extends List<? super ModLoadingException>>, V extends Executor> { public interface EventHandler<T extends LifecycleEvent, U extends Consumer<? extends List<? super ModLoadingException>>, V extends Executor, R extends Runnable> {
void dispatchEvent(T event, U exceptionHandler, V executor); void dispatchEvent(T event, U exceptionHandler, V executor, R ticker);
} }
} }

View file

@ -33,10 +33,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.*;
import java.util.concurrent.Executor;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
@ -81,9 +78,9 @@ public class ModList
return INSTANCE; return INSTANCE;
} }
static LifecycleEventProvider.EventHandler<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>, Executor> inlineDispatcher = (event, errors, executor) -> ModList.get().dispatchSynchronousEvent(event, errors, executor); static LifecycleEventProvider.EventHandler<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>, Executor, Runnable> inlineDispatcher = (event, errors, executor, ticker) -> ModList.get().dispatchSynchronousEvent(event, errors, executor);
static LifecycleEventProvider.EventHandler<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>, Executor> parallelDispatcher = (event, errors, executor) -> ModList.get().dispatchParallelEvent(event, errors, executor); static LifecycleEventProvider.EventHandler<LifecycleEventProvider.LifecycleEvent, Consumer<List<ModLoadingException>>, Executor, Runnable> parallelDispatcher = (event, errors, executor, ticker) -> ModList.get().dispatchParallelEvent(event, errors, executor, ticker);
public static ModList get() { public static ModList get() {
return INSTANCE; return INSTANCE;
@ -113,13 +110,17 @@ public class ModList
this.mods.forEach(m->m.transitionState(lifecycleEvent, errorHandler)); this.mods.forEach(m->m.transitionState(lifecycleEvent, errorHandler));
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent)); FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
} }
private void dispatchParallelEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler, final Executor executor) { private void dispatchParallelEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler, final Executor executor, final Runnable ticker) {
LOGGER.debug(LOADING, "Dispatching parallel event {}", lifecycleEvent); LOGGER.debug(LOADING, "Dispatching parallel event {}", lifecycleEvent);
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent)); FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
DeferredWorkQueue.clear(); DeferredWorkQueue.clear();
try try
{ {
modLoadingThreadPool.submit(()->this.mods.parallelStream().forEach(m->m.transitionState(lifecycleEvent, errorHandler))).get(); final ForkJoinTask<?> parallelTask = modLoadingThreadPool.submit(() -> this.mods.parallelStream().forEach(m -> m.transitionState(lifecycleEvent, errorHandler)));
while (ticker != null && !parallelTask.isDone()) {
executor.execute(ticker);
}
parallelTask.get();
} }
catch (InterruptedException | ExecutionException e) catch (InterruptedException | ExecutionException e)
{ {

View file

@ -102,7 +102,7 @@ public class ModLoader
private final List<ModLoadingWarning> loadingWarnings; private final List<ModLoadingWarning> loadingWarnings;
private GatherDataEvent.DataGeneratorConfig dataGeneratorConfig; private GatherDataEvent.DataGeneratorConfig dataGeneratorConfig;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Optional<Consumer<String>> statusConsumer = Optional.empty(); private final Optional<Consumer<String>> statusConsumer = StartupMessageManager.modLoaderConsumer();
private ModLoader() private ModLoader()
{ {
@ -127,15 +127,15 @@ public class ModLoader
DistExecutor.runWhenOn(Dist.CLIENT, ()->()-> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get())); DistExecutor.runWhenOn(Dist.CLIENT, ()->()-> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get()); ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get());
statusConsumer.ifPresent(c->c.accept("Mod setup: SETUP")); statusConsumer.ifPresent(c->c.accept("Mod setup: SETUP"));
dispatchAndHandleError(LifecycleEventProvider.SETUP, mainThreadExecutor); dispatchAndHandleError(LifecycleEventProvider.SETUP, mainThreadExecutor, null);
statusConsumer.ifPresent(c->c.accept("Mod setup: SIDED SETUP")); statusConsumer.ifPresent(c->c.accept("Mod setup: SIDED SETUP"));
mainThreadExecutor.execute(()->preSidedRunnable.accept(c->ModList.get().forEachModContainer((mi,mc)->mc.acceptEvent(c.get())))); mainThreadExecutor.execute(()->preSidedRunnable.accept(c->ModList.get().forEachModContainer((mi,mc)->mc.acceptEvent(c.get()))));
dispatchAndHandleError(LifecycleEventProvider.SIDED_SETUP, mainThreadExecutor); dispatchAndHandleError(LifecycleEventProvider.SIDED_SETUP, mainThreadExecutor, null);
mainThreadExecutor.execute(()->postSidedRunnable.accept(c->ModList.get().forEachModContainer((mi,mc)->mc.acceptEvent(c.get())))); mainThreadExecutor.execute(()->postSidedRunnable.accept(c->ModList.get().forEachModContainer((mi,mc)->mc.acceptEvent(c.get()))));
statusConsumer.ifPresent(c->c.accept("Mod setup complete")); statusConsumer.ifPresent(c->c.accept("Mod setup complete"));
} }
public void gatherAndInitializeMods() { public void gatherAndInitializeMods(final Runnable ticker) {
statusConsumer.ifPresent(c->c.accept("Loading mods")); statusConsumer.ifPresent(c->c.accept("Loading mods"));
final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(ModFileInfo::getFile).collect(Collectors.toList()), loadingModList.getMods()); final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(ModFileInfo::getFile).collect(Collectors.toList()), loadingModList.getMods());
if (!this.loadingExceptions.isEmpty()) { if (!this.loadingExceptions.isEmpty()) {
@ -155,22 +155,22 @@ public class ModLoader
throw new LoadingFailedException(loadingExceptions); throw new LoadingFailedException(loadingExceptions);
} }
modList.setLoadedMods(modContainers); modList.setLoadedMods(modContainers);
statusConsumer.ifPresent(c->c.accept("Constructing mods")); statusConsumer.ifPresent(c->c.accept(String.format("Constructing %d mods", modList.size())));
dispatchAndHandleError(LifecycleEventProvider.CONSTRUCT, Runnable::run); dispatchAndHandleError(LifecycleEventProvider.CONSTRUCT, Runnable::run, ticker);
statusConsumer.ifPresent(c->c.accept("Creating registries")); statusConsumer.ifPresent(c->c.accept("Creating registries"));
GameData.fireCreateRegistryEvents(LifecycleEventProvider.CREATE_REGISTRIES, event -> dispatchAndHandleError(event, Runnable::run)); GameData.fireCreateRegistryEvents(LifecycleEventProvider.CREATE_REGISTRIES, event -> dispatchAndHandleError(event, Runnable::run, ticker));
ObjectHolderRegistry.findObjectHolders(); ObjectHolderRegistry.findObjectHolders();
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData()); CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
statusConsumer.ifPresent(c->c.accept("Populating registries")); statusConsumer.ifPresent(c->c.accept("Populating registries"));
GameData.fireRegistryEvents(rl->true, LifecycleEventProvider.LOAD_REGISTRIES, event -> dispatchAndHandleError(event, Runnable::run)); GameData.fireRegistryEvents(rl->true, LifecycleEventProvider.LOAD_REGISTRIES, event -> dispatchAndHandleError(event, Runnable::run, ticker));
statusConsumer.ifPresent(c->c.accept("Early mod loading complete")); statusConsumer.ifPresent(c->c.accept("Early mod loading complete"));
} }
private void dispatchAndHandleError(LifecycleEventProvider event, Executor executor) { private void dispatchAndHandleError(LifecycleEventProvider event, Executor executor, final Runnable ticker) {
if (!loadingExceptions.isEmpty()) { if (!loadingExceptions.isEmpty()) {
LOGGER.error(LOADING,"Skipping lifecycle event {}, {} errors found.", event, loadingExceptions.size()); LOGGER.error(LOADING,"Skipping lifecycle event {}, {} errors found.", event, loadingExceptions.size());
} else { } else {
event.dispatch(this::accumulateErrors, executor); event.dispatch(this::accumulateErrors, executor, ticker);
} }
if (!loadingExceptions.isEmpty()) { if (!loadingExceptions.isEmpty()) {
LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", event, loadingExceptions.size()); LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", event, loadingExceptions.size());
@ -220,15 +220,15 @@ public class ModLoader
public void finishMods(Executor mainThreadExecutor) public void finishMods(Executor mainThreadExecutor)
{ {
statusConsumer.ifPresent(c->c.accept("Mod setup: ENQUEUE IMC")); statusConsumer.ifPresent(c->c.accept("Mod setup: ENQUEUE IMC"));
dispatchAndHandleError(LifecycleEventProvider.ENQUEUE_IMC, mainThreadExecutor); dispatchAndHandleError(LifecycleEventProvider.ENQUEUE_IMC, mainThreadExecutor, null);
statusConsumer.ifPresent(c->c.accept("Mod setup: PROCESS IMC")); statusConsumer.ifPresent(c->c.accept("Mod setup: PROCESS IMC"));
dispatchAndHandleError(LifecycleEventProvider.PROCESS_IMC, mainThreadExecutor); dispatchAndHandleError(LifecycleEventProvider.PROCESS_IMC, mainThreadExecutor, null);
statusConsumer.ifPresent(c->c.accept("Mod setup: Final completion")); statusConsumer.ifPresent(c->c.accept("Mod setup: Final completion"));
dispatchAndHandleError(LifecycleEventProvider.COMPLETE, mainThreadExecutor); dispatchAndHandleError(LifecycleEventProvider.COMPLETE, mainThreadExecutor, null);
statusConsumer.ifPresent(c->c.accept("Freezing data")); statusConsumer.ifPresent(c->c.accept("Freezing data"));
GameData.freezeData(); GameData.freezeData();
NetworkRegistry.lock(); NetworkRegistry.lock();
statusConsumer.ifPresent(c->c.accept("")); statusConsumer.ifPresent(c->c.accept(String.format("Mod loading complete - %d mods loaded", ModList.get().size())));
} }
public List<ModLoadingWarning> getWarnings() public List<ModLoadingWarning> getWarnings()
@ -246,16 +246,12 @@ public class ModLoader
LOGGER.info("Initializing Data Gatherer for mods {}", mods); LOGGER.info("Initializing Data Gatherer for mods {}", mods);
Bootstrap.register(); Bootstrap.register();
dataGeneratorConfig = new GatherDataEvent.DataGeneratorConfig(mods, path, inputs, serverGenerators, clientGenerators, devToolGenerators, reportsGenerator, structureValidator); dataGeneratorConfig = new GatherDataEvent.DataGeneratorConfig(mods, path, inputs, serverGenerators, clientGenerators, devToolGenerators, reportsGenerator, structureValidator);
gatherAndInitializeMods(); gatherAndInitializeMods(null);
dispatchAndHandleError(LifecycleEventProvider.GATHERDATA, Runnable::run); dispatchAndHandleError(LifecycleEventProvider.GATHERDATA, Runnable::run, null);
dataGeneratorConfig.runAll(); dataGeneratorConfig.runAll();
} }
public Function<ModContainer, ModLifecycleEvent> getDataGeneratorEvent() { public Function<ModContainer, ModLifecycleEvent> getDataGeneratorEvent() {
return mc -> new GatherDataEvent(mc, dataGeneratorConfig.makeGenerator(p->dataGeneratorConfig.getMods().size() == 1 ? p : p.resolve(mc.getModId()), dataGeneratorConfig.getMods().contains(mc.getModId())), dataGeneratorConfig); return mc -> new GatherDataEvent(mc, dataGeneratorConfig.makeGenerator(p->dataGeneratorConfig.getMods().size() == 1 ? p : p.resolve(mc.getModId()), dataGeneratorConfig.getMods().contains(mc.getModId())), dataGeneratorConfig);
} }
public void setStatusConsumer(Consumer<String> consumer) {
this.statusConsumer = Optional.ofNullable(consumer);
}
} }

View file

@ -0,0 +1,103 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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;
import com.google.common.base.Ascii;
import com.google.common.base.CharMatcher;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class StartupMessageManager {
private static final EnumMap<MessageType, List<Message>> messages = new EnumMap<>(MessageType.class);
static {
Arrays.stream(MessageType.values()).forEach(mt->messages.computeIfAbsent(mt, k->new CopyOnWriteArrayList<>()));
}
public static List<Pair<Integer,Message>> getMessages() {
final long ts = System.nanoTime();
return messages.values().stream().flatMap(Collection::stream).
sorted(Comparator.comparingLong(Message::getTimestamp).thenComparing(Message::getText).reversed()).
map(m -> Pair.of((int) ((ts - m.timestamp) / 1e6), m)).
collect(Collectors.toList());
}
public static class Message {
private final String text;
private final MessageType type;
private final long timestamp;
public Message(final String text, final MessageType type) {
this.text = text;
this.type = type;
this.timestamp = System.nanoTime();
}
public String getText() {
return text;
}
MessageType getType() {
return type;
}
long getTimestamp() {
return timestamp;
}
public float[] getTypeColour() {
return type.colour();
}
}
enum MessageType {
MC(0.0f, 0.0f, 0.0f),
ML(0.0f, 0.0f, 0.5f),
MOD(0.5f, 0.0f, 0.0f);
private final float[] colour;
MessageType(final float r, final float g, final float b) {
colour = new float[] {r,g,b};
}
public float[] colour() {
return colour;
}
}
public static void addModMessage(final String message) {
final String safeMessage = Ascii.truncate(CharMatcher.ascii().retainFrom(message),80,"~");
final List<Message> messages = StartupMessageManager.messages.get(MessageType.MOD);
messages.subList(0, Math.max(0, messages.size() - 20)).clear();
messages.add(new Message(safeMessage, MessageType.MOD));
}
static Optional<Consumer<String>> modLoaderConsumer() {
return Optional.of(s-> messages.get(MessageType.ML).add(new Message(s, MessageType.ML)));
}
static Optional<Consumer<String>> mcLoaderConsumer() {
return Optional.of(s-> messages.get(MessageType.MC).add(new Message(s, MessageType.MC)));
}
}

View file

@ -64,8 +64,7 @@ public class ClientModLoader
SidedProvider.setClient(()->minecraft); SidedProvider.setClient(()->minecraft);
LogicalSidedProvider.setClient(()->minecraft); LogicalSidedProvider.setClient(()->minecraft);
earlyLoaderGUI = new EarlyLoaderGUI(minecraft.mainWindow); earlyLoaderGUI = new EarlyLoaderGUI(minecraft.mainWindow);
ModLoader.get().setStatusConsumer(earlyLoaderGUI.getStatusConsumer()); createRunnableWithCatch(() -> ModLoader.get().gatherAndInitializeMods(earlyLoaderGUI::renderTick)).run();
createRunnableWithCatch(ModLoader.get()::gatherAndInitializeMods).run();
ResourcePackLoader.loadResourcePacks(defaultResourcePacks); ResourcePackLoader.loadResourcePacks(defaultResourcePacks);
mcResourceManager.addReloadListener(ClientModLoader::onreload); mcResourceManager.addReloadListener(ClientModLoader::onreload);
mcResourceManager.addReloadListener(BrandingControl.resourceManagerReloadListener()); mcResourceManager.addReloadListener(BrandingControl.resourceManagerReloadListener());

View file

@ -1,18 +1,48 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.client; package net.minecraftforge.fml.client;
import com.google.common.base.Ascii;
import com.google.common.base.CharMatcher;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.client.MainWindow; import net.minecraft.client.MainWindow;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.StartupMessageManager;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.stb.STBEasyFont; import org.lwjgl.stb.STBEasyFont;
import org.lwjgl.stb.STBImage;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
public class EarlyLoaderGUI { public class EarlyLoaderGUI {
private final MainWindow window; private final MainWindow window;
private String message;
private boolean handledElsewhere; private boolean handledElsewhere;
public EarlyLoaderGUI(final MainWindow window) { public EarlyLoaderGUI(final MainWindow window) {
@ -22,51 +52,69 @@ public class EarlyLoaderGUI {
window.update(false); window.update(false);
} }
public Consumer<String> getStatusConsumer() {
return this::update;
}
private void update(final String message) {
this.message = message;
if (handledElsewhere) return;
doMatrix();
GlStateManager.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC);
renderMessage();
window.update(false);
}
public void handleElsewhere() { public void handleElsewhere() {
this.handledElsewhere = true; this.handledElsewhere = true;
} }
void renderFromGUI() { void renderFromGUI() {
doMatrix(); renderMessages();
renderMessage();
} }
void renderMessage() {
void renderTick() {
if (handledElsewhere) return;
int guiScale = window.func_216521_a(0, false);
window.func_216525_a(guiScale);
GlStateManager.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC);
window.func_216522_a(Minecraft.IS_RUNNING_ON_MAC);
renderMessages();
window.update(false);
}
private void renderMessages() {
List<Pair<Integer, StartupMessageManager.Message>> messages = StartupMessageManager.getMessages();
for (int i = 0; i < messages.size(); i++) {
final Pair<Integer, StartupMessageManager.Message> pair = messages.get(i);
final float fade = MathHelper.clamp((4000.0f - (float) pair.getLeft() - ( i - 4 ) * 1000.0f) / 5000.0f, 0.0f, 1.0f);
if (fade <0.01f) continue;
StartupMessageManager.Message msg = pair.getRight();
renderMessage(msg.getText(), msg.getTypeColour(), i, fade);
}
renderMemoryInfo();
}
private static final float[] memorycolour = new float[] { 0.0f, 0.0f, 0.0f};
private void renderMemoryInfo() {
final MemoryUsage heapusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
final MemoryUsage offheapusage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
final float pctmemory = (float) heapusage.getUsed() / heapusage.getMax();
String memory = String.format("Memory Heap: %d / %d MB (%.1f%%) OffHeap: %d MB", heapusage.getUsed() >> 20, heapusage.getMax() >> 20, pctmemory * 100.0, offheapusage.getUsed() >> 20);
final int i = MathHelper.hsvToRGB((1.0f - (float)Math.pow(pctmemory, 1.5f)) / 3f, 1.0f, 0.5f);
memorycolour[2] = ((i) & 0xFF) / 255.0f;
memorycolour[1] = ((i >> 8 ) & 0xFF) / 255.0f;
memorycolour[0] = ((i >> 16 ) & 0xFF) / 255.0f;
renderMessage(memory, memorycolour, 21, 1.0f);
}
void renderMessage(final String message, final float[] colour, int line, float alpha) {
GlStateManager.enableClientState(GL11.GL_VERTEX_ARRAY); GlStateManager.enableClientState(GL11.GL_VERTEX_ARRAY);
ByteBuffer charBuffer = MemoryUtil.memAlloc(this.message.length() * 270); ByteBuffer charBuffer = MemoryUtil.memAlloc(message.length() * 270);
int quads = STBEasyFont.stb_easy_font_print(0, 0, this.message, null, charBuffer); int quads = STBEasyFont.stb_easy_font_print(0, 0, message, null, charBuffer);
GlStateManager.vertexPointer(2, GL11.GL_FLOAT, 16, charBuffer); GlStateManager.vertexPointer(2, GL11.GL_FLOAT, 16, charBuffer);
GlStateManager.color3f(0,0,0); GlStateManager.enableBlend();
GL14.glBlendColor(0,0,0, alpha);
GlStateManager.blendFunc(GlStateManager.SourceFactor.CONSTANT_ALPHA, GlStateManager.DestFactor.ONE_MINUS_CONSTANT_ALPHA);
GlStateManager.color3f(colour[0],colour[1],colour[2]);
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
GlStateManager.translatef(10, window.getFramebufferHeight() - 50, 0); GlStateManager.translatef(10, window.getScaledHeight() - 15 - line * 10, 0);
GlStateManager.scalef(3, 3, 0); GlStateManager.scalef(1, 1, 0);
GlStateManager.drawArrays(GL11.GL_QUADS, 0, quads * 4); GlStateManager.drawArrays(GL11.GL_QUADS, 0, quads * 4);
GlStateManager.popMatrix(); GlStateManager.popMatrix();
MemoryUtil.memFree(charBuffer); MemoryUtil.memFree(charBuffer);
} }
private void doMatrix() {
GlStateManager.clear(GL11.GL_DEPTH_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC);
GlStateManager.matrixMode(GL11.GL_PROJECTION);
GlStateManager.loadIdentity();
GlStateManager.ortho(0.0, window.getFramebufferWidth(), window.getFramebufferHeight(), 0.0, -1.0, 1.0);
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
GlStateManager.loadIdentity();
}
} }

View file

@ -1,25 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.client;
public class FMLClientConfig
{
}

View file

@ -1,30 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.client;
import net.minecraft.client.gui.screen.Screen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public interface IDisplayableError
{
@OnlyIn(Dist.CLIENT)
Screen createGui();
}

View file

@ -1,987 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.client;
/*
import static net.minecraftforge.fml.Logging.SPLASH;
import static net.minecraftforge.fml.Logging.fmlLog;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.nio.IntBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import com.google.common.base.CharMatcher;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.DefaultResourcePack;
import net.minecraft.client.resources.FileResourcePack;
import net.minecraft.client.resources.FolderResourcePack;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.client.resources.SimpleResource;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.CrashReportExtender;
import net.minecraftforge.fml.common.EnhancedRuntimeException;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.ICrashCallable;
import net.minecraftforge.fml.common.ProgressManager;
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.Drawable;
import org.lwjgl.opengl.SharedDrawable;
import org.lwjgl.util.glu.GLU;
/**
* Not a fully fleshed out API, may change in future MC versions.
* However feel free to use and suggest additions.
*/
@SuppressWarnings("serial")
public class SplashProgress
{
/*
private static Drawable d;
private static volatile boolean pause = false;
private static volatile boolean done = false;
private static Thread thread;
private static volatile Throwable threadError;
private static int angle = 0;
private static final Lock lock = new ReentrantLock(true);
private static SplashFontRenderer fontRenderer;
private static final IResourcePack mcPack = Minecraft.getMinecraft().mcDefaultResourcePack;
private static final IResourcePack fmlPack = mcPack;
private static IResourcePack miscPack;
private static Texture fontTexture;
private static Texture logoTexture;
private static Texture forgeTexture;
private static Properties config;
private static boolean enabled;
private static boolean rotate;
private static int logoOffset;
private static int backgroundColor;
private static int fontColor;
private static int barBorderColor;
private static int barColor;
private static int barBackgroundColor;
private static boolean showMemory;
private static int memoryGoodColor;
private static int memoryWarnColor;
private static int memoryLowColor;
private static float memoryColorPercent;
private static long memoryColorChangeTime;
static boolean isDisplayVSyncForced = false;
private static final int TIMING_FRAME_COUNT = 200;
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() {
/*
// 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
// We'll get another go next time
if (!SplashProgress.mutex.tryAcquire()) return null;
Display.processMessages();
SplashProgress.mutex.release();
*/
}
/*
private static String getString(String name, String def)
{
String value = config.getProperty(name, def);
config.setProperty(name, value);
return value;
}
private static boolean getBool(String name, boolean def)
{
return Boolean.parseBoolean(getString(name, Boolean.toString(def)));
}
private static int getInt(String name, int def)
{
return Integer.decode(getString(name, Integer.toString(def)));
}
private static int getHex(String name, int def)
{
return Integer.decode(getString(name, "0x" + Integer.toString(def, 16).toUpperCase()));
}
public static void start()
{
File configFile = new File(Minecraft.getMinecraft().mcDataDir, "config/splash.properties");
File parent = configFile.getParentFile();
if (!parent.exists())
parent.mkdirs();
config = new Properties();
try (Reader r = new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8))
{
config.load(r);
}
catch(IOException e)
{
fmlLog.info(SPLASH, "Could not load splash.properties, will create a default one");
}
enabled = getBool("enabled", true);
rotate = getBool("rotate", false);
showMemory = getBool("showMemory", true);
logoOffset = getInt("logoOffset", 0);
backgroundColor = getHex("background", 0xFFFFFF);
fontColor = getHex("font", 0x000000);
barBorderColor = getHex("barBorder", 0xC0C0C0);
barColor = getHex("bar", 0xCB3D35);
barBackgroundColor = getHex("barBackground", 0xFFFFFF);
memoryGoodColor = getHex("memoryGood", 0x78CB34);
memoryWarnColor = getHex("memoryWarn", 0xE6E84A);
memoryLowColor = getHex("memoryLow", 0xE42F2F);
final ResourceLocation fontLoc = new ResourceLocation(getString("fontTexture", "textures/font/ascii.png"));
final ResourceLocation logoLoc = new ResourceLocation("textures/gui/title/mojang.png");
final ResourceLocation forgeLoc = new ResourceLocation(getString("forgeTexture", "fml:textures/gui/forge.png"));
final ResourceLocation forgeFallbackLoc = new ResourceLocation("fml:textures/gui/forge.png");
File miscPackFile = new File(Minecraft.getMinecraft().mcDataDir, getString("resourcePackPath", "resources"));
try (Writer w = new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8))
{
config.store(w, "Splash screen properties");
}
catch(IOException e)
{
LOGGER.error("Could not save the splash.properties file", e);
}
miscPack = createResourcePack(miscPackFile);
if(!enabled) return;
// getting debug info out of the way, while we still can
CrashReportExtender.registerCrashCallable(new ICrashCallable()
{
@Override
public String call() throws Exception
{
return "' Vendor: '" + glGetString(GL_VENDOR) +
"' Version: '" + glGetString(GL_VERSION) +
"' Renderer: '" + glGetString(GL_RENDERER) +
"'";
}
@Override
public String getLabel()
{
return "GL info";
}
});
CrashReport report = CrashReport.makeCrashReport(new Throwable(), "Loading screen debug info");
StringBuilder systemDetailsBuilder = new StringBuilder();
report.getCategory().appendToStringBuilder(systemDetailsBuilder);
fmlLog.info(SPLASH, systemDetailsBuilder.toString());
try
{
d = new SharedDrawable(Display.getDrawable());
Display.getDrawable().releaseContext();
d.makeCurrent();
}
catch (LWJGLException e)
{
LOGGER.error("Error starting SplashProgress:", e);
disableSplash(e);
}
//Call this ASAP if splash is enabled so that threading doesn't cause issues later
getMaxTextureSize();
//Thread mainThread = Thread.currentThread();
thread = new Thread(new Runnable()
{
private final int barWidth = 400;
private final int barHeight = 20;
private final int textHeight2 = 20;
private final int barOffset = 55;
private long updateTiming;
private long framecount;
@Override
public void run()
{
setGL();
fontTexture = new Texture(fontLoc, null);
logoTexture = new Texture(logoLoc, null, false);
forgeTexture = new Texture(forgeLoc, forgeFallbackLoc);
glEnable(GL_TEXTURE_2D);
fontRenderer = new SplashFontRenderer();
glDisable(GL_TEXTURE_2D);
while(!done)
{
framecount++;
ProgressBar first = null, penult = null, last = null;
Iterator<ProgressBar> i = ProgressManager.barIterator();
while(i.hasNext())
{
if(first == null) first = i.next();
else
{
penult = last;
last = i.next();
}
}
glClear(GL_COLOR_BUFFER_BIT);
// matrix setup
int w = Display.getWidth();
int h = Display.getHeight();
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(320 - w/2, 320 + w/2, 240 + h/2, 240 - h/2, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// mojang logo
setColor(backgroundColor);
glEnable(GL_TEXTURE_2D);
logoTexture.bind();
glBegin(GL_QUADS);
logoTexture.texCoord(0, 0, 0);
glVertex2f(320 - 256, 240 - 256);
logoTexture.texCoord(0, 0, 1);
glVertex2f(320 - 256, 240 + 256);
logoTexture.texCoord(0, 1, 1);
glVertex2f(320 + 256, 240 + 256);
logoTexture.texCoord(0, 1, 0);
glVertex2f(320 + 256, 240 - 256);
glEnd();
glDisable(GL_TEXTURE_2D);
// memory usage
if (showMemory)
{
glPushMatrix();
glTranslatef(320 - (float) barWidth / 2, 20, 0);
drawMemoryBar();
glPopMatrix();
}
// bars
if(first != null)
{
glPushMatrix();
glTranslatef(320 - (float)barWidth / 2, 310, 0);
drawBar(first);
if(penult != null)
{
glTranslatef(0, barOffset, 0);
drawBar(penult);
}
if(last != null)
{
glTranslatef(0, barOffset, 0);
drawBar(last);
}
glPopMatrix();
}
angle += 1;
// forge logo
glColor4f(1, 1, 1, 1);
float fw = (float)forgeTexture.getWidth() / 2;
float fh = (float)forgeTexture.getHeight() / 2;
if(rotate)
{
float sh = Math.max(fw, fh);
glTranslatef(320 + w/2 - sh - logoOffset, 240 + h/2 - sh - logoOffset, 0);
glRotatef(angle, 0, 0, 1);
}
else
{
glTranslatef(320 + w/2 - fw - logoOffset, 240 + h/2 - fh - logoOffset, 0);
}
int f = (angle / 5) % forgeTexture.getFrames();
glEnable(GL_TEXTURE_2D);
forgeTexture.bind();
glBegin(GL_QUADS);
forgeTexture.texCoord(f, 0, 0);
glVertex2f(-fw, -fh);
forgeTexture.texCoord(f, 0, 1);
glVertex2f(-fw, fh);
forgeTexture.texCoord(f, 1, 1);
glVertex2f(fw, fh);
forgeTexture.texCoord(f, 1, 0);
glVertex2f(fw, -fh);
glEnd();
glDisable(GL_TEXTURE_2D);
// We use mutex to indicate safely to the main thread that we're taking the display global lock
// So the main thread can skip processing messages while we're updating.
// There are system setups where this call can pause for a while, because the GL implementation
// is trying to impose a framerate or other thing is occurring. Without the mutex, the main
// thread would delay waiting for the same global display lock
mutex.acquireUninterruptibly();
long updateStart = System.nanoTime();
Display.update();
// As soon as we're done, we release the mutex. The other thread can now ping the processmessages
// call as often as it wants until we get get back here again
long dur = System.nanoTime() - updateStart;
if (framecount < TIMING_FRAME_COUNT) {
updateTiming += dur;
}
mutex.release();
if(pause)
{
clearGL();
setGL();
}
// Such a hack - if the time taken is greater than 10 milliseconds, we're gonna guess that we're on a
// system where vsync is forced through the swapBuffers call - so we have to force a sleep and let the
// loading thread have a turn - some badly designed mods access Keyboard and therefore GlobalLock.lock
// during splash screen, and mutex against the above Display.update call as a result.
// 4 milliseconds is a guess - but it should be enough to trigger in most circumstances. (Maybe if
// 240FPS is possible, this won't fire?)
if (framecount >= TIMING_FRAME_COUNT && updateTiming > TIMING_FRAME_THRESHOLD) {
if (!isDisplayVSyncForced)
{
isDisplayVSyncForced = true;
fmlLog.info(SPLASH,"Using alternative sync timing : {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming);
}
try { Thread.sleep(16); } catch (InterruptedException ie) {}
} else
{
if (framecount ==TIMING_FRAME_COUNT) {
fmlLog.info("Using sync timing. {} frames of Display.update took {} nanos", TIMING_FRAME_COUNT, updateTiming);
}
Display.sync(100);
}
}
clearGL();
}
private void setColor(int color)
{
glColor3ub((byte)((color >> 16) & 0xFF), (byte)((color >> 8) & 0xFF), (byte)(color & 0xFF));
}
private void drawBox(int w, int h)
{
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2f(0, h);
glVertex2f(w, h);
glVertex2f(w, 0);
glEnd();
}
private void drawBar(ProgressBar b)
{
glPushMatrix();
// title - message
setColor(fontColor);
glScalef(2, 2, 1);
glEnable(GL_TEXTURE_2D);
fontRenderer.drawString(b.getTitle() + " - " + b.getMessage(), 0, 0, 0x000000);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
// border
glPushMatrix();
glTranslatef(0, textHeight2, 0);
setColor(barBorderColor);
drawBox(barWidth, barHeight);
// interior
setColor(barBackgroundColor);
glTranslatef(1, 1, 0);
drawBox(barWidth - 2, barHeight - 2);
// slidy part
setColor(barColor);
int step = b.getStep();
drawBox((barWidth - 2) * (step + 1) / (b.getTotalSteps() + 1), barHeight - 2); // Step can sometimes be 0.
// progress text
String progress = "" + step + "/" + b.getTotalSteps();
glTranslatef(((float)barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0);
setColor(fontColor);
glScalef(2, 2, 1);
glEnable(GL_TEXTURE_2D);
fontRenderer.drawString(progress, 0, 0, 0x000000);
glPopMatrix();
}
private void drawMemoryBar() {
int maxMemory = bytesToMb(Runtime.getRuntime().maxMemory());
int totalMemory = bytesToMb(Runtime.getRuntime().totalMemory());
int freeMemory = bytesToMb(Runtime.getRuntime().freeMemory());
int usedMemory = totalMemory - freeMemory;
float usedMemoryPercent = usedMemory / (float) maxMemory;
glPushMatrix();
// title - message
setColor(fontColor);
glScalef(2, 2, 1);
glEnable(GL_TEXTURE_2D);
fontRenderer.drawString("Memory Used / Total", 0, 0, 0x000000);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
// border
glPushMatrix();
glTranslatef(0, textHeight2, 0);
setColor(barBorderColor);
drawBox(barWidth, barHeight);
// interior
setColor(barBackgroundColor);
glTranslatef(1, 1, 0);
drawBox(barWidth - 2, barHeight - 2);
// slidy part
long time = System.currentTimeMillis();
if (usedMemoryPercent > memoryColorPercent || (time - memoryColorChangeTime > 1000))
{
memoryColorChangeTime = time;
memoryColorPercent = usedMemoryPercent;
}
int memoryBarColor;
if (memoryColorPercent < 0.75f)
{
memoryBarColor = memoryGoodColor;
}
else if (memoryColorPercent < 0.85f)
{
memoryBarColor = memoryWarnColor;
}
else
{
memoryBarColor = memoryLowColor;
}
setColor(memoryLowColor);
glPushMatrix();
glTranslatef((barWidth - 2) * (totalMemory) / (maxMemory) - 2, 0, 0);
drawBox(2, barHeight - 2);
glPopMatrix();
setColor(memoryBarColor);
drawBox((barWidth - 2) * (usedMemory) / (maxMemory), barHeight - 2);
// progress text
String progress = getMemoryString(usedMemory) + " / " + getMemoryString(maxMemory);
glTranslatef(((float)barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0);
setColor(fontColor);
glScalef(2, 2, 1);
glEnable(GL_TEXTURE_2D);
fontRenderer.drawString(progress, 0, 0, 0x000000);
glPopMatrix();
}
private String getMemoryString(int memory)
{
return StringUtils.leftPad(Integer.toString(memory), 4, ' ') + " MB";
}
private void setGL()
{
lock.lock();
try
{
Display.getDrawable().makeCurrent();
}
catch (LWJGLException e)
{
LOGGER.error("Error setting GL context:", e);
throw new RuntimeException(e);
}
glClearColor((float)((backgroundColor >> 16) & 0xFF) / 0xFF, (float)((backgroundColor >> 8) & 0xFF) / 0xFF, (float)(backgroundColor & 0xFF) / 0xFF, 1);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
private void clearGL()
{
Minecraft mc = Minecraft.getMinecraft();
mc.displayWidth = Display.getWidth();
mc.displayHeight = Display.getHeight();
mc.resize(mc.displayWidth, mc.displayHeight);
glClearColor(1, 1, 1, 1);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, .1f);
try
{
Display.getDrawable().releaseContext();
}
catch (LWJGLException e)
{
LOGGER.error("Error releasing GL context:", e);
throw new RuntimeException(e);
}
finally
{
lock.unlock();
}
}
});
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler()
{
@Override
public void uncaughtException(Thread t, Throwable e)
{
LOGGER.error("Splash thread Exception", e);
threadError = e;
}
});
thread.start();
checkThreadState();
}
private static int max_texture_size = -1;
public static int getMaxTextureSize()
{
if (max_texture_size != -1) return max_texture_size;
for (int i = 0x4000; i > 0; i >>= 1)
{
GlStateManager.glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, i, i, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
if (GlStateManager.glGetTexLevelParameteri(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) != 0)
{
max_texture_size = i;
return i;
}
}
return -1;
}
private static void checkThreadState()
{
if(thread.getState() == Thread.State.TERMINATED || threadError != null)
{
throw new IllegalStateException("Splash thread", threadError);
}
}
/**
* Call before you need to explicitly modify GL context state during loading.
* Resource loading doesn't usually require this call.
* Call {@link #resume()} when you're done.
* @deprecated not a stable API, will break, don't use this yet
* /
@Deprecated
public static void pause()
{
if(!enabled) return;
checkThreadState();
pause = true;
lock.lock();
try
{
d.releaseContext();
Display.getDrawable().makeCurrent();
}
catch (LWJGLException e)
{
LOGGER.error("Error setting GL context:", e);
throw new RuntimeException(e);
}
}
/**
* @deprecated not a stable API, will break, don't use this yet
* /
@Deprecated
public static void resume()
{
if(!enabled) return;
checkThreadState();
pause = false;
try
{
Display.getDrawable().releaseContext();
d.makeCurrent();
}
catch (LWJGLException e)
{
LOGGER.error("Error releasing GL context:", e);
throw new RuntimeException(e);
}
lock.unlock();
}
public static void finish()
{
if(!enabled) return;
try
{
checkThreadState();
done = true;
thread.join();
glFlush(); // process any remaining GL calls before releaseContext (prevents missing textures on mac)
d.releaseContext();
Display.getDrawable().makeCurrent();
fontTexture.delete();
logoTexture.delete();
forgeTexture.delete();
}
catch (Exception e)
{
LOGGER.error("Error finishing SplashProgress:", e);
disableSplash(e);
}
}
private static boolean disableSplash(Exception e)
{
if (disableSplash())
{
throw new EnhancedRuntimeException(e)
{
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
stream.println("SplashProgress has detected a error loading Minecraft.");
stream.println("This can sometimes be caused by bad video drivers.");
stream.println("We have automatically disabled the new Splash Screen in config/splash.properties.");
stream.println("Try reloading minecraft before reporting any errors.");
}
};
}
else
{
throw new EnhancedRuntimeException(e)
{
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
stream.println("SplashProgress has detected a error loading Minecraft.");
stream.println("This can sometimes be caused by bad video drivers.");
stream.println("Please try disabling the new Splash Screen in config/splash.properties.");
stream.println("After doing so, try reloading minecraft before reporting any errors.");
}
};
}
}
private static boolean disableSplash()
{
File configFile = new File(Minecraft.getMinecraft().mcDataDir, "config/splash.properties");
File parent = configFile.getParentFile();
if (!parent.exists())
parent.mkdirs();
enabled = false;
config.setProperty("enabled", "false");
try (Writer w = new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8))
{
config.store(w, "Splash screen properties");
}
catch(IOException e)
{
LOGGER.error("Could not save the splash.properties file", e);
return false;
}
return true;
}
private static IResourcePack createResourcePack(File file)
{
if(file.isDirectory())
{
return new FolderResourcePack(file);
}
else
{
return new FileResourcePack(file);
}
}
private static final IntBuffer buf = BufferUtils.createIntBuffer(4 * 1024 * 1024);
// From FontRenderer.renderCharAtPos
private static final String ALLOWED_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u0000\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
private static final CharMatcher DISALLOWED_CHAR_MATCHER = CharMatcher.anyOf(ALLOWED_CHARS).negate();
public static String stripSpecialChars(String message)
{
// We can't handle many unicode points in the splash renderer
return DISALLOWED_CHAR_MATCHER.removeFrom(net.minecraft.util.StringUtils.stripControlCodes(message));
}
@SuppressWarnings("unused")
private static class Texture
{
private final ResourceLocation location;
private final int name;
private final int width;
private final int height;
private final int frames;
private final int size;
public Texture(ResourceLocation location, @Nullable ResourceLocation fallback)
{
this(location, fallback, true);
}
public Texture(ResourceLocation location, @Nullable ResourceLocation fallback, boolean allowRP)
{
InputStream s = null;
try
{
this.location = location;
s = open(location, fallback, allowRP);
ImageInputStream stream = ImageIO.createImageInputStream(s);
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if(!readers.hasNext()) throw new IOException("No suitable reader found for image" + location);
ImageReader reader = readers.next();
reader.setInput(stream);
int frames = reader.getNumImages(true);
BufferedImage[] images = new BufferedImage[frames];
for(int i = 0; i < frames; i++)
{
images[i] = reader.read(i);
}
reader.dispose();
width = images[0].getWidth();
int height = images[0].getHeight();
// Animation strip
if (height > width && height % width == 0)
{
frames = height / width;
BufferedImage original = images[0];
height = width;
images = new BufferedImage[frames];
for (int i = 0; i < frames; i++)
{
images[i] = original.getSubimage(0, i * height, width, height);
}
}
this.frames = frames;
this.height = height;
int size = 1;
while((size / width) * (size / height) < frames) size *= 2;
this.size = size;
glEnable(GL_TEXTURE_2D);
synchronized(SplashProgress.class)
{
name = glGenTextures();
glBindTexture(GL_TEXTURE_2D, name);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, (IntBuffer)null);
checkGLError("Texture creation");
for(int i = 0; i * (size / width) < frames; i++)
{
for(int j = 0; i * (size / width) + j < frames && j < size / width; j++)
{
buf.clear();
BufferedImage image = images[i * (size / width) + j];
for(int k = 0; k < height; k++)
{
for(int l = 0; l < width; l++)
{
buf.put(image.getRGB(l, k));
}
}
buf.position(0).limit(width * height);
glTexSubImage2D(GL_TEXTURE_2D, 0, j * width, i * height, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buf);
checkGLError("Texture uploading");
}
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}
catch(IOException e)
{
LOGGER.error("Error reading texture from file: {}", location, e);
throw new RuntimeException(e);
}
finally
{
IOUtils.closeQuietly(s);
}
}
public ResourceLocation getLocation()
{
return location;
}
public int getName()
{
return name;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public int getFrames()
{
return frames;
}
public int getSize()
{
return size;
}
public void bind()
{
glBindTexture(GL_TEXTURE_2D, name);
}
public void delete()
{
glDeleteTextures(name);
}
public float getU(int frame, float u)
{
return width * (frame % (size / width) + u) / size;
}
public float getV(int frame, float v)
{
return height * (frame / (size / width) + v) / size;
}
public void texCoord(int frame, float u, float v)
{
glTexCoord2f(getU(frame, u), getV(frame, v));
}
}
private static class SplashFontRenderer extends FontRenderer
{
public SplashFontRenderer()
{
super(Minecraft.getMinecraft().gameSettings, fontTexture.getLocation(), null, false);
super.onResourceManagerReload(null);
}
@Override
protected void bindTexture(@Nonnull ResourceLocation location)
{
if(location != locationFontTexture) throw new IllegalArgumentException();
fontTexture.bind();
}
@Nonnull
@Override
protected IResource getResource(@Nonnull ResourceLocation location) throws IOException
{
DefaultResourcePack pack = Minecraft.getMinecraft().mcDefaultResourcePack;
return new SimpleResource(pack.getPackName(), location, pack.getInputStream(location), null, null);
}
}
public static void drawVanillaScreen(TextureManager renderEngine) throws LWJGLException
{
if(!enabled)
{
Minecraft.getMinecraft().drawSplashScreen(renderEngine);
}
}
public static void clearVanillaResources(TextureManager renderEngine, ResourceLocation mojangLogo)
{
if(!enabled)
{
renderEngine.deleteTexture(mojangLogo);
}
}
public static void checkGLError(String where)
{
int err = glGetError();
if (err != 0)
{
throw new IllegalStateException(where + ": " + GLU.gluErrorString(err));
}
}
private static InputStream open(ResourceLocation loc, @Nullable ResourceLocation fallback, boolean allowResourcePack) throws IOException
{
if (!allowResourcePack)
return mcPack.getInputStream(loc);
if(miscPack.resourceExists(loc))
{
return miscPack.getInputStream(loc);
}
else if(fmlPack.resourceExists(loc))
{
return fmlPack.getInputStream(loc);
}
else if(!mcPack.resourceExists(loc) && fallback != null)
{
return open(fallback, null, true);
}
return mcPack.getInputStream(loc);
}
private static int bytesToMb(long bytes)
{
return (int) (bytes / 1024L / 1024L);
}
*/
}

View file

@ -1,31 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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) {}
}

View file

@ -1,98 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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<String, String> stripChars;
private final IProgressBarTracker tracker;
private volatile int step = 0;
private volatile String message = "";
public ProgressBar(String title, int totalSteps, Function<String, String> 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<Integer, String> 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);
}
}

View file

@ -1,129 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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<ProgressBar> 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<ProgressBar> barIterator()
{
return bars.iterator();
}
}

View file

@ -1,63 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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<String, String> stripChars = SidedProvider.STRIPCHARS.get();
public static void start(String title, int steps, Consumer<ProgressBar> task)
{
start(title, steps, false, task);
}
public static void start(String title, int steps, boolean timeEachStep, Consumer<ProgressBar> 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<ProgressBar> barIterator()
{
return StartupProgressBarTracker.barIterator();
}
}

View file

@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* 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.network; package net.minecraftforge.fml.network;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;

View file

@ -42,7 +42,7 @@ public class ServerModLoader
SidedProvider.setServer(()->dedicatedServer); SidedProvider.setServer(()->dedicatedServer);
LogicalSidedProvider.setServer(()->dedicatedServer); LogicalSidedProvider.setServer(()->dedicatedServer);
LanguageHook.loadForgeAndMCLangs(); LanguageHook.loadForgeAndMCLangs();
ModLoader.get().gatherAndInitializeMods(); ModLoader.get().gatherAndInitializeMods(null);
ModLoader.get().loadMods(Runnable::run, (a)->{}, (a)->{}); ModLoader.get().loadMods(Runnable::run, (a)->{}, (a)->{});
} }