initial: JustASplash 1.21.1 NeoForge me.sashegdev - hotkey Z fullscreen png/gif ogg/mp3 fade 3s
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
package me.sashegdev.justasplash;
|
||||
|
||||
import me.sashegdev.justasplash.client.Hotkey;
|
||||
import me.sashegdev.justasplash.client.SplashManager;
|
||||
import me.sashegdev.justasplash.client.SplashOverlay;
|
||||
import me.sashegdev.justasplash.config.JustASplashConfig;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.config.ModConfig;
|
||||
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
|
||||
|
||||
@Mod(value = "justasplash", dist = Dist.CLIENT)
|
||||
public class JustASplash {
|
||||
public JustASplash(IEventBus modBus, ModContainer container) {
|
||||
container.registerConfig(ModConfig.Type.CLIENT, JustASplashConfig.SPEC);
|
||||
container.registerExtensionPoint(IConfigScreenFactory.class, (c, s) -> JustASplashConfig.createScreen(s));
|
||||
Hotkey.register(modBus);
|
||||
SplashOverlay.register();
|
||||
SplashManager.init();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package me.sashegdev.justasplash.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.sounds.SoundManager;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class AudioPlayer {
|
||||
private static SoundInstance current;
|
||||
|
||||
public static double play(ResourceLocation loc, float vol) {
|
||||
try {
|
||||
var mc = Minecraft.getInstance();
|
||||
var rm = mc.getResourceManager();
|
||||
var res = rm.getResource(loc).orElse(null);
|
||||
double dur = 3.0;
|
||||
if (res != null) {
|
||||
try (InputStream in = res.open()) {
|
||||
dur = probeDuration(in, loc.getPath());
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
SoundEvent ev = SoundEvent.createVariableRangeEvent(loc);
|
||||
current = new SimpleSoundInstance(ev.getLocation(), SoundSource.MASTER, vol, 1.0f, SoundInstance.createUnseededRandom(), false, 0, SoundInstance.Attenuation.NONE, 0, 0, 0, true);
|
||||
mc.getSoundManager().play(current);
|
||||
return dur;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 3.0;
|
||||
}
|
||||
}
|
||||
|
||||
private static double probeDuration(InputStream in, String path) {
|
||||
try {
|
||||
in.mark(Integer.MAX_VALUE);
|
||||
AudioInputStream ais = AudioSystem.getAudioInputStream(in);
|
||||
long frames = ais.getFrameLength();
|
||||
float rate = ais.getFormat().getFrameRate();
|
||||
double sec = frames / rate;
|
||||
if (sec > 0 && sec < 300) return sec;
|
||||
} catch (Exception ignored) {}
|
||||
return path.endsWith(".mp3") ? 5.0 : 3.0;
|
||||
}
|
||||
|
||||
public static void stop() {
|
||||
if (current != null) {
|
||||
Minecraft.getInstance().getSoundManager().stop(current);
|
||||
current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package me.sashegdev.justasplash.client;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class Hotkey {
|
||||
public static KeyMapping SPLASH = new KeyMapping("key.justasplash.splash", GLFW.GLFW_KEY_Z, "key.categories.justasplash");
|
||||
|
||||
public static void register(IEventBus bus) {
|
||||
bus.addListener(Hotkey::onRegister);
|
||||
}
|
||||
|
||||
private static void onRegister(RegisterKeyMappingsEvent e) {
|
||||
e.register(SPLASH);
|
||||
}
|
||||
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public static class Tick {
|
||||
@SubscribeEvent
|
||||
public static void onTick(ClientTickEvent.Post e) {
|
||||
while (SPLASH.consumeClick()) {
|
||||
SplashManager.trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package me.sashegdev.justasplash.client;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ImageLoader {
|
||||
private static ResourceLocation texLoc;
|
||||
private static int w, h;
|
||||
private static List<Frame> frames = List.of();
|
||||
private static int frameIdx = 0;
|
||||
private static long lastFrameMs = 0;
|
||||
|
||||
record Frame(DynamicTexture tex, int delayMs) {}
|
||||
|
||||
public static void load(ResourceLocation loc) {
|
||||
try {
|
||||
var mc = Minecraft.getInstance();
|
||||
var rm = mc.getResourceManager();
|
||||
var res = rm.getResource(loc).orElse(null);
|
||||
if (res == null) return;
|
||||
try (InputStream in = res.open()) {
|
||||
if (loc.getPath().endsWith(".gif")) loadGif(in);
|
||||
else loadPng(in);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadPng(InputStream in) throws Exception {
|
||||
NativeImage img = NativeImage.read(in);
|
||||
w = img.getWidth();
|
||||
h = img.getHeight();
|
||||
DynamicTexture tex = new DynamicTexture(img);
|
||||
texLoc = new ResourceLocation("justasplash", "splash_" + System.nanoTime());
|
||||
Minecraft.getInstance().getTextureManager().register(texLoc, tex);
|
||||
frames = List.of(new Frame(tex, 0));
|
||||
}
|
||||
|
||||
private static void loadGif(InputStream in) throws Exception {
|
||||
ImageReader r = ImageIO.getImageReadersByFormatName("gif").next();
|
||||
r.setInput(ImageIO.createImageInputStream(in));
|
||||
int n = r.getNumImages(true);
|
||||
List<Frame> list = new ArrayList<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
var bi = r.read(i);
|
||||
int delay = 100;
|
||||
try {
|
||||
var meta = r.getImageMetadata(i);
|
||||
var tree = meta.getAsTree("javax_imageio_gif_image_1.0");
|
||||
var gce = tree.getChildNodes();
|
||||
for (int j = 0; j < gce.getLength(); j++) {
|
||||
var node = gce.item(j);
|
||||
if ("GraphicControlExtension".equals(node.getNodeName())) {
|
||||
delay = Integer.parseInt(node.getAttributes().getNamedItem("delayTime").getNodeValue()) * 10;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
NativeImage img = toNativeImage(bi);
|
||||
w = img.getWidth();
|
||||
h = img.getHeight();
|
||||
DynamicTexture tex = new DynamicTexture(img);
|
||||
ResourceLocation loc = new ResourceLocation("justasplash", "splash_gif_" + i + "_" + System.nanoTime());
|
||||
Minecraft.getInstance().getTextureManager().register(loc, tex);
|
||||
list.add(new Frame(tex, delay == 0 ? 100 : delay));
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
frames = list;
|
||||
texLoc = frames.get(0).tex.getTextureLocation();
|
||||
}
|
||||
}
|
||||
|
||||
private static NativeImage toNativeImage(java.awt.image.BufferedImage bi) {
|
||||
int wi = bi.getWidth(), hi = bi.getHeight();
|
||||
NativeImage img = new NativeImage(wi, hi, false);
|
||||
for (int y = 0; y < hi; y++) for (int x = 0; x < wi; x++) {
|
||||
int argb = bi.getRGB(x, y);
|
||||
img.setPixelRGBA(x, y, argb);
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
public static ResourceLocation getTexture() {
|
||||
if (frames.size() <= 1) return texLoc;
|
||||
long now = System.currentTimeMillis();
|
||||
int delay = frames.get(frameIdx).delayMs;
|
||||
if (now - lastFrameMs > delay) {
|
||||
frameIdx = (frameIdx + 1) % frames.size();
|
||||
lastFrameMs = now;
|
||||
texLoc = frames.get(frameIdx).tex.getTextureLocation();
|
||||
}
|
||||
return texLoc;
|
||||
}
|
||||
|
||||
public static int getWidth() { return w; }
|
||||
public static int getHeight() { return h; }
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package me.sashegdev.justasplash.client;
|
||||
|
||||
import me.sashegdev.justasplash.config.JustASplashConfig;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class SplashManager {
|
||||
private static long startMs = 0;
|
||||
private static boolean showing = false;
|
||||
private static double fadeSec = 3.0;
|
||||
private static double audioSec = 0;
|
||||
|
||||
public static void init() {
|
||||
}
|
||||
|
||||
public static void trigger() {
|
||||
var mc = Minecraft.getInstance();
|
||||
if (mc.level == null) return;
|
||||
String img = JustASplashConfig.SPLASH_IMAGE.get();
|
||||
String snd = JustASplashConfig.SPLASH_SOUND.get();
|
||||
fadeSec = JustASplashConfig.FADE.get();
|
||||
double vol = JustASplashConfig.VOLUME.get();
|
||||
ResourceLocation imgLoc = ResourceLocation.tryParse(img);
|
||||
ResourceLocation sndLoc = snd == null || snd.isEmpty() ? null : ResourceLocation.tryParse(snd);
|
||||
if (imgLoc != null) ImageLoader.load(imgLoc);
|
||||
if (sndLoc != null) {
|
||||
audioSec = AudioPlayer.play(sndLoc, (float) vol);
|
||||
} else audioSec = 0;
|
||||
if (fadeSec < 0) fadeSec = audioSec > 0 ? audioSec : 3.0;
|
||||
startMs = System.currentTimeMillis();
|
||||
showing = true;
|
||||
}
|
||||
|
||||
public static boolean isShowing() {
|
||||
if (!showing) return false;
|
||||
double elapsed = (System.currentTimeMillis() - startMs) / 1000.0;
|
||||
if (elapsed >= fadeSec && elapsed >= audioSec) {
|
||||
showing = false;
|
||||
if (audioSec > 0 && elapsed >= audioSec) AudioPlayer.stop();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static float getFadeAlpha() {
|
||||
double elapsed = (System.currentTimeMillis() - startMs) / 1000.0;
|
||||
if (elapsed >= fadeSec) return 0f;
|
||||
return (float) (1.0 - elapsed / fadeSec);
|
||||
}
|
||||
|
||||
public static boolean shouldKeepAudio() {
|
||||
double elapsed = (System.currentTimeMillis() - startMs) / 1000.0;
|
||||
return elapsed < audioSec;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package me.sashegdev.justasplash.client;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.LayeredDraw;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent;
|
||||
|
||||
public class SplashOverlay {
|
||||
public static void register() {
|
||||
}
|
||||
|
||||
@Mod.EventBusSubscriber(value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public static class Reg {
|
||||
@SubscribeEvent
|
||||
public static void onLayers(RegisterGuiLayersEvent e) {
|
||||
e.registerAboveAll(new net.minecraft.resources.ResourceLocation("justasplash", "splash"), SplashOverlay::render);
|
||||
}
|
||||
}
|
||||
|
||||
private static void render(GuiGraphics g, DeltaTracker d) {
|
||||
if (!SplashManager.isShowing()) return;
|
||||
var mc = Minecraft.getInstance();
|
||||
int w = mc.getWindow().getGuiScaledWidth();
|
||||
int h = mc.getWindow().getGuiScaledHeight();
|
||||
float a = SplashManager.getFadeAlpha();
|
||||
if (a <= 0.01f) return;
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.setShaderColor(1, 1, 1, a);
|
||||
var tex = ImageLoader.getTexture();
|
||||
if (tex != null) {
|
||||
int iw = ImageLoader.getWidth();
|
||||
int ih = ImageLoader.getHeight();
|
||||
float scale = Math.min((float) w / iw, (float) h / ih);
|
||||
int dw = (int) (iw * scale);
|
||||
int dh = (int) (ih * scale);
|
||||
int x = (w - dw) / 2;
|
||||
int y = (h - dh) / 2;
|
||||
g.blit(tex, x, y, 0, 0, dw, dh, dw, dh);
|
||||
}
|
||||
RenderSystem.setShaderColor(1, 1, 1, 1);
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package me.sashegdev.justasplash.config;
|
||||
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.neoforged.common.ModConfigSpec;
|
||||
import net.neoforged.neoforge.common.ModConfigSpec.*;
|
||||
|
||||
public class JustASplashConfig {
|
||||
public static final ModConfigSpec SPEC;
|
||||
public static final ConfigValue<String> SPLASH_IMAGE;
|
||||
public static final ConfigValue<String> SPLASH_SOUND;
|
||||
public static final DoubleValue FADE;
|
||||
public static final DoubleValue VOLUME;
|
||||
|
||||
static {
|
||||
Builder b = new Builder();
|
||||
b.push("splash");
|
||||
SPLASH_IMAGE = b.comment("ResourceLocation png|gif in assets/justasplash/ or config/justasplash/ - e.g. justasplash:textures/gui/splashes/splash.png")
|
||||
.define("splashImage", "justasplash:textures/gui/splashes/splash.png");
|
||||
SPLASH_SOUND = b.comment("ResourceLocation ogg|mp3 - e.g. justasplash:sounds/splash.ogg, empty to disable")
|
||||
.define("splashSound", "justasplash:sounds/splash.ogg");
|
||||
FADE = b.comment("Fade duration seconds 100%->0%, -1 = use audio duration, default 3.0")
|
||||
.defineInRange("fade", 3.0, -1.0, 60.0);
|
||||
VOLUME = b.comment("Sound volume 0.0-1.0")
|
||||
.defineInRange("volume", 1.0, 0.0, 1.0);
|
||||
b.pop();
|
||||
SPEC = b.build();
|
||||
}
|
||||
|
||||
public static Screen createScreen(Screen parent) {
|
||||
return new net.neoforged.neoforge.client.gui.ConfigurationScreen(parent, SPEC, "justasplash");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
modLoader="javafml"
|
||||
loaderVersion="[4,)"
|
||||
license="MIT"
|
||||
issueTrackerURL="https://git.swe.zern.cc/sasheg/justasplash-neo/issues"
|
||||
[[mods]]
|
||||
modId="justasplash"
|
||||
version="${mod_version}"
|
||||
displayName="Just A Splash"
|
||||
updateJSONURL="https://git.swe.zern.cc/sasheg/justasplash-neo"
|
||||
displayURL="https://git.swe.zern.cc/sasheg/justasplash-neo"
|
||||
logoFile="justasplash.png"
|
||||
authors="SashegDev"
|
||||
description="Hotkey Z -> fullscreen png/gif + ogg/mp3 splash, 100% -> 0% fade, client only. Fully configurable."
|
||||
[[dependencies.justasplash]]
|
||||
modId="neoforge"
|
||||
type="required"
|
||||
versionRange="[21.1.133,21.2)"
|
||||
ordering="NONE"
|
||||
side="CLIENT"
|
||||
[[dependencies.justasplash]]
|
||||
modId="minecraft"
|
||||
type="required"
|
||||
versionRange="[1.21.1,1.22)"
|
||||
ordering="NONE"
|
||||
side="CLIENT"
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"pack": {
|
||||
"description": "Just A Splash resources",
|
||||
"pack_format": 34,
|
||||
"supported_formats": {"min_inclusive": 34, "max_inclusive": 34}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user