1
mirror of https://github.com/Shiewk/BedrockDeathScreen.git synced 2026-04-27 22:44:17 +02:00

Rework death screen buttons

Also makes buttons visually pressed (#3)
This commit is contained in:
Shy
2025-05-25 14:27:30 +02:00
parent bf357349bb
commit b7957807b5
2 changed files with 223 additions and 172 deletions
@@ -1,15 +1,13 @@
package de.shiewk.bedrockdeathscreen.client.screen; package de.shiewk.bedrockdeathscreen.client.screen;
import de.shiewk.bedrockdeathscreen.client.screen.components.BedrockDeathScreenButton;
import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.DeathScreen; import net.minecraft.client.gui.screen.DeathScreen;
import net.minecraft.client.gui.screen.MessageScreen; import net.minecraft.client.gui.screen.MessageScreen;
import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.MutableText; import net.minecraft.text.MutableText;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
@@ -25,13 +23,14 @@ public class BedrockDeathScreen extends DeathScreen {
private Text scoreText = Text.empty(); private Text scoreText = Text.empty();
private static final Text menuMessage = Text.translatable("deathScreen.titleScreen"); private static final Text menuMessage = Text.translatable("deathScreen.titleScreen");
private static final MutableText confirmQuitText = Text.translatable("deathScreen.quit.confirm"); private static final MutableText confirmQuitText = Text.translatable("deathScreen.quit.confirm");
private Text respawnMessage;
private final boolean hardcore; private final boolean hardcore;
private final Identifier SOUND = Identifier.of("minecraft", "ui.button.click");
private final int deg = (int) (Math.random() * 360); private final int deg = (int) (Math.random() * 360);
private boolean confirmingExit = false; private boolean confirmingExit = false;
private boolean wasHoveringButtons = false; private boolean wasHoveringButtons = false;
private BedrockDeathScreenButton respawnButton;
private BedrockDeathScreenButton menuButton;
public BedrockDeathScreen(@Nullable Text message, boolean isHardcore) { public BedrockDeathScreen(@Nullable Text message, boolean isHardcore) {
super(message, isHardcore); super(message, isHardcore);
this.message = message; this.message = message;
@@ -39,142 +38,16 @@ public class BedrockDeathScreen extends DeathScreen {
screenCreationTime = Util.getMeasuringTimeNano(); screenCreationTime = Util.getMeasuringTimeNano();
} }
private boolean hoversRespawn(int mouseX, int mouseY){
int startX = width/2 - 75;
int startY = height - height / 3 - 9;
int endX = width/2 + 75;
int endY = height - height / 3 + 13;
return getTotalScreenTime() > 1050 &&
mouseX > startX &&
mouseX < endX &&
mouseY > startY &&
mouseY < endY;
}
private boolean hoversMenuButton(int mouseX, int mouseY){
final int startX = width/2 - 75;
final int startY = height - height / 3 - 9 + 30;
final int endX = width/2 + 75;
final int endY = height - height / 3 + 13 + 30;
return getTotalScreenTime() > 1050 &&
mouseX > startX &&
mouseX < endX &&
mouseY > startY &&
mouseY < endY;
}
private void renderRespawnButton(DrawContext context, int mouxeX, int mouseY, float opacity){
if ((int) opacity == 0){
return;
}
final int primary = new Color(60, 133, 39, (int) opacity).getRGB();
final int secondary = new Color(29, 77, 19, (int) opacity).getRGB();
final int gaccent = new Color(79, 145, 60, (int) opacity).getRGB();
final int black = new Color(0, 0, 0, (int) opacity).getRGB();
final int textColor = new Color(255, 255, 255, (int) opacity).getRGB();
final boolean mouseHover = hoversRespawn(mouxeX, mouseY);
final int startX = width/2 - 75;
final int startY = height - height / 3 - 9;
final int endX = width/2 + 75;
final int endY = height - height / 3 + 13;
context.fill(startX+2, startY+2, endX-2, endY-1, (mouseHover ? secondary : primary));
context.drawBorder(startX+1, startY+1, (endX-1) - (startX+1), (endY) - (startY+1), gaccent);
context.fill(startX+1, endY, endX-1, endY+3, secondary);
context.drawBorder(startX, startY, (endX) - (startX), (endY+4) - (startY), black);
context.drawCenteredTextWithShadow(textRenderer, respawnMessage, width/2, height - height/3 - 1, textColor);
}
private void renderMenuButton(DrawContext context, int mouxeX, int mouseY, float opacity){
if ((int) opacity == 0){
return;
}
final int primary = new Color(208, 209, 212, (int) opacity).getRGB();
final int secondary = new Color(88, 88, 90, (int) opacity).getRGB();
final int buttonAccent = new Color(177, 178, 181, (int) opacity).getRGB();
final int gaccent = new Color(227, 227, 229, (int) opacity).getRGB();
final int black = new Color(0, 0, 0, (int) opacity).getRGB();
final int textColor = new Color(30, 30, 30, (int) opacity).getRGB();
final boolean mouseHover = hoversMenuButton(mouxeX, mouseY);
final int startX = width/2 - 75;
final int startY = height - height / 3 - 9 + 30;
final int endX = width/2 + 75;
final int endY = height - height / 3 + 13 + 30;
context.fill(startX+2, startY+2, endX-2, endY-1, (mouseHover ? buttonAccent : primary));
context.drawBorder(startX+1, startY+1, (endX-1) - (startX+1), (endY) - (startY+1), gaccent);
context.fill(startX+1, endY, endX-1, endY+3, secondary);
context.drawBorder(startX, startY, (endX) - (startX), (endY+4) - (startY), black);
context.drawText(textRenderer, menuMessage, (width/2) - (textRenderer.getWidth(menuMessage)/2), height - height/3 - 1 + 31, textColor, false);
}
private void renderConfirmRespawnButton(DrawContext context, int mouxeX, int mouseY){
final int primary = new Color(60, 133, 39, (int) (float) 255.0).getRGB();
final int secondary = new Color(29, 77, 19, (int) (float) 255.0).getRGB();
final int gaccent = new Color(79, 145, 60, (int) (float) 255.0).getRGB();
final int black = new Color(0, 0, 0, (int) (float) 255.0).getRGB();
final int textColor = new Color(255, 255, 255, (int) (float) 255.0).getRGB();
final boolean mouseHover = hoversMenuButton(mouxeX, mouseY);
final int startX = width/2 - 75;
final int startY = height - height / 3 - 9 + 30;
final int endX = width/2 + 75;
final int endY = height - height / 3 + 13 + 30;
context.fill(startX+2, startY+2, endX-2, endY-1, (mouseHover ? secondary : primary));
context.drawBorder(startX+1, startY+1, (endX-1) - (startX+1), (endY) - (startY+1), gaccent);
context.fill(startX+1, endY, endX-1, endY+3, secondary);
context.drawBorder(startX, startY, (endX) - (startX), (endY+4) - (startY), black);
context.drawText(textRenderer, respawnMessage, (width/2) - (textRenderer.getWidth(respawnMessage)/2), height - height/3 - 1 + 30, textColor, false);
}
private void renderConfirmQuitButton(DrawContext context, int mouxeX, int mouseY){
final int primary = new Color(208, 209, 212, (int) (float) 255.0).getRGB();
final int secondary = new Color(88, 88, 90, (int) (float) 255.0).getRGB();
final int buttonAccent = new Color(177, 178, 181, (int) (float) 255.0).getRGB();
final int gaccent = new Color(227, 227, 229, (int) (float) 255.0).getRGB();
final int black = new Color(0, 0, 0, (int) (float) 255.0).getRGB();
final int textColor = new Color(30, 30, 30, (int) (float) 255.0).getRGB();
final boolean mouseHover = hoversRespawn(mouxeX, mouseY);
final int startX = width/2 - 75;
final int startY = height - height / 3 - 9;
final int endX = width/2 + 75;
final int endY = height - height / 3 + 13;
context.fill(startX+2, startY+2, endX-2, endY-1, (mouseHover ? buttonAccent : primary));
context.drawBorder(startX+1, startY+1, (endX-1) - (startX+1), (endY) - (startY+1), gaccent);
context.fill(startX+1, endY, endX-1, endY+3, secondary);
context.drawBorder(startX, startY, (endX) - (startX), (endY+4) - (startY), black);
context.drawText(textRenderer, menuMessage, (width/2) - (textRenderer.getWidth(menuMessage)/2), height - height/3 - 1, textColor, false);
}
public float getTotalScreenTime(){ public float getTotalScreenTime(){
return (Util.getMeasuringTimeNano() - screenCreationTime) / 1000000f; return (Util.getMeasuringTimeNano() - screenCreationTime) / 1000000f;
} }
@Override @Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) { public void render(DrawContext context, int mouseX, int mouseY, float delta) {
boolean hoveringButton = hoversMenuButton(mouseX, mouseY) || hoversRespawn(mouseX, mouseY);
if (hoveringButton != wasHoveringButtons){
wasHoveringButtons = hoveringButton;
assert client != null;
long window = client.getWindow().getHandle();
if (hoveringButton){
GLFW.glfwSetCursor(window, CURSOR_HAND);
} else {
GLFW.glfwSetCursor(window, 0);
}
}
final float totalScreenTime = getTotalScreenTime(); final float totalScreenTime = getTotalScreenTime();
context.fill(0, 0, width, height, new Color(0, 0, 0, (int) Math.min(80, totalScreenTime/4f)).getRGB()); context.fill(0, 0, width, height, new Color(0, 0, 0, (int) Math.min(80, totalScreenTime/4f)).getRGB());
if (totalScreenTime > 750.0f){ if (totalScreenTime > 750.0f){
final int backOpacity = (int) Math.min(255, (totalScreenTime - 750f) / 10f); final int backOpacity = (int) Math.min(255, (totalScreenTime - 750f) / 10f);
context.fill(0, 0, width, height, new Color(155, 0, 0, (int) (backOpacity/2.5)).getRGB()); context.fill(0, 0, width, height, new Color(155, 0, 0, (int) (backOpacity/2.5)).getRGB());
@@ -194,66 +67,88 @@ public class BedrockDeathScreen extends DeathScreen {
context.drawCenteredTextWithShadow(this.textRenderer, this.scoreText, this.width / 2, (int) (this.height / 3.5) + 12, new Color(255, 255, 255, scoreTextOpacity).getRGB()); context.drawCenteredTextWithShadow(this.textRenderer, this.scoreText, this.width / 2, (int) (this.height / 3.5) + 12, new Color(255, 255, 255, scoreTextOpacity).getRGB());
} }
} }
if (!confirmingExit){
if (totalScreenTime > 1259f){ if (confirmingExit){
float respawnOpacity = (int) Math.min(255, (totalScreenTime - 1250f) / 3f);
renderRespawnButton(context, mouseX, mouseY, respawnOpacity);
}
if (totalScreenTime > 1759f){
float menuOpacity = (int) Math.min(255, (totalScreenTime - 1750f) / 3f);
renderMenuButton(context, mouseX, mouseY, menuOpacity);
}
} else {
context.drawCenteredTextWithShadow(this.textRenderer, BedrockDeathScreen.confirmQuitText, this.width / 2, this.height - this.height / 3 - 9 - 12, new Color(255, 255, 255, 255).getRGB()); context.drawCenteredTextWithShadow(this.textRenderer, BedrockDeathScreen.confirmQuitText, this.width / 2, this.height - this.height / 3 - 9 - 12, new Color(255, 255, 255, 255).getRGB());
renderConfirmRespawnButton(context, mouseX, mouseY); }
renderConfirmQuitButton(context, mouseX, mouseY); respawnButton.render(context, mouseX, mouseY, delta);
menuButton.render(context, mouseX, mouseY, delta);
boolean hoveringButton = menuButton.isHovered() || respawnButton.isHovered();
if (hoveringButton != wasHoveringButtons){
wasHoveringButtons = hoveringButton;
assert client != null;
long window = client.getWindow().getHandle();
if (hoveringButton){
GLFW.glfwSetCursor(window, CURSOR_HAND);
} else {
GLFW.glfwSetCursor(window, 0);
}
} }
} }
@Override @Override
protected void init() { protected void init() {
this.respawnMessage = this.hardcore ? Text.translatable("deathScreen.spectate") : Text.translatable("deathScreen.respawn"); Text respawnMessage = this.hardcore ? Text.translatable("deathScreen.spectate") : Text.translatable("deathScreen.respawn");
if (this.client != null && this.client.player != null) { if (this.client != null && this.client.player != null) {
this.scoreText = Text.translatable("deathScreen.score.value", Text.literal(Integer.toString(this.client.player.getScore())).formatted(Formatting.YELLOW)); this.scoreText = Text.translatable("deathScreen.score.value", Text.literal(Integer.toString(this.client.player.getScore())).formatted(Formatting.YELLOW));
} }
respawnButton = new BedrockDeathScreenButton(
width / 2 - 75,
height - height / 3 - 9,
150,
22,
respawnMessage,
textRenderer,
0x3c8527,
0x1d4d13,
0x4f913c,
0x1d4d13,
0xffffff,
0x1d4d13,
0x4a7142,
true,
() -> (int) Math.min(255, (getTotalScreenTime() - 1250f) / 3f),
this::respawn
);
menuButton = new BedrockDeathScreenButton(
width / 2 - 75,
height - height / 3 + 21,
150,
22,
menuMessage,
textRenderer,
0xd0d1d4,
0x58585a,
0xe3e3e5,
0xb1b2b5,
0x1e1e1e,
0xb1b2b5,
0xe0e0e1,
false,
() -> (int) Math.min(255, (getTotalScreenTime() - 1750f) / 3f),
this::clickQuitButton
);
} }
private void respawn(){ private void respawn(){
if (this.client != null && this.client.player != null) { if (this.client != null && this.client.player != null) {
this.client.player.requestRespawn(); this.client.player.requestRespawn();
} }
playUISound();
}
private void playUISound() {
if (this.client != null) {
if (this.client.player != null) {
this.client.player.playSoundToPlayer(SoundEvent.of(SOUND), SoundCategory.MASTER, .75f, 1f);
}
}
} }
@Override @Override
public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (hoversRespawn((int) mouseX, (int) mouseY)){ if (respawnButton.mouseClicked(mouseX, mouseY, button)) return true;
if (!confirmingExit){ return menuButton.mouseClicked(mouseX, mouseY, button);
respawn(); }
} else {
playUISound(); @Override
quitLevel(); public boolean mouseReleased(double mouseX, double mouseY, int button) {
} respawnButton.mouseReleased(mouseX, mouseY, button);
return true; menuButton.mouseReleased(mouseX, mouseY, button);
} else if (hoversMenuButton((int) mouseX, (int) mouseY)){ return true;
if (!confirmingExit){
playUISound();
this.confirmingExit = true;
} else {
respawn();
}
return true;
}
return false;
} }
private void quitLevel(){ private void quitLevel(){
@@ -296,4 +191,18 @@ public class BedrockDeathScreen extends DeathScreen {
GLFW.glfwSetCursor(window, 0); GLFW.glfwSetCursor(window, 0);
super.removed(); super.removed();
} }
private void clickQuitButton() {
if (confirmingExit) {
this.quitLevel();
} else {
confirmingExit = true;
int y = menuButton.getY();
menuButton.setY(respawnButton.getY());
respawnButton.setY(y);
menuButton.resetClickedState();
respawnButton.resetClickedState();
}
}
} }
@@ -0,0 +1,142 @@
package de.shiewk.bedrockdeathscreen.client.screen.components;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.sound.SoundManager;
import net.minecraft.text.Text;
import java.util.function.IntSupplier;
public class BedrockDeathScreenButton extends ClickableWidget {
public static final int colorBlack = 0x000000;
public final TextRenderer textRenderer;
public final int colorPrimary;
public final int colorSecondary;
public final int colorBorder;
public final int colorHover;
public final int colorText;
public final int colorPrimaryPressed;
public final int colorBorderPressed;
public final boolean textShadow;
public final IntSupplier opacitySupplier;
public final Runnable clickAction;
private boolean pressed = false;
private boolean clicked = false;
public BedrockDeathScreenButton(
int x, int y, int width, int height,
Text message, TextRenderer textRenderer,
int colorPrimary, int colorSecondary,
int colorBorder, int colorHover,
int colorText, int colorPrimaryPressed, int colorBorderPressed, boolean textShadow,
IntSupplier opacitySupplier, Runnable clickAction
) {
super(x, y, width, height, message);
this.textRenderer = textRenderer;
this.colorPrimary = colorPrimary;
this.colorSecondary = colorSecondary;
this.colorBorder = colorBorder;
this.colorHover = colorHover;
this.colorText = colorText;
this.colorPrimaryPressed = colorPrimaryPressed;
this.colorBorderPressed = colorBorderPressed;
this.textShadow = textShadow;
this.opacitySupplier = opacitySupplier;
this.clickAction = clickAction;
}
public int changeColorOpacity(int color, int opacity){
return (color & 0x00ffffff) | (opacity << 24);
}
@Override
protected void renderWidget(DrawContext context, int mouseX, int mouseY, float deltaTicks) {
final boolean mouseHover = isHovered();
final int opacity = getOpacity();
if (opacity < 4) return;
final int startX = getX();
final int startY = getY();
final int endX = getX() + getWidth();
final int endY = getY() + getHeight();
boolean shouldAppearPressed = pressed || clicked;
if (shouldAppearPressed){
context.fill(startX+2, startY+4, endX-2, endY+2, changeColorOpacity(colorPrimaryPressed, opacity));
context.drawBorder(startX+1, startY+3, (endX-1) - (startX+1), (endY+1) - (startY+1), changeColorOpacity(colorBorderPressed, opacity));
context.drawBorder(startX, startY+2, endX - startX, (endY+2) - startY, changeColorOpacity(colorBlack, opacity));
} else {
context.fill(startX+2, startY+2, endX-2, endY-1, (mouseHover ? changeColorOpacity(colorHover, opacity) : changeColorOpacity(colorPrimary, opacity)));
context.drawBorder(startX+1, startY+1, (endX-1) - (startX+1), (endY) - (startY+1), changeColorOpacity(colorBorder, opacity));
context.fill(startX+1, endY, endX-1, endY+3, changeColorOpacity(colorSecondary, opacity));
context.drawBorder(startX, startY, endX - startX, (endY+4) - startY, changeColorOpacity(colorBlack, opacity));
}
if (textShadow){
context.drawCenteredTextWithShadow(
textRenderer,
getMessage(),
startX+getWidth()/2,
endY - getHeight()/2 - (shouldAppearPressed ? 1 : 3),
changeColorOpacity(colorText, opacity)
);
} else {
context.drawText(
textRenderer,
getMessage(),
startX + (getWidth()/2) - (textRenderer.getWidth(getMessage())/2),
endY - getHeight()/2 - (shouldAppearPressed ? 1 : 3),
changeColorOpacity(colorText, opacity),
false
);
}
}
@Override
public void onClick(double mouseX, double mouseY) {
pressed = true;
}
@Override
public void onRelease(double mouseX, double mouseY) {
if (pressed && hovered) {
clicked = true;
clickAction.run();
}
pressed = false;
}
@Override
public void playDownSound(SoundManager soundManager) {
if (!clicked) super.playDownSound(soundManager);
}
@Override
protected void appendClickableNarrations(NarrationMessageBuilder builder) {}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (getOpacity() > 0){
return super.mouseClicked(mouseX, mouseY, button);
} else {
return false;
}
}
public void resetClickedState() {
clicked = false;
}
public int getOpacity(){
return opacitySupplier.getAsInt();
}
@Override
public boolean isHovered() {
return super.isHovered() && getOpacity() > 0;
}
}