SetScreen mixin

This commit is contained in:
2026-02-20 17:35:59 +01:00
parent 365063e8d5
commit 039d2cd032
6 changed files with 119 additions and 77 deletions
@@ -0,0 +1,35 @@
package org.saturnclient.saturnclient.mixin;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui2.screens.TitleMenu;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen;
@Mixin(MinecraftClient.class)
public class SetScreenMixin {
private boolean replacingScreen = false;
@Inject(method = "setScreen", at = @At("HEAD"), cancellable = true)
private void onSetScreen(Screen screen, CallbackInfo ci) {
if (replacingScreen)
return;
@SuppressWarnings("resource") // False positive bc MinecraftClient has close()
MinecraftClient client = ((MinecraftClient) (Object) this);
if (SaturnClientConfig.saturnTitleScreen.value
&& ((screen == null && client.world == null) || screen instanceof TitleScreen)) {
replacingScreen = true;
client.setScreen(new TitleMenu());
ci.cancel();
replacingScreen = false;
}
}
}
@@ -51,71 +51,96 @@ public abstract class SplashOverlayMixin {
} }
/** /**
* @author SaturnClient
* @reason Replace vanilla splash rendering completely but keep exit logic * @reason Replace vanilla splash rendering completely but keep exit logic
*/ */
@Overwrite @Overwrite
public void render(DrawContext context, int mouseX, int mouseY, float delta) { public void render(DrawContext context, int mouseX, int mouseY, float delta) {
int width = context.getScaledWindowWidth(); int screenWidth = context.getScaledWindowWidth();
int height = context.getScaledWindowHeight(); int screenHeight = context.getScaledWindowHeight();
long currentTime = Util.getMeasuringTimeMs(); long currentTime = Util.getMeasuringTimeMs();
// Handle reload start timing (vanilla uses 500ms fade-in) // Initialize reload start time if not set
if (this.reloadStartTime == -1L) { if (reloadStartTime == -1L) {
this.reloadStartTime = currentTime; reloadStartTime = currentTime;
} }
// Compute fade-out timing // Compute fade-out progress after reload completes
float f = this.reloadCompleteTime > -1L ? (float) (currentTime - this.reloadCompleteTime) / 1000f : -1f; float fadeOutProgress = reloadCompleteTime > -1L
? (float) (currentTime - reloadCompleteTime) / 1000f
: -1f;
int alpha = f >= 0f int logoAlpha = fadeOutProgress >= 0f
? MathHelper.ceil((1.0f - MathHelper.clamp(f - 1f, 0f, 1f)) * 255f) ? MathHelper.ceil((1.0f - MathHelper.clamp(fadeOutProgress - 1f, 0f, 1f)) * 255f)
: 255; : 255;
long l = Util.getMeasuringTimeMs(); // Compute fade-in progress while reloading
float g = this.reloadStartTime > -1L ? (float) (l - this.reloadStartTime) / 500.0F : -1.0F; float reloadProgress = reloadStartTime > -1L
? (float) (currentTime - reloadStartTime) / 500f
: -1f;
int k; // Draw background overlay
if (fadeOutProgress >= 1.0F) {
if (f >= 1.0F) { renderCurrentScreen(context, mouseX, mouseY, delta);
if (this.client.currentScreen != null) { int overlayAlpha = computeOverlayAlpha(fadeOutProgress - 1f);
this.client.currentScreen.render(context, 0, 0, delta); context.fill(RenderLayer.getGuiOverlay(), 0, 0, screenWidth, screenHeight,
withAlpha(0x28282B, overlayAlpha));
} else if (reloading) {
if (reloadProgress < 1.0F) {
renderCurrentScreen(context, mouseX, mouseY, delta);
} }
int overlayAlpha = MathHelper.ceil(MathHelper.clamp(reloadProgress, 0.15, 1.0) * 255.0);
k = MathHelper.ceil((1.0F - MathHelper.clamp(f - 1.0F, 0.0F, 1.0F)) * context.fill(RenderLayer.getGuiOverlay(), 0, 0, screenWidth, screenHeight,
255.0F); withAlpha(0x28282B, overlayAlpha));
context.fill(RenderLayer.getGuiOverlay(), 0, 0, width, height,
withAlpha(0x28282B, k));
} else if (this.reloading) {
if (this.client.currentScreen != null && g < 1.0F) {
this.client.currentScreen.render(context, mouseX, mouseY, delta);
}
k = MathHelper.ceil(MathHelper.clamp((double) g, 0.15, 1.0) * 255.0);
context.fill(RenderLayer.getGuiOverlay(), 0, 0, width, height,
withAlpha(0x28282B, k));
} }
// Draw central logo
drawLogo(context, screenWidth, screenHeight, logoAlpha);
// Remove overlay after fade-out completes
if (fadeOutProgress >= 2.0F) {
client.setOverlay(null);
}
// Handle reload completion and exceptions
handleReloadCompletion(context);
}
private void renderCurrentScreen(DrawContext context, int mouseX, int mouseY, float delta) {
if (client.currentScreen != null) {
client.currentScreen.render(context, mouseX, mouseY, delta);
}
}
/** Draw the main logo centered */
private void drawLogo(DrawContext context, int screenWidth, int screenHeight, int alpha) {
RenderScope scope = new RenderScope(context); RenderScope scope = new RenderScope(context);
scope.setRenderLayer(RenderLayer::getGuiTextured); scope.setRenderLayer(RenderLayer::getGuiTextured);
scope.drawTexture(Textures.LOGO, width / 2 - 49, height / 2 - 49, 0, 0, 98, 98, withAlpha(0xFFFFFF, alpha)); scope.drawTexture(Textures.LOGO, screenWidth / 2 - 49, screenHeight / 2 - 49, 0, 0, 98, 98,
withAlpha(0xFFFFFF, alpha));
}
if (f >= 2.0F) { /** Compute overlay alpha from fade progress */
this.client.setOverlay(null); private int computeOverlayAlpha(float progress) {
} return MathHelper.ceil((1.0F - MathHelper.clamp(progress, 0.0F, 1.0F)) * 255.0F);
}
if (this.reloadCompleteTime == -1L && this.reload.isComplete() && (!this.reloading || g >= 2.0F)) { /** Handle reload completion logic */
private void handleReloadCompletion(DrawContext context) {
float reloadProgress = reloadStartTime > -1L ? (float) (Util.getMeasuringTimeMs() - reloadStartTime) / 500f
: -1f;
if (reloadCompleteTime == -1L && reload.isComplete() && (!reloading || reloadProgress >= 2.0F)) {
try { try {
this.reload.throwException(); reload.throwException();
this.exceptionHandler.accept(Optional.empty()); exceptionHandler.accept(Optional.empty());
} catch (Throwable var24) { } catch (Throwable ex) {
this.exceptionHandler.accept(Optional.of(var24)); exceptionHandler.accept(Optional.of(ex));
} }
this.reloadCompleteTime = Util.getMeasuringTimeMs(); reloadCompleteTime = Util.getMeasuringTimeMs();
if (this.client.currentScreen != null) {
this.client.currentScreen.init(this.client, context.getScaledWindowWidth(), if (client.currentScreen != null) {
context.getScaledWindowHeight()); client.currentScreen.init(client, context.getScaledWindowWidth(), context.getScaledWindowHeight());
} }
} }
} }
@@ -1,22 +0,0 @@
package org.saturnclient.saturnclient.mixin;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui2.screens.TitleMenu;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.gui.screen.TitleScreen;
@Mixin(TitleScreen.class)
public class TitleScreenMixin {
@Inject(method = "init", at = @At("HEAD"), cancellable = true)
private void onInit(CallbackInfo ci) {
if (SaturnClientConfig.saturnTitleScreen.value) {
SaturnClient.client.setScreen(new TitleMenu());
ci.cancel();
}
}
}
@@ -22,6 +22,7 @@ import net.minecraft.util.Identifier;
public abstract class SaturnScreen extends Screen { public abstract class SaturnScreen extends Screen {
private final Pool pool = new Pool(3); private final Pool pool = new Pool(3);
protected List<Element> elements = new ArrayList<>(); protected List<Element> elements = new ArrayList<>();
protected float backgroundOpacity = 1.0f;
public int blurDuration = 700; public int blurDuration = 700;
public float blurProgress = 0.0f; public float blurProgress = 0.0f;
public int backgroundBlur = 10; public int backgroundBlur = 10;
@@ -43,7 +44,7 @@ public abstract class SaturnScreen extends Screen {
synchronized (elements) { synchronized (elements) {
elements.add(element); elements.add(element);
} }
if (element.animation != null) { if (element.animation != null) {
element.animation.init(element); element.animation.init(element);
@@ -93,16 +94,16 @@ public abstract class SaturnScreen extends Screen {
mouseY *= 2; mouseY *= 2;
if (client.world == null && client.getCurrentServerEntry() == null) { if (client.world == null && client.getCurrentServerEntry() == null) {
ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, 1.0F, delta); ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, backgroundOpacity, delta);
} }
PostEffectProcessor postEffectProcessor = this.client.getShaderLoader().loadPostEffect( PostEffectProcessor postEffectProcessor = this.client.getShaderLoader().loadPostEffect(
Identifier.ofVanilla("blur"), Identifier.ofVanilla("blur"),
DefaultFramebufferSet.MAIN_ONLY); DefaultFramebufferSet.MAIN_ONLY);
if (postEffectProcessor != null) { if (postEffectProcessor != null) {
postEffectProcessor.setUniforms("Radius", backgroundBlur * blurProgress); postEffectProcessor.setUniforms("Radius", backgroundBlur * blurProgress);
postEffectProcessor.render(this.client.getFramebuffer(), this.pool); postEffectProcessor.render(this.client.getFramebuffer(), this.pool);
} }
// We are using a Abstracted RenderScope because older minecraft versions don't // We are using a Abstracted RenderScope because older minecraft versions don't
// use DrawContext // use DrawContext
@@ -20,14 +20,17 @@ import net.minecraft.client.gui.screen.world.SelectWorldScreen;
public class TitleMenu extends SaturnScreen { public class TitleMenu extends SaturnScreen {
public TitleMenu() { public TitleMenu() {
super("Tile Menu"); super("Tile Menu");
this.backgroundOpacity = 0.0f;
} }
@Override @Override
public void ui() { public void ui() {
backgroundBlur = 0; backgroundBlur = 0;
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).centerOffset(width, height, 0, -36).animation(new Fade(700))); draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).centerOffset(width, height, 0, -36)
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -82).animation(new SlideY(700, -20))); .animation(new Fade(700)));
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -82)
.animation(new SlideY(700, -20)));
draw(new Button("SINGLEPLAYER", () -> { draw(new Button("SINGLEPLAYER", () -> {
client.setScreen(new SelectWorldScreen(new TitleMenu())); client.setScreen(new SelectWorldScreen(new TitleMenu()));
+2 -2
View File
@@ -9,8 +9,8 @@
"PlayerEntityRendererMixin", "PlayerEntityRendererMixin",
"WhoAmI", "WhoAmI",
"DrawContextAccessor", "DrawContextAccessor",
"TitleScreenMixin", "SplashOverlayMixin",
"SplashOverlayMixin" "SetScreenMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1