package net.puzzlemc.splashscreen; import com.mojang.blaze3d.pipeline.BlendFunction; import com.mojang.blaze3d.pipeline.RenderPipeline; import com.mojang.blaze3d.platform.DepthTestFunction; import com.mojang.blaze3d.platform.DestFactor; import com.mojang.blaze3d.platform.SourceFactor; import eu.midnightdust.lib.util.MidnightColorUtil; import eu.midnightdust.lib.util.PlatformFunctions; import net.minecraft.client.texture.NativeImageBackedTexture; import net.minecraft.client.texture.TextureContents; import net.minecraft.resource.*; import net.minecraft.util.Util; import net.puzzlemc.core.config.PuzzleConfig; import net.minecraft.client.MinecraftClient; import net.minecraft.client.resource.metadata.TextureResourceMetadata; import net.minecraft.client.texture.NativeImage; import net.minecraft.client.texture.ResourceTexture; import net.minecraft.util.Identifier; import net.puzzlemc.splashscreen.mixin.RenderPipelinesAccessor; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import static net.puzzlemc.core.PuzzleCore.LOGGER; import static net.puzzlemc.core.PuzzleCore.MOD_ID; public class PuzzleSplashScreen { public static final Identifier LOGO = Identifier.of("textures/gui/title/mojangstudios.png"); public static final Identifier BACKGROUND = Identifier.of("puzzle/splash_background.png"); public static File CONFIG_PATH = new File(String.valueOf(PlatformFunctions.getConfigDirectory().resolve(".puzzle_cache"))); public static Path LOGO_TEXTURE = Paths.get(CONFIG_PATH + "/mojangstudios.png"); public static Path BACKGROUND_TEXTURE = Paths.get(CONFIG_PATH + "/splash_background.png"); private static MinecraftClient client = MinecraftClient.getInstance(); private static boolean keepBackground = false; private static RenderPipeline CUSTOM_LOGO_PIPELINE; public static void init() { if (!CONFIG_PATH.exists()) { // Run when config directory is nonexistent // if (CONFIG_PATH.mkdir()) { // Create our custom config directory // if (Util.getOperatingSystem().equals(Util.OperatingSystem.WINDOWS)) { try { Files.setAttribute(CONFIG_PATH.toPath(), "dos:hidden", true); } catch (IOException ignored) {} } } } buildRenderLayer(); } public static RenderPipeline getCustomLogoRenderPipeline() { return CUSTOM_LOGO_PIPELINE; } public static void buildRenderLayer() { if (PuzzleConfig.resourcepackSplashScreen) { BlendFunction blendFunction = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE); if (PuzzleConfig.disableBlend) blendFunction = null; else if (PuzzleConfig.customBlendFunction.size() == 4) { try { blendFunction = new BlendFunction( SourceFactor.valueOf(PuzzleConfig.customBlendFunction.get(0)), DestFactor.valueOf(PuzzleConfig.customBlendFunction.get(1)), SourceFactor.valueOf(PuzzleConfig.customBlendFunction.get(2)), DestFactor.valueOf(PuzzleConfig.customBlendFunction.get(3))); } catch (Exception e) { LOGGER.error("Incorrect blend function defined in color.properties: {}{}", PuzzleConfig.customBlendFunction, e.getMessage()); } } var CUSTOM_LOGO_PIPELINE_BUILDER = RenderPipeline.builder(RenderPipelinesAccessor.getPOSITION_TEX_COLOR_SNIPPET()) .withLocation("pipeline/mojang_logo_puzzle") .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) .withDepthWrite(false); CUSTOM_LOGO_PIPELINE_BUILDER = blendFunction != null ? CUSTOM_LOGO_PIPELINE_BUILDER.withBlend(blendFunction) : CUSTOM_LOGO_PIPELINE_BUILDER.withoutBlend(); CUSTOM_LOGO_PIPELINE = CUSTOM_LOGO_PIPELINE_BUILDER.build(); } } public static class ReloadListener implements SynchronousResourceReloader { public static final ReloadListener INSTANCE = new ReloadListener(); private ReloadListener() {} @Override public void reload(ResourceManager manager) { client = MinecraftClient.getInstance(); if (PuzzleConfig.resourcepackSplashScreen) { PuzzleSplashScreen.resetColors(); client.getTextureManager().registerTexture(LOGO, new LogoTexture(LOGO)); client.getTextureManager().registerTexture(BACKGROUND, new LogoTexture(BACKGROUND)); manager.findResources("optifine", path -> path.getPath().contains("color.properties")).forEach((id, resource) -> { try (InputStream stream = resource.getInputStream()) { Properties properties = new Properties(); properties.load(stream); if (properties.get("screen.loading") != null) { PuzzleConfig.backgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading").toString()).getRGB(); PuzzleConfig.hasCustomSplashScreen = true; } if (properties.get("screen.loading.bar") != null) { PuzzleConfig.progressBarBackgroundColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.bar").toString()).getRGB(); PuzzleConfig.hasCustomSplashScreen = true; } if (properties.get("screen.loading.progress") != null) { PuzzleConfig.progressBarColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.progress").toString()).getRGB(); PuzzleConfig.hasCustomSplashScreen = true; } if (properties.get("screen.loading.outline") != null) { PuzzleConfig.progressFrameColor = MidnightColorUtil.hex2Rgb(properties.get("screen.loading.outline").toString()).getRGB(); PuzzleConfig.hasCustomSplashScreen = true; } if (properties.get("screen.loading.blend") != null) { // Recommended blend: SRC_ALPHA ONE_MINUS_SRC_ALPHA ONE ZERO PuzzleConfig.disableBlend = properties.get("screen.loading.blend").toString().equals("off"); PuzzleConfig.customBlendFunction = new ArrayList<>(Arrays.stream(properties.get("screen.loading.blend").toString().split(" ")).toList()); PuzzleConfig.hasCustomSplashScreen = true; } } catch (Exception e) { LOGGER.error("Error occurred while loading color.properties {}", id.toString(), e); } }); AtomicInteger logoCount = new AtomicInteger(); manager.findResources("textures", path -> path.getPath().contains("mojangstudios.png")).forEach((id, resource) -> { try (InputStream stream = resource.getInputStream()) { Files.copy(stream, LOGO_TEXTURE, StandardCopyOption.REPLACE_EXISTING); client.getTextureManager().registerTexture(LOGO, new DynamicLogoTexture()); if (logoCount.get() > 0) PuzzleConfig.hasCustomSplashScreen = true; logoCount.getAndIncrement(); } catch (Exception e) { LOGGER.error("Error occurred while loading custom minecraft logo {}", id.toString(), e); } }); manager.findResources(MOD_ID, path -> path.getPath().contains("splash_background.png")).forEach((id, resource) -> { try (InputStream stream = resource.getInputStream()) { Files.copy(stream, BACKGROUND_TEXTURE, StandardCopyOption.REPLACE_EXISTING); InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.BACKGROUND_TEXTURE)); client.getTextureManager().registerTexture(BACKGROUND, new NativeImageBackedTexture(() -> "splash_screen_background", NativeImage.read(input))); keepBackground = true; PuzzleConfig.hasCustomSplashScreen = true; } catch (Exception e) { LOGGER.error("Error occurred while loading custom splash background {}", id.toString(), e); } }); if (!keepBackground) { try { Files.delete(BACKGROUND_TEXTURE); } catch (Exception ignored) {} } keepBackground = false; PuzzleConfig.write(MOD_ID); buildRenderLayer(); } } } public static void resetColors() { PuzzleConfig.backgroundColor = 15675965; PuzzleConfig.progressBarColor = 16777215; PuzzleConfig.progressBarBackgroundColor = 15675965; PuzzleConfig.progressFrameColor = 16777215; PuzzleConfig.disableBlend = false; PuzzleConfig.customBlendFunction = new ArrayList<>(); PuzzleConfig.hasCustomSplashScreen = false; } public static class LogoTexture extends ResourceTexture { public LogoTexture(Identifier logo) { super(logo); } @Override public TextureContents loadContents(ResourceManager resourceManager) { MinecraftClient minecraftClient = MinecraftClient.getInstance(); DefaultResourcePack defaultResourcePack = minecraftClient.getDefaultResourcePack(); try { InputStream inputStream = Objects.requireNonNull(defaultResourcePack.open(ResourceType.CLIENT_RESOURCES, LOGO)).get(); TextureContents var6; try { var6 = new TextureContents(NativeImage.read(inputStream), new TextureResourceMetadata(true, true)); } finally { if (inputStream != null) { inputStream.close(); } } return var6; } catch (IOException var18) { return TextureContents.createMissing(); } } } public static class DynamicLogoTexture extends ResourceTexture { public DynamicLogoTexture() { super(LOGO); } @Override public TextureContents loadContents(ResourceManager resourceManager) { try { InputStream input = new FileInputStream(String.valueOf(PuzzleSplashScreen.LOGO_TEXTURE)); return new TextureContents(NativeImage.read(input), new TextureResourceMetadata(true, true)); } catch (IOException e) { LOGGER.error("Encountered an error during logo loading: ", e); try { return TextureContents.load(resourceManager, LOGO); } catch (IOException ex) { return TextureContents.createMissing(); } } } } }