Reset at MSK timezone

This commit is contained in:
2026-04-18 00:21:07 +03:00
parent cbbfc8eca3
commit ee9ef9abd8
6 changed files with 56 additions and 33 deletions

View File

@@ -6,7 +6,7 @@ minecraft_version=1.21.1
loader_version=0.18.5 loader_version=0.18.5
loom_version=1.15-SNAPSHOT loom_version=1.15-SNAPSHOT
mod_version=1.0.0 mod_version=1.0.1
maven_group=net.respawnbackoff maven_group=net.respawnbackoff
fabric_api_version=0.116.10+1.21.1 fabric_api_version=0.116.10+1.21.1

View File

@@ -5,6 +5,7 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.respawnbackoff.CooldownSyncPayload; import net.respawnbackoff.CooldownSyncPayload;
@@ -27,8 +28,28 @@ public class RespawnBackoffClient implements ClientModInitializer {
} }
/** Invoked from a mixin at the end of {@link net.minecraft.client.gui.Gui#render} (HUD + chat). Pause UI and toasts draw later. */ /**
public static void renderPenaltyOverlay(GuiGraphics graphics) { * Invoked from a mixin at the end of {@link net.minecraft.client.renderer.GameRenderer#render} so chat,
* Jade, and other late overlays sit underneath the blackout. Skipped while any screen is open.
*/
public static void renderPenaltyOverlayEndOfFrame() {
if (!overlayActive) {
return;
}
Minecraft client = Minecraft.getInstance();
if (client.player == null || client.screen != null) {
return;
}
MultiBufferSource.BufferSource bufferSource = client.renderBuffers().bufferSource();
GuiGraphics graphics = new GuiGraphics(client, bufferSource);
try {
renderPenaltyOverlay(graphics);
} finally {
graphics.flush();
}
}
private static void renderPenaltyOverlay(GuiGraphics graphics) {
if (!overlayActive) { if (!overlayActive) {
return; return;
} }

View File

@@ -0,0 +1,22 @@
package net.respawnbackoff.mixin;
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.DeltaTracker;
import net.minecraft.client.renderer.GameRenderer;
import net.respawnbackoff.client.RespawnBackoffClient;
/**
* Draw the penalty blackout after the full frame (vanilla HUD, chat, and typical mod overlays like
* Jade). Skip while a {@link net.minecraft.client.gui.screens.Screen} is open so pause menus stay unobstructed.
*/
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Inject(method = "render", at = @At("RETURN"))
private void respawn_backoff$penaltyOverlayLastInFrame(DeltaTracker deltaTracker, boolean tick, CallbackInfo ci) {
RespawnBackoffClient.renderPenaltyOverlayEndOfFrame();
}
}

View File

@@ -1,23 +0,0 @@
package net.respawnbackoff.mixin;
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.DeltaTracker;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiGraphics;
import net.respawnbackoff.client.RespawnBackoffClient;
/**
* Draw the penalty screen after the in-game HUD (including chat). Vanilla then draws the pause
* menu and toasts on top, so we no longer paint over {@link net.minecraft.client.gui.screens.PauseScreen} widgets.
*/
@Mixin(Gui.class)
public class GuiMixin {
@Inject(method = "render", at = @At("RETURN"))
private void respawn_backoff$afterInGameHud(GuiGraphics graphics, DeltaTracker deltaTracker, CallbackInfo ci) {
RespawnBackoffClient.renderPenaltyOverlay(graphics);
}
}

View File

@@ -1,7 +1,7 @@
package net.respawnbackoff; package net.respawnbackoff;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneOffset; import java.time.ZoneId;
import java.util.Collections; import java.util.Collections;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@@ -25,6 +25,9 @@ import net.minecraft.world.level.GameType;
public class RespawnBackoffMod implements ModInitializer { public class RespawnBackoffMod implements ModInitializer {
public static final String MOD_ID = "respawn_backoff"; public static final String MOD_ID = "respawn_backoff";
/** Calendar day for resetting the death-chain exponent: midnight MSK (UTC+3). */
private static final ZoneId DAILY_RESET_ZONE = ZoneId.of("Europe/Moscow");
public static final AttachmentType<RespawnBackoffData> RESPAWN_BACKOFF = AttachmentRegistry.create( public static final AttachmentType<RespawnBackoffData> RESPAWN_BACKOFF = AttachmentRegistry.create(
ResourceLocation.fromNamespaceAndPath(MOD_ID, "state"), ResourceLocation.fromNamespaceAndPath(MOD_ID, "state"),
builder -> builder builder -> builder
@@ -78,12 +81,12 @@ public class RespawnBackoffMod implements ModInitializer {
}); });
} }
private static long currentUtcEpochDay() { private static long currentResetEpochDay() {
return LocalDate.now(ZoneOffset.UTC).toEpochDay(); return LocalDate.now(DAILY_RESET_ZONE).toEpochDay();
} }
static void onPlayerDeath(ServerPlayer player) { static void onPlayerDeath(ServerPlayer player) {
long today = currentUtcEpochDay(); long today = currentResetEpochDay();
RespawnBackoffData data = player.getAttachedOrElse(RESPAWN_BACKOFF, RespawnBackoffData.DEFAULT); RespawnBackoffData data = player.getAttachedOrElse(RESPAWN_BACKOFF, RespawnBackoffData.DEFAULT);
int exponent = data.exponent(); int exponent = data.exponent();
@@ -166,11 +169,11 @@ public class RespawnBackoffMod implements ModInitializer {
} }
/** /**
* Next death uses the minimum wait (1 minute): exponent 0 and today's UTC day recorded. * Next death uses the minimum wait (1 minute): exponent 0 and today's calendar day (MSK) recorded.
* Does not end an active on-screen countdown; use {@link #skipCooldown} for that. * Does not end an active on-screen countdown; use {@link #skipCooldown} for that.
*/ */
public static void resetBackoffChain(ServerPlayer player) { public static void resetBackoffChain(ServerPlayer player) {
long today = currentUtcEpochDay(); long today = currentResetEpochDay();
RespawnBackoffData data = player.getAttachedOrElse(RESPAWN_BACKOFF, RespawnBackoffData.DEFAULT); RespawnBackoffData data = player.getAttachedOrElse(RESPAWN_BACKOFF, RespawnBackoffData.DEFAULT);
RespawnBackoffData next = new RespawnBackoffData( RespawnBackoffData next = new RespawnBackoffData(
0, 0,

View File

@@ -6,7 +6,7 @@
"ServerPlayerGameModeMixin" "ServerPlayerGameModeMixin"
], ],
"client": [ "client": [
"GuiMixin" "GameRendererMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1