Improve Media Handler API

- Also fix logspam
This commit is contained in:
Martin Prokoph
2024-07-07 18:54:15 +02:00
parent 9c550dcd7d
commit 3b3009fefb
8 changed files with 115 additions and 51 deletions

View File

@@ -2,6 +2,10 @@ package eu.midnightdust.picturesign;
import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.lib.util.PlatformFunctions;
import eu.midnightdust.picturesign.config.PictureSignConfig; import eu.midnightdust.picturesign.config.PictureSignConfig;
import eu.midnightdust.picturesign.util.GIFHandler;
import eu.midnightdust.picturesign.util.MediaHandler;
import eu.midnightdust.picturesign.util.WaterGIFHandler;
import eu.midnightdust.picturesign.util.WaterMediaHandler;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.KeyBinding; import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
@@ -21,6 +25,10 @@ public class PictureSignClient {
public static void init() { public static void init() {
PictureSignConfig.init(MOD_ID, PictureSignConfig.class); PictureSignConfig.init(MOD_ID, PictureSignConfig.class);
if (hasWaterMedia) {
MediaHandler.registerHandler(WaterMediaHandler::new);
GIFHandler.registerHandler(WaterGIFHandler::new);
}
} }
public static Identifier id(String path) { public static Identifier id(String path) {
return Identifier.of(MOD_ID, path); return Identifier.of(MOD_ID, path);

View File

@@ -38,7 +38,6 @@ import org.joml.Matrix4f;
import java.util.Iterator; import java.util.Iterator;
import static eu.midnightdust.picturesign.PictureSignClient.client; import static eu.midnightdust.picturesign.PictureSignClient.client;
import static eu.midnightdust.picturesign.PictureSignClient.hasWaterMedia;
import static eu.midnightdust.picturesign.PictureSignClient.id; import static eu.midnightdust.picturesign.PictureSignClient.id;
import static eu.midnightdust.picturesign.util.PictureSignType.GIF; import static eu.midnightdust.picturesign.util.PictureSignType.GIF;
import static eu.midnightdust.picturesign.util.PictureSignType.PICTURE; import static eu.midnightdust.picturesign.util.PictureSignType.PICTURE;
@@ -96,9 +95,9 @@ public class PictureRenderer {
MediaHandler mediaHandler = null; MediaHandler mediaHandler = null;
GIFHandler gifHandler = null; GIFHandler gifHandler = null;
if (errorMessage == null && MediaHandler.hasValidImplementation()) { if (errorMessage == null) {
if (type.isVideo || type.isAudio) mediaHandler = MediaHandler.getOrCreate(videoId, pos); if ((type.isVideo || type.isAudio) && MediaHandler.hasValidImplementation()) mediaHandler = MediaHandler.getOrCreate(videoId, pos);
else if (type == GIF && hasWaterMedia) gifHandler = GIFHandler.getOrCreate(videoId); else if (type == GIF && GIFHandler.hasValidImplementation()) gifHandler = GIFHandler.getOrCreate(videoId);
else { else {
MediaHandler.closePlayer(videoId); MediaHandler.closePlayer(videoId);
GIFHandler.closePlayer(videoId); GIFHandler.closePlayer(videoId);
@@ -107,8 +106,6 @@ public class PictureRenderer {
if (isDisabledViaRedstone(blockEntity.getWorld(), pos)) { if (isDisabledViaRedstone(blockEntity.getWorld(), pos)) {
if (mediaHandler != null && mediaHandler.isWorking() && !mediaHandler.isStopped()) mediaHandler.stop(); if (mediaHandler != null && mediaHandler.isWorking() && !mediaHandler.isStopped()) mediaHandler.stop();
//PictureURLUtils.cachedJsonData.remove(url);
return; return;
} }
else if (mediaHandler != null && mediaHandler.isDeactivated) { else if (mediaHandler != null && mediaHandler.isDeactivated) {
@@ -126,8 +123,7 @@ public class PictureRenderer {
if (!mediaHandler.playbackStarted && !mediaHandler.hasMedia()) { if (!mediaHandler.playbackStarted && !mediaHandler.hasMedia()) {
mediaHandler.play(url, type.isVideo); mediaHandler.play(url, type.isVideo);
if (info != null && info.start() > 0) mediaHandler.setTime(info.start()); if (info != null && info.start() > 0) mediaHandler.setTime(info.start());
if (type.isLooped && !mediaHandler.hasMedia() && !mediaHandler.playbackStarted) mediaHandler.setRepeat(type.isLooped);
mediaHandler.setRepeat(true);
} }
if (info != null && info.volume() >= 0) mediaHandler.setMaxVolume(info.volume()); if (info != null && info.volume() >= 0) mediaHandler.setMaxVolume(info.volume());

View File

@@ -1,64 +1,63 @@
package eu.midnightdust.picturesign.util; package eu.midnightdust.picturesign.util;
import me.srrapero720.watermedia.api.image.ImageAPI;
import me.srrapero720.watermedia.api.image.ImageCache;
import me.srrapero720.watermedia.api.math.MathAPI;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import static eu.midnightdust.picturesign.PictureSignClient.client; import java.util.function.Function;
public class GIFHandler { public class GIFHandler {
public static Map<Identifier, GIFHandler> gifPlayers = new HashMap<>(); private static final List<Function<Identifier, GIFHandler>> implementations = new ArrayList<>();
public static Map<Identifier, GIFHandler> gifHandlers = new HashMap<>();
public final Identifier id; public final Identifier id;
public boolean playbackStarted; public boolean playbackStarted;
private ImageCache player;
private long tick = 0L;
private GIFHandler(Identifier id) { public GIFHandler(Identifier id) {
System.out.println("New GIF handler :" + id);
this.id = id; this.id = id;
gifPlayers.put(id, this); gifHandlers.put(id, this);
}
public static void registerHandler(Function<Identifier, GIFHandler> handler) {
implementations.add(handler);
}
public static boolean hasValidImplementation() {
return !implementations.isEmpty();
} }
public static GIFHandler getOrCreate(Identifier id) { public static GIFHandler getOrCreate(Identifier id) {
if (gifPlayers.containsKey(id)) return gifPlayers.get(id); if (gifHandlers.containsKey(id)) return gifHandlers.get(id);
else return new GIFHandler(id); AtomicReference<GIFHandler> handler = new AtomicReference<>();
implementations.forEach(impl -> {
handler.set(impl.apply(id));
});
return handler.get();
} }
public void tick() { public void tick() {
if (player != null && player.getRenderer() != null && tick < player.getRenderer().duration) tick += 1;
else tick = 0;
} }
public void closePlayer() { public void closePlayer() {
player.release(); gifHandlers.remove(this.id);
player = null;
gifPlayers.remove(this.id);
} }
public static void closePlayer(Identifier videoId) { public static void closePlayer(Identifier videoId) {
if (gifPlayers.containsKey(videoId)) gifPlayers.get(videoId).closePlayer(); if (gifHandlers.containsKey(videoId)) gifHandlers.get(videoId).closePlayer();
} }
public static void closeAll() { public static void closeAll() {
gifPlayers.forEach((id, handler) -> handler.closePlayer()); gifHandlers.forEach((id, handler) -> handler.closePlayer());
gifPlayers.clear(); gifHandlers.clear();
} }
public void play(String url) { public void play(String url) {
this.player = ImageAPI.getCache(url, client);
player.load();
this.playbackStarted = true; this.playbackStarted = true;
} }
public boolean hasMedia() { public boolean hasMedia() {
return player != null && player.getStatus() == ImageCache.Status.READY; return false;
} }
public int getTexture() { public int getTexture() {
return player.getRenderer().texture(tick, return -1;
(MathAPI.tickToMs(client.getRenderTickCounter().getTickDelta(true))), true);
} }
public boolean isWorking() { public boolean isWorking() {
if (player != null && player.getException() != null) player.getException().fillInStackTrace(); return false;
return player != null && player.getStatus() == ImageCache.Status.READY && player.getRenderer() != null;
} }
} }

View File

@@ -4,14 +4,19 @@ import eu.midnightdust.picturesign.config.PictureSignConfig;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import org.jetbrains.annotations.ApiStatus;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import static eu.midnightdust.picturesign.PictureSignClient.client; import static eu.midnightdust.picturesign.PictureSignClient.client;
import static eu.midnightdust.picturesign.PictureSignClient.hasWaterMedia;
public abstract class MediaHandler { public abstract class MediaHandler {
private static final List<BiFunction<Identifier, BlockPos, MediaHandler>> implementations = new ArrayList<>();
public static Map<Identifier, MediaHandler> mediaHandlers = new HashMap<>(); public static Map<Identifier, MediaHandler> mediaHandlers = new HashMap<>();
public final Identifier id; public final Identifier id;
@@ -20,19 +25,23 @@ public abstract class MediaHandler {
public boolean isDeactivated; public boolean isDeactivated;
int maxVolume = 100; int maxVolume = 100;
MediaHandler(Identifier id, BlockPos pos) { public MediaHandler(Identifier id, BlockPos pos) {
this.id = id; this.id = id;
this.pos = pos; this.pos = pos;
} }
public static void registerHandler(BiFunction<Identifier, BlockPos, MediaHandler> handler) {
implementations.add(handler);
}
public static boolean hasValidImplementation() {
return !implementations.isEmpty();
}
public static MediaHandler getOrCreate(Identifier id, BlockPos pos) { public static MediaHandler getOrCreate(Identifier id, BlockPos pos) {
if (mediaHandlers.containsKey(id)) return mediaHandlers.get(id); if (mediaHandlers.containsKey(id)) return mediaHandlers.get(id);
else if (hasWaterMedia) return new WaterMediaHandler(id, pos); AtomicReference<MediaHandler> handler = new AtomicReference<>();
// Add new implementations here via Mixin implementations.forEach(impl -> {
else return null; handler.set(impl.apply(id, pos));
} });
public static boolean hasValidImplementation() { // Mixin here to add new Multimedia implementations return handler.get();
if (hasWaterMedia) return true;
else return false;
} }
public void setVolumeBasedOnDistance() { public void setVolumeBasedOnDistance() {
if (!isWorking() || client.player == null) return; if (!isWorking() || client.player == null) return;
@@ -45,7 +54,9 @@ public abstract class MediaHandler {
double distance = this.pos.getSquaredDistance(playerPos) / PictureSignConfig.audioDistanceMultiplier; double distance = this.pos.getSquaredDistance(playerPos) / PictureSignConfig.audioDistanceMultiplier;
setVolume((int) Math.clamp(maxVolume-distance, 0, 100)); setVolume((int) Math.clamp(maxVolume-distance, 0, 100));
} }
void setVolume(int volume) {} @ApiStatus.Internal
public void setVolume(int volume) {} // Please use 'setMaxVolume' to adjust the playback volume
public void setMaxVolume(int volume) { public void setMaxVolume(int volume) {
maxVolume = volume; maxVolume = volume;
} }

View File

@@ -0,0 +1,50 @@
package eu.midnightdust.picturesign.util;
import me.srrapero720.watermedia.api.image.ImageAPI;
import me.srrapero720.watermedia.api.image.ImageCache;
import me.srrapero720.watermedia.api.math.MathAPI;
import net.minecraft.util.Identifier;
import static eu.midnightdust.picturesign.PictureSignClient.client;
public class WaterGIFHandler extends GIFHandler {
private ImageCache player;
private long tick = 0L;
public WaterGIFHandler(Identifier id) {
super(id);
}
@Override
public void tick() {
if (player != null && player.getRenderer() != null && tick < player.getRenderer().duration) tick += 1;
else tick = 0;
}
@Override
public void closePlayer() {
player.release();
player = null;
super.closePlayer();
}
@Override
public void play(String url) {
this.player = ImageAPI.getCache(url, client);
player.load();
super.play(url);
}
@Override
public boolean hasMedia() {
return player != null && player.getStatus() == ImageCache.Status.READY;
}
@Override
public int getTexture() {
return player.getRenderer().texture(tick,
(MathAPI.tickToMs(client.getRenderTickCounter().getTickDelta(true))), true);
}
@Override
public boolean isWorking() {
if (player != null && player.getException() != null) player.getException().fillInStackTrace();
return player != null && player.getStatus() == ImageCache.Status.READY && player.getRenderer() != null;
}
}

View File

@@ -15,12 +15,12 @@ import static eu.midnightdust.picturesign.PictureSignClient.client;
public class WaterMediaHandler extends MediaHandler { public class WaterMediaHandler extends MediaHandler {
private SyncBasePlayer player; private SyncBasePlayer player;
WaterMediaHandler(Identifier id, BlockPos pos) { public WaterMediaHandler(Identifier id, BlockPos pos) {
super(id, pos); super(id, pos);
mediaHandlers.put(id, this); mediaHandlers.put(id, this);
} }
@Override @Override
void setVolume(int volume) { public void setVolume(int volume) {
player.setVolume((int) (volume * MinecraftClient.getInstance().options.getSoundVolume(SoundCategory.MASTER))); player.setVolume((int) (volume * MinecraftClient.getInstance().options.getSoundVolume(SoundCategory.MASTER)));
} }
@@ -36,7 +36,7 @@ public class WaterMediaHandler extends MediaHandler {
@Override @Override
public void stop() { public void stop() {
player.stop(); player.stop();
isDeactivated = true; super.stop();
} }
@Override @Override
public boolean isStopped() { public boolean isStopped() {

View File

@@ -36,7 +36,7 @@ public class PictureSignClientFabric implements ClientModInitializer {
} }
}); });
ClientTickEvents.END_CLIENT_TICK.register(client -> { ClientTickEvents.END_CLIENT_TICK.register(client -> {
GIFHandler.gifPlayers.forEach(((identifier, handler) -> handler.tick())); GIFHandler.gifHandlers.forEach(((identifier, handler) -> handler.tick()));
if (!BINDING_COPY_SIGN.isPressed()) return; if (!BINDING_COPY_SIGN.isPressed()) return;
BINDING_COPY_SIGN.setPressed(false); BINDING_COPY_SIGN.setPressed(false);
if (client.player == null || client.world == null || client.crosshairTarget == null || client.crosshairTarget.getType() != HitResult.Type.BLOCK) return; if (client.player == null || client.world == null || client.crosshairTarget == null || client.crosshairTarget.getType() != HitResult.Type.BLOCK) return;

View File

@@ -5,7 +5,7 @@ yarn_mappings=1.21+build.2
enabled_platforms=fabric,neoforge enabled_platforms=fabric,neoforge
archives_base_name=picturesign archives_base_name=picturesign
mod_version=2.0.0 mod_version=2.0.1
maven_group=eu.midnightdust maven_group=eu.midnightdust
release_type=release release_type=release
curseforge_id=533897 curseforge_id=533897