clock image
This commit is contained in:
@@ -9,7 +9,7 @@ Minecraft 26.2 uses the unobfuscated Mojang/official names and Java 25. This por
|
||||
|
||||
Run `compiler.bat` on Windows or `./compiler.sh` on Linux/macOS. The script checks whether the existing JAR contains the same `mod_version+mc<minecraft_version>` as `gradle.properties`; matching builds offer Push/Recompile/Quit. After a successful build it offers Git push and retries failed pushes in groups of three.
|
||||
|
||||
## Commands (v0.3.2)
|
||||
## Commands (v0.3.4)
|
||||
|
||||
`/idt reload`
|
||||
|
||||
@@ -17,3 +17,7 @@ Run `compiler.bat` on Windows or `./compiler.sh` on Linux/macOS. The script chec
|
||||
- Client player (operator/moderator): reloads the client config and requests a server-config reload. The server validates permission before accepting the request.
|
||||
- Dedicated-server console: reloads only `item-despawn-timer-server.json`.
|
||||
- The server-side `/idt reload` node requires Minecraft moderator/operator permission, so it is not advertised by the server command tree to ordinary players. The client-side command remains available because ordinary players are allowed to reload their own presentation config.
|
||||
|
||||
## Client display colors
|
||||
|
||||
`clockColor`, `timerTextColor`, and `nameTextColor` use `#RRGGBB` values. The bundled `clock.png` is rendered as a bitmap glyph on the same baseline as the countdown text.
|
||||
|
||||
@@ -1 +1,12 @@
|
||||
{"timerVisible":true,"nameVisible":false,"timerLabelHeight":0.75,"nameLabelHeight":1.1,"useTimerVisibilityThreshold":false,"timerVisibilityThresholdSeconds":300,"timerTextColor":"#FFFFFF","nameTextColor":"#FFFFFF","backgroundAlpha":64}
|
||||
{
|
||||
"timerVisible": true,
|
||||
"nameVisible": false,
|
||||
"timerLabelHeight": 0.75,
|
||||
"nameLabelHeight": 1.1,
|
||||
"useTimerVisibilityThreshold": false,
|
||||
"timerVisibilityThresholdSeconds": 300,
|
||||
"clockColor": "#FFFFFF",
|
||||
"timerTextColor": "#FFFFFF",
|
||||
"nameTextColor": "#FFFFFF",
|
||||
"backgroundAlpha": 64
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@ org.gradle.configuration-cache=false
|
||||
minecraft_version=26.2
|
||||
loader_version=0.19.3
|
||||
fabric_version=0.160.0+26.2
|
||||
mod_version=0.3.2
|
||||
mod_version=0.3.4
|
||||
maven_group=whirlfrenzy.itemdespawntimer
|
||||
archives_base_name=item-despawn-timer
|
||||
|
||||
@@ -2,7 +2,13 @@ package whirlfrenzy.itemdespawntimer.client;
|
||||
import com.google.gson.*; import net.fabricmc.loader.api.FabricLoader; import java.io.*; import java.nio.file.*;
|
||||
public final class ClientConfig {
|
||||
private static final Gson GSON=new GsonBuilder().setPrettyPrinting().create(); public static Data data=new Data();
|
||||
public static final class Data { public boolean timerVisible=true; public boolean nameVisible=false; public float timerLabelHeight=0.75f; public float nameLabelHeight=1.1f; public boolean useTimerVisibilityThreshold=false; public int timerVisibilityThresholdSeconds=300; public String timerTextColor="#FFFFFF"; public String nameTextColor="#FFFFFF"; public int backgroundAlpha=64; }
|
||||
public static final class Data {
|
||||
public boolean timerVisible=true; public boolean nameVisible=false;
|
||||
public float timerLabelHeight=0.75f; public float nameLabelHeight=1.1f;
|
||||
public boolean useTimerVisibilityThreshold=false; public int timerVisibilityThresholdSeconds=300;
|
||||
public String clockColor="#FFFFFF"; public String timerTextColor="#FFFFFF"; public String nameTextColor="#FFFFFF";
|
||||
public int backgroundAlpha=64;
|
||||
}
|
||||
public static void load(){ Path p=FabricLoader.getInstance().getConfigDir().resolve("item-despawn-timer-client.json"); try{if(Files.exists(p)){try(Reader r=Files.newBufferedReader(p)){Data d=GSON.fromJson(r,Data.class);if(d!=null)data=d;}}else{try(Writer w=Files.newBufferedWriter(p)){GSON.toJson(data,w);}}}catch(Exception ignored){}}
|
||||
public static int color(String s){try{return 0xFF000000|Integer.parseInt(s.replace("#",""),16);}catch(Exception e){return 0xFFFFFFFF;}}
|
||||
}
|
||||
|
||||
+43
-8
@@ -4,28 +4,63 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.ItemEntityRenderer;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.client.renderer.entity.state.ItemEntityRenderState;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.FontDescription;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.*;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import whirlfrenzy.itemdespawntimer.client.*;
|
||||
import whirlfrenzy.itemdespawntimer.client.ClientConfig;
|
||||
import whirlfrenzy.itemdespawntimer.client.ClientTimerData;
|
||||
import whirlfrenzy.itemdespawntimer.client.TimerRenderStateAccess;
|
||||
|
||||
@Mixin(ItemEntityRenderer.class)
|
||||
public abstract class ItemEntityRendererMixin {
|
||||
private static final String CLOCK_GLYPH = "\uE000";
|
||||
private static final FontDescription CLOCK_FONT =
|
||||
new FontDescription.Resource(Identifier.fromNamespaceAndPath("item-despawn-timer", "clock"));
|
||||
|
||||
@Inject(method="extractRenderState", at=@At("TAIL"))
|
||||
private void itemDespawnTimer$extract(ItemEntity entity, ItemEntityRenderState state, float partialTick, CallbackInfo ci){ ((TimerRenderStateAccess)(Object)state).itemDespawnTimer$set(entity.getId(),entity.getItem().getHoverName().getString()); }
|
||||
private void itemDespawnTimer$extract(ItemEntity entity, ItemEntityRenderState state, float partialTick, CallbackInfo ci) {
|
||||
((TimerRenderStateAccess)(Object)state).itemDespawnTimer$set(entity.getId(),entity.getItem().getHoverName().getString());
|
||||
}
|
||||
|
||||
@Inject(method="submit", at=@At("TAIL"))
|
||||
private void itemDespawnTimer$submit(ItemEntityRenderState state, PoseStack pose, SubmitNodeCollector queue, CameraRenderState camera, CallbackInfo ci) {
|
||||
TimerRenderStateAccess ext=(TimerRenderStateAccess)(Object)state; ClientTimerData.Timer timer=ClientTimerData.get(ext.itemDespawnTimer$id()); if(timer==null)return;
|
||||
long elapsed=Math.max(0,System.currentTimeMillis()-timer.receivedAtMs()); int age=timer.age()+(int)(elapsed/50L); int remainTicks=timer.lifespan()==Integer.MAX_VALUE?Integer.MAX_VALUE:Math.max(0,timer.lifespan()-age); int seconds=remainTicks==Integer.MAX_VALUE?Integer.MAX_VALUE:(remainTicks+19)/20;
|
||||
TimerRenderStateAccess ext=(TimerRenderStateAccess)(Object)state;
|
||||
ClientTimerData.Timer timer=ClientTimerData.get(ext.itemDespawnTimer$id()); if(timer==null)return;
|
||||
long elapsed=Math.max(0,System.currentTimeMillis()-timer.receivedAtMs());
|
||||
int age=timer.age()+(int)(elapsed/50L);
|
||||
int remainTicks=timer.lifespan()==Integer.MAX_VALUE?Integer.MAX_VALUE:Math.max(0,timer.lifespan()-age);
|
||||
int seconds=remainTicks==Integer.MAX_VALUE?Integer.MAX_VALUE:(remainTicks+19)/20;
|
||||
var cfg=ClientConfig.data; var font=Minecraft.getInstance().font;
|
||||
|
||||
if(cfg.timerVisible && (!cfg.useTimerVisibilityThreshold || seconds<=cfg.timerVisibilityThresholdSeconds)){
|
||||
String s=seconds==Integer.MAX_VALUE?"∞":"◷ "+seconds+"s"; float w=font.width(s); pose.pushPose(); pose.translate(0,cfg.timerLabelHeight,0); pose.mulPose(camera.orientation); pose.scale(0.025f,-0.025f,0.025f); queue.submitText(pose,-w/2f,0,Component.literal(s).getVisualOrderText(),false,net.minecraft.client.gui.Font.DisplayMode.SEE_THROUGH,state.lightCoords,ClientConfig.color(cfg.timerTextColor),(cfg.backgroundAlpha&255)<<24,0); pose.popPose();
|
||||
String countdown=seconds==Integer.MAX_VALUE?"∞":seconds+"s";
|
||||
MutableComponent icon=Component.literal(CLOCK_GLYPH).withStyle(style -> style
|
||||
.withFont(CLOCK_FONT).withColor(ClientConfig.color(cfg.clockColor)&0xFFFFFF));
|
||||
MutableComponent timerText=Component.literal(" "+countdown).withStyle(style -> style
|
||||
.withColor(ClientConfig.color(cfg.timerTextColor)&0xFFFFFF));
|
||||
MutableComponent line=Component.empty().append(icon).append(timerText);
|
||||
float w=font.width(line);
|
||||
pose.pushPose(); pose.translate(0,cfg.timerLabelHeight,0); pose.mulPose(camera.orientation); pose.scale(0.025f,-0.025f,0.025f);
|
||||
queue.submitText(pose,-w/2f,0,line.getVisualOrderText(),false,
|
||||
net.minecraft.client.gui.Font.DisplayMode.SEE_THROUGH,state.lightCoords,
|
||||
0xFFFFFFFF,(cfg.backgroundAlpha&255)<<24,0);
|
||||
pose.popPose();
|
||||
}
|
||||
if(cfg.nameVisible){
|
||||
String s=ext.itemDespawnTimer$name(); float w=font.width(s);
|
||||
pose.pushPose(); pose.translate(0,cfg.nameLabelHeight,0); pose.mulPose(camera.orientation); pose.scale(0.025f,-0.025f,0.025f);
|
||||
queue.submitText(pose,-w/2f,0,Component.literal(s).getVisualOrderText(),false,
|
||||
net.minecraft.client.gui.Font.DisplayMode.SEE_THROUGH,state.lightCoords,
|
||||
ClientConfig.color(cfg.nameTextColor),(cfg.backgroundAlpha&255)<<24,0);
|
||||
pose.popPose();
|
||||
}
|
||||
if(cfg.nameVisible){String s=ext.itemDespawnTimer$name();float w=font.width(s);pose.pushPose();pose.translate(0,cfg.nameLabelHeight,0);pose.mulPose(camera.orientation);pose.scale(0.025f,-0.025f,0.025f);queue.submitText(pose,-w/2f,0,Component.literal(s).getVisualOrderText(),false,net.minecraft.client.gui.Font.DisplayMode.SEE_THROUGH,state.lightCoords,ClientConfig.color(cfg.nameTextColor),(cfg.backgroundAlpha&255)<<24,0);pose.popPose();}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"providers": [
|
||||
{
|
||||
"type": "bitmap",
|
||||
"file": "item-despawn-timer:font/clock.png",
|
||||
"ascent": 8,
|
||||
"height": 9,
|
||||
"chars": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 278 B |
Reference in New Issue
Block a user