From 61db8af3b970fccdfe205d4fc413c79eb2fd48fc Mon Sep 17 00:00:00 2001 From: Vinrobot Date: Sun, 16 Jul 2023 00:45:58 +0200 Subject: [PATCH] Load glyphs in a separate thread with ThreadPoolExecutor --- .../mcemote/client/font/EmoteFontStorage.java | 18 +++++++++++++--- .../mcemote/client/helpers/FutureHelper.java | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/client/java/net/vinrobot/mcemote/client/helpers/FutureHelper.java diff --git a/src/client/java/net/vinrobot/mcemote/client/font/EmoteFontStorage.java b/src/client/java/net/vinrobot/mcemote/client/font/EmoteFontStorage.java index 5f6b7a0..15bc50c 100644 --- a/src/client/java/net/vinrobot/mcemote/client/font/EmoteFontStorage.java +++ b/src/client/java/net/vinrobot/mcemote/client/font/EmoteFontStorage.java @@ -3,6 +3,11 @@ import java.time.Instant; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.font.BuiltinEmptyGlyph; @@ -12,6 +17,7 @@ import net.minecraft.client.texture.TextureManager; import net.minecraft.util.Identifier; import net.vinrobot.mcemote.MinecraftEmoteMod; +import net.vinrobot.mcemote.client.helpers.FutureHelper; import net.vinrobot.mcemote.client.text.EmotesManager; @Environment(EnvType.CLIENT) @@ -20,8 +26,9 @@ public class EmoteFontStorage extends FontStorage { public static final float GLYPH_HEIGHT = 9; private final EmotesManager emotesManager; - private final Map framesCache = new HashMap<>(); + private final Map> framesCache = new HashMap<>(); private final Map glyphRendererCache = new HashMap<>(); + private final ExecutorService executorService = new ThreadPoolExecutor(1, 10, 30, TimeUnit.SECONDS, new LinkedBlockingQueue()); public EmoteFontStorage(TextureManager textureManager, EmotesManager emotesManager) { super(textureManager, IDENTIFIER); @@ -31,13 +38,18 @@ public EmoteFontStorage(TextureManager textureManager, EmotesManager emotesManag @Override public Glyph getGlyph(int codePoint, boolean validateAdvance) { try { - return this.framesCache.computeIfAbsent(codePoint, this::loadAnimatedGlyph) - .getGlyphAt(Instant.now()); + return FutureHelper.asOptional(this.framesCache.computeIfAbsent(codePoint, this::asyncLoadAnimatedGlyph)) + .map(m -> m.getGlyphAt(Instant.now())) + .orElse(BuiltinEmptyGlyph.MISSING); } catch (RuntimeException ex) { return BuiltinEmptyGlyph.MISSING; } } + private Future asyncLoadAnimatedGlyph(int codePoint) { + return this.executorService.submit(() -> this.loadAnimatedGlyph(codePoint)); + } + private AnimatedGlyph loadAnimatedGlyph(int codePoint) { try { final Emote emote = this.emotesManager.getByCodePoint(codePoint).orElseThrow(); diff --git a/src/client/java/net/vinrobot/mcemote/client/helpers/FutureHelper.java b/src/client/java/net/vinrobot/mcemote/client/helpers/FutureHelper.java new file mode 100644 index 0000000..cd84060 --- /dev/null +++ b/src/client/java/net/vinrobot/mcemote/client/helpers/FutureHelper.java @@ -0,0 +1,21 @@ +package net.vinrobot.mcemote.client.helpers; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +public final class FutureHelper { + public static Optional asOptional(Future future) { + if (!future.isDone()) { + return Optional.empty(); + } + + try { + return Optional.of(future.get()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e.getCause()); + } + } +}