Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,47 +1,77 @@
package me.contaria.seedqueue.customization;

import me.contaria.seedqueue.SeedQueue;
import me.contaria.speedrunapi.util.IdentifierUtil;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jetbrains.annotations.Nullable;

public class AnimatedTexture {
private final Identifier id;
@Nullable
protected final AnimationResourceMetadata animation;

protected AnimatedTexture(Identifier id) {
this.id = id;
AnimationResourceMetadata animation = null;
try {
animation = MinecraftClient.getInstance().getResourceManager().getResource(id).getMetadata(AnimationResourceMetadata.READER);
} catch (IOException e) {
SeedQueue.LOGGER.warn("Failed to read animation data for {}!", id, e);
}
this.animation = animation;
}
protected final List<Identifier> ids = new ArrayList<>();
protected final List<@Nullable AnimationResourceMetadata> animations = new ArrayList<>();
private int totalAnimationDuration = 0;

public Identifier getId() {
return this.id;
protected AnimatedTexture(List<Identifier> ids) {
for (Identifier id : ids) {
if (!MinecraftClient.getInstance().getResourceManager().containsResource(id)) {
continue;
}
try {
AnimationResourceMetadata animation = MinecraftClient.getInstance().getResourceManager().getResource(id).getMetadata(AnimationResourceMetadata.READER);
this.ids.add(id);
this.animations.add(animation);
if (animation == null) {
continue;
}
this.totalAnimationDuration += animation.getDefaultFrameTime() * animation.getFrameCount();
} catch (IOException e) {
SeedQueue.LOGGER.warn("Failed to read animation data for {}!", id, e);
}
}
this.totalAnimationDuration = Math.max(1, this.totalAnimationDuration); // avoid division by zero
}

public int getFrameIndex(int tick) {
public AnimationFrameMetadata getFrame(int tick) {
// does not currently support setting frametime for individual frames
// see AnimationFrameResourceMetadata#usesDefaultFrameTime
return this.animation != null ? this.animation.getFrameIndex((tick / this.animation.getDefaultFrameTime()) % this.animation.getFrameCount()) : 0;
int animationPosition = tick % this.totalAnimationDuration;
for (int i = 0; i < this.animations.size(); i++) {
AnimationResourceMetadata animation = this.animations.get(i);
if (animation == null) {
continue;
}
int duration = animation.getDefaultFrameTime() * animation.getFrameCount();
if (animationPosition < duration) {
return new AnimationFrameMetadata(this.ids.get(i), animation.getFrameIndexSet().size(), animation.getFrameIndex(animationPosition / animation.getDefaultFrameTime()));
}
animationPosition -= duration;
}
return new AnimationFrameMetadata(this.ids.get(0), 1, 0);
}

public int getIndividualFrameCount() {
return this.animation != null ? this.animation.getFrameIndexSet().size() : 1;
@Nullable
public static AnimatedTexture ofChunks(String namespace, String pathPrefix, String pathSuffix) {
List<Identifier> chunks = new ArrayList<>();
Identifier chunk = IdentifierUtil.of(namespace, pathPrefix + pathSuffix);
do {
chunks.add(chunk);
} while (MinecraftClient.getInstance().getResourceManager().containsResource(chunk = IdentifierUtil.of(namespace, pathPrefix + "-" + chunks.size() + pathSuffix)));
return AnimatedTexture.of(chunks);
}

public static @Nullable AnimatedTexture of(Identifier id) {
if (MinecraftClient.getInstance().getResourceManager().containsResource(id)) {
return new AnimatedTexture(id);
@Nullable
public static AnimatedTexture of(List<Identifier> ids) {
AnimatedTexture texture = new AnimatedTexture(ids);
if (texture.ids.isEmpty()) {
SeedQueue.LOGGER.warn("No valid animated textures found for identifiers: {}", ids);
return null;
}
return null;
return texture;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package me.contaria.seedqueue.customization;

import net.minecraft.util.Identifier;

public class AnimationFrameMetadata {
public final Identifier animationId;
public final int animationFrameCount;
public final int frameIndex;
public AnimationFrameMetadata(Identifier animationId, int animationFrameCount, int frameIndex) {
this.animationId = animationId;
this.animationFrameCount = animationFrameCount;
this.frameIndex = frameIndex;
}
}
15 changes: 11 additions & 4 deletions src/main/java/me/contaria/seedqueue/customization/LockTexture.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,32 @@
import me.contaria.seedqueue.SeedQueue;
import me.contaria.speedrunapi.util.IdentifierUtil;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.resource.metadata.AnimationResourceMetadata;
import net.minecraft.client.texture.NativeImage;
import net.minecraft.util.Identifier;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class LockTexture extends AnimatedTexture {
private final int width;
private final int height;

public LockTexture(Identifier id) throws IOException {
super(id);
try (NativeImage image = NativeImage.read(MinecraftClient.getInstance().getResourceManager().getResource(id).getInputStream())) {
public LockTexture(List<Identifier> ids) throws IOException {
super(ids);
try (NativeImage image = NativeImage.read(MinecraftClient.getInstance().getResourceManager().getResource(this.ids.get(0)).getInputStream())) {
AnimationResourceMetadata animation = this.animations.get(0);
this.width = image.getWidth();
this.height = image.getHeight() / (this.animation != null ? this.animation.getFrameIndexSet().size() : 1);
this.height = image.getHeight() / (animation != null ? animation.getFrameIndexSet().size() : 1);
}
}

public LockTexture(Identifier id) throws IOException {
this(Collections.singletonList(id));
}

public double getAspectRatio() {
return (double) this.width / this.height;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import me.contaria.seedqueue.compat.SeedQueuePreviewProperties;
import me.contaria.seedqueue.compat.SeedQueueSettingsCache;
import me.contaria.seedqueue.customization.AnimatedTexture;
import me.contaria.seedqueue.customization.AnimationFrameMetadata;
import me.contaria.seedqueue.customization.Layout;
import me.contaria.seedqueue.customization.LockTexture;
import me.contaria.seedqueue.debug.SeedQueueProfiler;
Expand Down Expand Up @@ -47,10 +48,13 @@ public class SeedQueueWallScreen extends Screen {
private static final Set<WorldRenderer> WORLD_RENDERERS = new HashSet<>();

public static final Identifier CUSTOM_LAYOUT = IdentifierUtil.of("seedqueue", "wall/custom_layout.json");
private static final Identifier WALL_BACKGROUND = IdentifierUtil.of("seedqueue", "textures/gui/wall/background.png");
private static final Identifier WALL_OVERLAY = IdentifierUtil.of("seedqueue", "textures/gui/wall/overlay.png");
private static final Identifier INSTANCE_BACKGROUND = IdentifierUtil.of("seedqueue", "textures/gui/wall/instance_background.png");
private static final Identifier INSTANCE_OVERLAY = IdentifierUtil.of("seedqueue", "textures/gui/wall/instance_overlay.png");

public static final String TEXTURE_NAMESPACE = "seedqueue";
private static final String WALL_BACKGROUND_PREFIX = "textures/gui/wall/background";
private static final String WALL_OVERLAY_PREFIX = "textures/gui/wall/overlay";
private static final String INSTANCE_BACKGROUND_PREFIX = "textures/gui/wall/instance_background";
private static final String INSTANCE_OVERLAY_PREFIX = "textures/gui/wall/instance_overlay";
public static final String TEXTURE_SUFFIX = ".png";

private static boolean renderingPreview;

Expand Down Expand Up @@ -113,10 +117,10 @@ protected void init() {
this.lockedPreviews = this.layout.locked != null ? new ArrayList<>() : null;
this.preparingPreviews = new ArrayList<>();
this.lockTextures = LockTexture.createLockTextures();
this.background = AnimatedTexture.of(WALL_BACKGROUND);
this.overlay = AnimatedTexture.of(WALL_OVERLAY);
this.instanceBackground = AnimatedTexture.of(INSTANCE_BACKGROUND);
this.instanceOverlay = AnimatedTexture.of(INSTANCE_OVERLAY);
this.background = AnimatedTexture.ofChunks(TEXTURE_NAMESPACE, WALL_BACKGROUND_PREFIX, TEXTURE_SUFFIX);
this.overlay = AnimatedTexture.ofChunks(TEXTURE_NAMESPACE, WALL_OVERLAY_PREFIX, TEXTURE_SUFFIX);
this.instanceBackground = AnimatedTexture.ofChunks(TEXTURE_NAMESPACE, INSTANCE_BACKGROUND_PREFIX, TEXTURE_SUFFIX);
this.instanceOverlay = AnimatedTexture.ofChunks(TEXTURE_NAMESPACE, INSTANCE_OVERLAY_PREFIX, TEXTURE_SUFFIX);
}

protected LockTexture getRandomLockTexture() {
Expand Down Expand Up @@ -260,35 +264,37 @@ private void renderInstanceOverlay(Layout.Group group, MatrixStack matrices) {

private void drawLock(MatrixStack matrices, Layout.Pos pos, LockTexture lock) {
this.setOrtho(this.client.getWindow().getFramebufferWidth(), this.client.getWindow().getFramebufferHeight());
this.client.getTextureManager().bindTexture(lock.getId());
AnimationFrameMetadata frame = lock.getFrame(this.ticks);
this.client.getTextureManager().bindTexture(frame.animationId);
DrawableHelper.drawTexture(
matrices,
pos.x,
pos.y,
0.0f,
lock.getFrameIndex(this.ticks) * pos.height,
frame.frameIndex * pos.height,
(int) Math.min(pos.width, pos.height * lock.getAspectRatio()),
pos.height,
(int) (pos.height * lock.getAspectRatio()),
pos.height * lock.getIndividualFrameCount()
pos.height * frame.animationFrameCount
);
this.resetOrtho();
}

@SuppressWarnings("SameParameterValue")
private void drawAnimatedTexture(AnimatedTexture texture, MatrixStack matrices, int x, int y, int width, int height) {
this.client.getTextureManager().bindTexture(texture.getId());
AnimationFrameMetadata frame = texture.getFrame(this.ticks);
this.client.getTextureManager().bindTexture(frame.animationId);
RenderSystem.enableBlend();
DrawableHelper.drawTexture(
matrices,
x,
y,
0.0f,
texture.getFrameIndex(this.ticks) * height,
frame.frameIndex * height,
width,
height,
width,
height * texture.getIndividualFrameCount()
height * frame.animationFrameCount
);
RenderSystem.disableBlend();
}
Expand Down