package net.minecraft.client.gui.screens; import com.google.common.collect.Lists; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.util.List; import net.minecraft.ChatFormatting; import net.minecraft.client.GameNarrator; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.LogoRenderer; import net.minecraft.client.renderer.RenderType; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.Music; import net.minecraft.sounds.Musics; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.GsonHelper; import net.minecraft.util.RandomSource; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @OnlyIn(Dist.CLIENT) public class WinScreen extends Screen { private static final ResourceLocation VIGNETTE_LOCATION = ResourceLocation.withDefaultNamespace("textures/misc/credits_vignette.png"); private static final Logger LOGGER = LogUtils.getLogger(); private static final Component SECTION_HEADING = Component.literal("============").withStyle(ChatFormatting.WHITE); private static final String NAME_PREFIX = " "; private static final String OBFUSCATE_TOKEN = "" + ChatFormatting.WHITE + ChatFormatting.OBFUSCATED + ChatFormatting.GREEN + ChatFormatting.AQUA; private static final float SPEEDUP_FACTOR = 5.0F; private static final float SPEEDUP_FACTOR_FAST = 15.0F; private static final ResourceLocation END_POEM_LOCATION = ResourceLocation.withDefaultNamespace("texts/end.txt"); private static final ResourceLocation CREDITS_LOCATION = ResourceLocation.withDefaultNamespace("texts/credits.json"); private static final ResourceLocation POSTCREDITS_LOCATION = ResourceLocation.withDefaultNamespace("texts/postcredits.txt"); private final boolean poem; private final Runnable onFinished; private float scroll; private List lines; private IntSet centeredLines; private int totalScrollLength; private boolean speedupActive; private final IntSet speedupModifiers = new IntOpenHashSet(); private float scrollSpeed; private final float unmodifiedScrollSpeed; private int direction; private final LogoRenderer logoRenderer = new LogoRenderer(false); public WinScreen(boolean p_276286_, Runnable p_276294_) { super(GameNarrator.NO_TITLE); this.poem = p_276286_; this.onFinished = p_276294_; if (!p_276286_) { this.unmodifiedScrollSpeed = 0.75F; } else { this.unmodifiedScrollSpeed = 0.5F; } this.direction = 1; this.scrollSpeed = this.unmodifiedScrollSpeed; } private float calculateScrollSpeed() { return this.speedupActive ? this.unmodifiedScrollSpeed * (5.0F + this.speedupModifiers.size() * 15.0F) * this.direction : this.unmodifiedScrollSpeed * this.direction; } @Override public void tick() { this.minecraft.getMusicManager().tick(); this.minecraft.getSoundManager().tick(false); float f = this.totalScrollLength + this.height + this.height + 24; if (this.scroll > f) { this.respawn(); } } @Override public boolean keyPressed(int p_169469_, int p_169470_, int p_169471_) { if (p_169469_ == 265) { this.direction = -1; } else if (p_169469_ == 341 || p_169469_ == 345) { this.speedupModifiers.add(p_169469_); } else if (p_169469_ == 32) { this.speedupActive = true; } this.scrollSpeed = this.calculateScrollSpeed(); return super.keyPressed(p_169469_, p_169470_, p_169471_); } @Override public boolean keyReleased(int p_169476_, int p_169477_, int p_169478_) { if (p_169476_ == 265) { this.direction = 1; } if (p_169476_ == 32) { this.speedupActive = false; } else if (p_169476_ == 341 || p_169476_ == 345) { this.speedupModifiers.remove(p_169476_); } this.scrollSpeed = this.calculateScrollSpeed(); return super.keyReleased(p_169476_, p_169477_, p_169478_); } @Override public void onClose() { this.respawn(); } private void respawn() { this.onFinished.run(); } @Override protected void init() { if (this.lines == null) { this.lines = Lists.newArrayList(); this.centeredLines = new IntOpenHashSet(); if (this.poem) { this.wrapCreditsIO(END_POEM_LOCATION, this::addPoemFile); } this.wrapCreditsIO(CREDITS_LOCATION, this::addCreditsFile); if (this.poem) { this.wrapCreditsIO(POSTCREDITS_LOCATION, this::addPoemFile); } this.totalScrollLength = this.lines.size() * 12; } } private void wrapCreditsIO(ResourceLocation p_342721_, WinScreen.CreditsReader p_197400_) { try (Reader reader = this.minecraft.getResourceManager().openAsReader(p_342721_)) { p_197400_.read(reader); } catch (Exception exception) { LOGGER.error("Couldn't load credits from file {}", p_342721_, exception); } } private void addPoemFile(Reader p_232818_) throws IOException { BufferedReader bufferedreader = new BufferedReader(p_232818_); RandomSource randomsource = RandomSource.create(8124371L); String s; while ((s = bufferedreader.readLine()) != null) { s = s.replaceAll("PLAYERNAME", this.minecraft.getUser().getName()); int i; while ((i = s.indexOf(OBFUSCATE_TOKEN)) != -1) { String s1 = s.substring(0, i); String s2 = s.substring(i + OBFUSCATE_TOKEN.length()); s = s1 + ChatFormatting.WHITE + ChatFormatting.OBFUSCATED + "XXXXXXXX".substring(0, randomsource.nextInt(4) + 3) + s2; } this.addPoemLines(s); this.addEmptyLine(); } for (int j = 0; j < 8; j++) { this.addEmptyLine(); } } private void addCreditsFile(Reader p_232820_) { for (JsonElement jsonelement : GsonHelper.parseArray(p_232820_)) { JsonObject jsonobject = jsonelement.getAsJsonObject(); String s = jsonobject.get("section").getAsString(); this.addCreditsLine(SECTION_HEADING, true); this.addCreditsLine(Component.literal(s).withStyle(ChatFormatting.YELLOW), true); this.addCreditsLine(SECTION_HEADING, true); this.addEmptyLine(); this.addEmptyLine(); for (JsonElement jsonelement1 : jsonobject.getAsJsonArray("disciplines")) { JsonObject jsonobject1 = jsonelement1.getAsJsonObject(); String s1 = jsonobject1.get("discipline").getAsString(); if (StringUtils.isNotEmpty(s1)) { this.addCreditsLine(Component.literal(s1).withStyle(ChatFormatting.YELLOW), true); this.addEmptyLine(); this.addEmptyLine(); } for (JsonElement jsonelement2 : jsonobject1.getAsJsonArray("titles")) { JsonObject jsonobject2 = jsonelement2.getAsJsonObject(); String s2 = jsonobject2.get("title").getAsString(); JsonArray jsonarray = jsonobject2.getAsJsonArray("names"); this.addCreditsLine(Component.literal(s2).withStyle(ChatFormatting.GRAY), false); for (JsonElement jsonelement3 : jsonarray) { String s3 = jsonelement3.getAsString(); this.addCreditsLine(Component.literal(" ").append(s3).withStyle(ChatFormatting.WHITE), false); } this.addEmptyLine(); this.addEmptyLine(); } } } } private void addEmptyLine() { this.lines.add(FormattedCharSequence.EMPTY); } private void addPoemLines(String p_181398_) { this.lines.addAll(this.minecraft.font.split(Component.literal(p_181398_), 256)); } private void addCreditsLine(Component p_169473_, boolean p_169474_) { if (p_169474_) { this.centeredLines.add(this.lines.size()); } this.lines.add(p_169473_.getVisualOrderText()); } @Override public void render(GuiGraphics p_281907_, int p_282364_, int p_282696_, float p_281316_) { super.render(p_281907_, p_282364_, p_282696_, p_281316_); this.renderVignette(p_281907_); this.scroll = Math.max(0.0F, this.scroll + p_281316_ * this.scrollSpeed); int i = this.width / 2 - 128; int j = this.height + 50; float f = -this.scroll; p_281907_.pose().pushPose(); p_281907_.pose().translate(0.0F, f, 0.0F); this.logoRenderer.renderLogo(p_281907_, this.width, 1.0F, j); int k = j + 100; for (int l = 0; l < this.lines.size(); l++) { if (l == this.lines.size() - 1) { float f1 = k + f - (this.height / 2 - 6); if (f1 < 0.0F) { p_281907_.pose().translate(0.0F, -f1, 0.0F); } } if (k + f + 12.0F + 8.0F > 0.0F && k + f < this.height) { FormattedCharSequence formattedcharsequence = this.lines.get(l); if (this.centeredLines.contains(l)) { p_281907_.drawCenteredString(this.font, formattedcharsequence, i + 128, k, -1); } else { p_281907_.drawString(this.font, formattedcharsequence, i, k, -1); } } k += 12; } p_281907_.pose().popPose(); } private void renderVignette(GuiGraphics p_330215_) { p_330215_.blit(RenderType::vignette, VIGNETTE_LOCATION, 0, 0, 0.0F, 0.0F, this.width, this.height, this.width, this.height); } @Override public void renderBackground(GuiGraphics p_282239_, int p_298581_, int p_297654_, float p_300743_) { if (this.poem) { p_282239_.fillRenderType(RenderType.endPortal(), 0, 0, this.width, this.height, 0); } else { super.renderBackground(p_282239_, p_298581_, p_297654_, p_300743_); } } @Override protected void renderMenuBackground(GuiGraphics p_335873_, int p_330470_, int p_334347_, int p_334935_, int p_329161_) { float f = this.scroll * 0.5F; Screen.renderMenuBackgroundTexture(p_335873_, Screen.MENU_BACKGROUND, 0, 0, 0.0F, f, p_334935_, p_329161_); } @Override public boolean isPauseScreen() { return !this.poem; } @Override public void removed() { this.minecraft.getMusicManager().stopPlaying(Musics.CREDITS); } @Override public Music getBackgroundMusic() { return Musics.CREDITS; } @FunctionalInterface @OnlyIn(Dist.CLIENT) interface CreditsReader { void read(Reader p_232822_) throws IOException; } }