From 9dfe541319621bf14d3713d8b258ba0897ad8747 Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Sun, 5 Dec 2021 18:54:43 -0800 Subject: [PATCH] Added decorators for AssetLoader functions AssetLoader functions will now notify passed Promise of exceptions Changed DcParams#combineFrames from boolean to int [-1 (auto), 0 (don't combine), 1 (combine)] --- .../java/com/riiablo/asset/AssetLoader.java | 85 +++++++++++++++++-- .../java/com/riiablo/asset/AssetManager.java | 24 ++++-- .../java/com/riiablo/asset/SyncMessage.java | 4 +- .../com/riiablo/asset/loader/Dc6Loader.java | 14 +-- .../com/riiablo/asset/loader/DccLoader.java | 20 ++--- .../com/riiablo/asset/loader/MusicLoader.java | 6 +- .../riiablo/asset/loader/PaletteLoader.java | 18 ++-- .../com/riiablo/asset/param/DcParams.java | 22 +++-- core/src/main/java/com/riiablo/file/Dc.java | 6 +- core/src/main/java/com/riiablo/file/Dc6.java | 4 +- core/src/main/java/com/riiablo/file/Dcc.java | 4 +- .../com/riiablo/asset/AssetManagerTest.java | 3 + 12 files changed, 150 insertions(+), 60 deletions(-) diff --git a/core/src/main/java/com/riiablo/asset/AssetLoader.java b/core/src/main/java/com/riiablo/asset/AssetLoader.java index e4733977..a7c693b8 100644 --- a/core/src/main/java/com/riiablo/asset/AssetLoader.java +++ b/core/src/main/java/com/riiablo/asset/AssetLoader.java @@ -2,18 +2,93 @@ package com.riiablo.asset; import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.Promise; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.utils.Array; public abstract class AssetLoader { - protected Array dependencies(AssetDesc asset) { + public final Array dependencies( + Promise promise, + AssetDesc asset + ) { + try { + return dependencies0(asset); + } catch (Throwable t) { + promise.setFailure(t); + throw t; + } + } + + public final void validate( + Promise promise, + AssetDesc asset + ) { + try { + validate0(asset); + } catch (Throwable t) { + promise.setFailure(t); + throw t; + } + } + + public final Future ioAsync( + Promise promise, + EventExecutor executor, + AssetManager assets, + AssetDesc asset, + F handle, + Adapter adapter + ) { + try { + return ioAsync0(executor, assets, asset, handle, adapter); + } catch (Throwable t) { + promise.setFailure(t); + throw t; + } + } + + public final T loadAsync( + Promise promise, + AssetManager assets, + AssetDesc asset, + F handle, + Object data + ) { + try { + return loadAsync0(assets, asset, handle, data); + } catch (Throwable t) { + promise.setFailure(t); + throw t; + } + } + + public final T loadSync( + Promise promise, + AssetManager assets, + AssetDesc asset, + T object + ) { + try { + return loadSync0(assets, asset, object); + } catch (Throwable t) { + promise.setFailure(t); + throw t; + } + } + + protected Array dependencies0( + AssetDesc asset + ) { return EmptyArray.empty(); } - protected void validate(AssetDesc asset) {} + protected void validate0( + AssetDesc asset + ) { + } - protected Future ioAsync( + protected Future ioAsync0( EventExecutor executor, AssetManager assets, AssetDesc asset, @@ -23,7 +98,7 @@ public abstract class AssetLoader { return executor.newSucceededFuture(null); } - protected T loadAsync( + protected T loadAsync0( AssetManager assets, AssetDesc asset, F handle, @@ -32,7 +107,7 @@ public abstract class AssetLoader { return null; } - protected T loadSync( + protected T loadSync0( AssetManager assets, AssetDesc asset, T object diff --git a/core/src/main/java/com/riiablo/asset/AssetManager.java b/core/src/main/java/com/riiablo/asset/AssetManager.java index 02187d2e..2ab501e3 100644 --- a/core/src/main/java/com/riiablo/asset/AssetManager.java +++ b/core/src/main/java/com/riiablo/asset/AssetManager.java @@ -142,7 +142,7 @@ public final class AssetManager implements Disposable { AssetContainer[] loadDependencies(Promise promise, AssetDesc asset) { final AssetLoader loader = findLoader(asset.type); @SuppressWarnings("unchecked") // guaranteed by loader contract - Array dependencies = loader.dependencies(asset); + Array dependencies = loader.dependencies(promise, asset); final int numDependencies = dependencies.size; final AssetContainer[] containers = numDependencies > 0 ? new AssetContainer[dependencies.size] @@ -169,10 +169,10 @@ public final class AssetManager implements Disposable { final FileHandle handle = resolve(asset); // TODO: refactor AssetLoader#resolver? final Adapter adapter = findAdapter(handle); loader - .ioAsync(executor, AssetManager.this, asset, handle, adapter) + .ioAsync(promise, executor, AssetManager.this, asset, handle, adapter) .addListener((FutureListener) future -> { @SuppressWarnings("unchecked") // guaranteed by loader contract - T object = (T) loader.loadAsync(AssetManager.this, asset, handle, future.getNow()); + T object = (T) loader.loadAsync(promise, AssetManager.this, asset, handle, future.getNow()); boolean inserted = syncQueue.offer(SyncMessage.wrap(container, promise, loader, object)); if (!inserted) log.error("Failed to enqueue {}", asset); }); @@ -185,15 +185,22 @@ public final class AssetManager implements Disposable { if (container0 != null) return container0.retain(); final Promise promise = sync.newPromise(); + promise.setUncancellable(); + promise.addListener(future -> { + final Throwable cause = future.cause(); + if (cause != null) { + log.warn("Failed to load asset {}", asset, cause); + } + }); + // FIXME: loadDependencies may throw an exception to propagate to caller final AssetContainer[] dependencies = loadDependencies(promise, asset); final AssetContainer container = AssetContainer.wrap(asset, promise, dependencies); loadedAssets.put(asset, container); if (promise.isDone()) return container; // one or more dependencies was invalid try { - findLoader(asset.type).validate(asset); - } catch (Throwable cause) { - promise.setFailure(cause); + findLoader(asset.type).validate(promise, asset); + } catch (Throwable t) { return container; } @@ -241,7 +248,10 @@ public final class AssetManager implements Disposable { start = end; msg = syncQueue.poll(timeoutRemaining, TimeUnit.MILLISECONDS); if (msg == null) break; - msg.loadSync(this); + try { + msg.loadSync(this); + } catch (Throwable ignored) { + } end = System.currentTimeMillis(); timeoutRemaining -= (end - start); } diff --git a/core/src/main/java/com/riiablo/asset/SyncMessage.java b/core/src/main/java/com/riiablo/asset/SyncMessage.java index 877bf6bb..b830d102 100644 --- a/core/src/main/java/com/riiablo/asset/SyncMessage.java +++ b/core/src/main/java/com/riiablo/asset/SyncMessage.java @@ -33,8 +33,8 @@ final class SyncMessage { @SuppressWarnings("unchecked") // guaranteed by loader contract Future loadSync(AssetManager assets) { - loader.loadSync(assets, container.asset, object); - promise.setSuccess(object); + loader.loadSync(promise, assets, container.asset, object); + promise.trySuccess(object); return promise; } diff --git a/core/src/main/java/com/riiablo/asset/loader/Dc6Loader.java b/core/src/main/java/com/riiablo/asset/loader/Dc6Loader.java index 8501d09b..21eb98ce 100644 --- a/core/src/main/java/com/riiablo/asset/loader/Dc6Loader.java +++ b/core/src/main/java/com/riiablo/asset/loader/Dc6Loader.java @@ -35,7 +35,7 @@ public class Dc6Loader extends AssetLoader { }; @Override - public Array dependencies(AssetDesc asset) { + public Array dependencies0(AssetDesc asset) { DcParams params = asset.params(DcParams.class); if (params.direction < 0) return EmptyArray.empty(); AssetDesc header = AssetDesc.of(asset, PARENT_DC); @@ -45,14 +45,14 @@ public class Dc6Loader extends AssetLoader { } @Override - protected Future ioAsync( + protected Future ioAsync0( EventExecutor executor, AssetManager assets, AssetDesc asset, F handle, Adapter adapter ) { - log.traceEntry("ioAsync(executor: {}, asset: {}, handle: {}, adapter: {})", executor, asset, handle, adapter); + log.traceEntry("ioAsync0(executor: {}, asset: {}, handle: {}, adapter: {})", executor, asset, handle, adapter); DcParams params = asset.params(DcParams.class); if (params.direction >= 0) { Dc6 dc6 = assets.getDepNow(AssetDesc.of(asset, PARENT_DC)); @@ -65,13 +65,13 @@ public class Dc6Loader extends AssetLoader { } @Override - protected Dc6 loadAsync( + protected Dc6 loadAsync0( AssetManager assets, AssetDesc asset, F handle, Object data ) { - log.traceEntry("loadAsync(assets: {}, asset: {}, handle: {}, data: {})", assets, asset, handle, data); + log.traceEntry("loadAsync0(assets: {}, asset: {}, handle: {}, data: {})", assets, asset, handle, data); DcParams params = asset.params(DcParams.class); if (params.direction >= 0) { boolean released = ReferenceCountUtil.release(handle); // dcc already owns a reference @@ -100,8 +100,8 @@ public class Dc6Loader extends AssetLoader { } @Override - protected Dc6 loadSync(AssetManager assets, AssetDesc asset, Dc6 dc6) { - log.traceEntry("loadSync(assets: {}, asset: {}, dcc: {})", assets, asset, dc6); + protected Dc6 loadSync0(AssetManager assets, AssetDesc asset, Dc6 dc6) { + log.traceEntry("loadSync0(assets: {}, asset: {}, dcc: {})", assets, asset, dc6); DcParams params = asset.params(DcParams.class); if (params.direction < 0) return dc6; dc6.uploadTextures(params.direction, params.combineFrames); diff --git a/core/src/main/java/com/riiablo/asset/loader/DccLoader.java b/core/src/main/java/com/riiablo/asset/loader/DccLoader.java index f314be13..32f25164 100644 --- a/core/src/main/java/com/riiablo/asset/loader/DccLoader.java +++ b/core/src/main/java/com/riiablo/asset/loader/DccLoader.java @@ -36,7 +36,7 @@ public class DccLoader extends AssetLoader { }; @Override - protected Array dependencies(AssetDesc asset) { + protected Array dependencies0(AssetDesc asset) { DcParams params = asset.params(DcParams.class); if (params.direction < 0) return EmptyArray.empty(); AssetDesc header = AssetDesc.of(asset, PARENT_DC); @@ -46,21 +46,21 @@ public class DccLoader extends AssetLoader { } @Override - protected void validate(AssetDesc asset) { + protected void validate0(AssetDesc asset) { DcParams params = asset.params(DcParams.class); - if (params.combineFrames) throw new InvalidParams(asset, - "Dcc does not support DcParams#combineFrames=true"); + if (params.combineFrames == 1) throw new InvalidParams(asset, + "Dcc does not support DcParams#combineFrames=1"); } @Override - protected Future ioAsync( + protected Future ioAsync0( EventExecutor executor, AssetManager assets, AssetDesc asset, F handle, Adapter adapter ) { - log.traceEntry("ioAsync(executor: {}, asset: {}, handle: {}, adapter: {})", executor, asset, handle, adapter); + log.traceEntry("ioAsync0(executor: {}, asset: {}, handle: {}, adapter: {})", executor, asset, handle, adapter); DcParams params = asset.params(DcParams.class); if (params.direction >= 0) { Dcc dcc = assets.getDepNow(AssetDesc.of(asset, PARENT_DC)); @@ -73,13 +73,13 @@ public class DccLoader extends AssetLoader { } @Override - protected Dcc loadAsync( + protected Dcc loadAsync0( AssetManager assets, AssetDesc asset, F handle, Object data ) { - log.traceEntry("loadAsync(assets: {}, asset: {}, handle: {}, data: {})", assets, asset, handle, data); + log.traceEntry("loadAsync0(assets: {}, asset: {}, handle: {}, data: {})", assets, asset, handle, data); DcParams params = asset.params(DcParams.class); if (params.direction >= 0) { boolean released = ReferenceCountUtil.release(handle); // dcc already owns a reference @@ -108,8 +108,8 @@ public class DccLoader extends AssetLoader { } @Override - protected Dcc loadSync(AssetManager assets, AssetDesc asset, Dcc dcc) { - log.traceEntry("loadSync(assets: {}, asset: {}, dcc: {})", assets, asset, dcc); + protected Dcc loadSync0(AssetManager assets, AssetDesc asset, Dcc dcc) { + log.traceEntry("loadSync0(assets: {}, asset: {}, dcc: {})", assets, asset, dcc); DcParams params = asset.params(DcParams.class); if (params.direction < 0) return dcc; dcc.uploadTextures(params.direction, params.combineFrames); diff --git a/core/src/main/java/com/riiablo/asset/loader/MusicLoader.java b/core/src/main/java/com/riiablo/asset/loader/MusicLoader.java index f6d7b958..f27f89f6 100644 --- a/core/src/main/java/com/riiablo/asset/loader/MusicLoader.java +++ b/core/src/main/java/com/riiablo/asset/loader/MusicLoader.java @@ -14,7 +14,7 @@ import com.riiablo.asset.AssetManager; public class MusicLoader extends AssetLoader { @Override - protected Future ioAsync( + protected Future ioAsync0( EventExecutor executor, AssetManager assets, AssetDesc asset, @@ -25,7 +25,7 @@ public class MusicLoader extends AssetLoader { } @Override - protected Music loadAsync( + protected Music loadAsync0( AssetManager assets, AssetDesc asset, F handle, @@ -35,7 +35,7 @@ public class MusicLoader extends AssetLoader { } @Override - protected Music loadSync( + protected Music loadSync0( AssetManager assets, AssetDesc asset, Music music diff --git a/core/src/main/java/com/riiablo/asset/loader/PaletteLoader.java b/core/src/main/java/com/riiablo/asset/loader/PaletteLoader.java index a02de84f..44962104 100644 --- a/core/src/main/java/com/riiablo/asset/loader/PaletteLoader.java +++ b/core/src/main/java/com/riiablo/asset/loader/PaletteLoader.java @@ -6,7 +6,6 @@ import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.Future; import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.utils.Array; import com.riiablo.asset.Adapter; import com.riiablo.asset.AssetDesc; @@ -20,25 +19,20 @@ public class PaletteLoader extends AssetLoader { private static final Logger log = LogManager.getLogger(PaletteLoader.class); @Override - public Array dependencies(AssetDesc asset) { - return super.dependencies(asset); - } - - @Override - protected Future ioAsync( + protected Future ioAsync0( EventExecutor executor, AssetManager assets, AssetDesc asset, F handle, Adapter adapter ) { - log.traceEntry("ioAsync(executor: {}, assets: {}, asset: {}, handle: {}, adapter: {})", executor, assets, asset, handle, adapter); + log.traceEntry("ioAsync0(executor: {}, assets: {}, asset: {}, handle: {}, adapter: {})", executor, assets, asset, handle, adapter); return adapter.buffer(executor, handle, 0, (int) handle.length()); } @Override - protected Palette loadAsync(AssetManager assets, AssetDesc asset, F handle, Object data) { - log.traceEntry("loadAsync(assets: {}, asset: {}, handle: {}, data: {})", assets, asset, handle, data); + protected Palette loadAsync0(AssetManager assets, AssetDesc asset, F handle, Object data) { + log.traceEntry("loadAsync0(assets: {}, asset: {}, handle: {}, data: {})", assets, asset, handle, data); assert data instanceof ByteBuf; ByteBuf buffer = (ByteBuf) data; // borrowed, don't release try { @@ -49,8 +43,8 @@ public class PaletteLoader extends AssetLoader { } @Override - protected Palette loadSync(AssetManager assets, AssetDesc asset, Palette palette) { - log.traceEntry("loadSync(assets: {}, asset: {}, object: {})", assets, asset, palette); + protected Palette loadSync0(AssetManager assets, AssetDesc asset, Palette palette) { + log.traceEntry("loadSync0(assets: {}, asset: {}, object: {})", assets, asset, palette); return palette; } } diff --git a/core/src/main/java/com/riiablo/asset/param/DcParams.java b/core/src/main/java/com/riiablo/asset/param/DcParams.java index 072933dc..febb47f6 100644 --- a/core/src/main/java/com/riiablo/asset/param/DcParams.java +++ b/core/src/main/java/com/riiablo/asset/param/DcParams.java @@ -7,42 +7,46 @@ import com.riiablo.mpq_bytebuf.Mpq; public class DcParams extends MpqParams { public static DcParams of(int direction) { - return of(direction, false); + return of(direction, -1); } - public static DcParams of(int direction, boolean combineFrames) { + public static DcParams of(int direction, int combineFrames) { return new DcParams(direction, combineFrames); } - public static DcParams of(short locale, int direction, boolean combineFrames) { + public static DcParams of(short locale, int direction, int combineFrames) { return new DcParams(locale, direction, combineFrames); } - public static DcParams of(short locale, short platform, int direction, boolean combineFrames) { + public static DcParams of(short locale, short platform, int direction, int combineFrames) { return new DcParams(locale, platform, direction, combineFrames); } public final int direction; - public final boolean combineFrames; + public final int combineFrames; - protected DcParams(int direction, boolean combineFrames) { + protected DcParams(int direction, int combineFrames) { super(); this.direction = direction; this.combineFrames = combineFrames; } - protected DcParams(short locale, int direction, boolean combineFrames) { + protected DcParams(short locale, int direction, int combineFrames) { super(locale); this.direction = direction; this.combineFrames = combineFrames; } - protected DcParams(short locale, short platform, int direction, boolean combineFrames) { + protected DcParams(short locale, short platform, int direction, int combineFrames) { super(locale, platform); this.direction = direction; this.combineFrames = combineFrames; } + public DcParams copy(int direction) { + return of(locale, platform, direction, combineFrames); + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -57,7 +61,7 @@ public class DcParams extends MpqParams { public int hashCode() { int result = super.hashCode(); result = 31 * result + direction; - result = 31 * result + (combineFrames ? 1 : 0); + result = 31 * result + combineFrames; return result; } diff --git a/core/src/main/java/com/riiablo/file/Dc.java b/core/src/main/java/com/riiablo/file/Dc.java index 87ce1c36..ca8d42d7 100644 --- a/core/src/main/java/com/riiablo/file/Dc.java +++ b/core/src/main/java/com/riiablo/file/Dc.java @@ -84,7 +84,11 @@ public abstract class Dc return directions[d]; } - public void uploadTextures(int d, boolean combineFrames) {} + public boolean loaded(int d) { + return directions[d] != null; + } + + public void uploadTextures(int d, int combineFrames) {} public BBox box() { return todo(); diff --git a/core/src/main/java/com/riiablo/file/Dc6.java b/core/src/main/java/com/riiablo/file/Dc6.java index 8342b365..b4842203 100644 --- a/core/src/main/java/com/riiablo/file/Dc6.java +++ b/core/src/main/java/com/riiablo/file/Dc6.java @@ -116,12 +116,12 @@ public class Dc6 extends Dc { } @Override - public void uploadTextures(int d, boolean combineFrames) { + public void uploadTextures(int d, int combineFrames) { final Dc6Direction direction = directions[d]; final Dc6Frame[] frame = direction.frames; final Pixmap[] pixmap = direction.pixmap; final Texture[] texture = direction.texture; - if (!combineFrames) { + if (combineFrames == 0 || (combineFrames == -1 && frame[0].width < Dc6.PAGE_SIZE)) { for (int f = 0; f < numFrames; f++) { Texture t = texture[f] = new Texture(pixmap[f]); frame[f].texture.setRegion(t); diff --git a/core/src/main/java/com/riiablo/file/Dcc.java b/core/src/main/java/com/riiablo/file/Dcc.java index 796df2d6..714f5707 100644 --- a/core/src/main/java/com/riiablo/file/Dcc.java +++ b/core/src/main/java/com/riiablo/file/Dcc.java @@ -113,8 +113,8 @@ public final class Dcc extends Dc { } @Override - public void uploadTextures(int d, boolean combineFrames) { - if (combineFrames) throw new UnsupportedOperationException("DCC do not support combined frames"); + public void uploadTextures(int d, int combineFrames) { + if (combineFrames == 1) throw new UnsupportedOperationException("DCC do not support combined frames"); final DccDirection direction = directions[d]; final DccFrame[] frame = direction.frames; final Pixmap[] pixmap = direction.pixmap; diff --git a/core/src/test/java/com/riiablo/asset/AssetManagerTest.java b/core/src/test/java/com/riiablo/asset/AssetManagerTest.java index b30c3d0c..5af8842f 100644 --- a/core/src/test/java/com/riiablo/asset/AssetManagerTest.java +++ b/core/src/test/java/com/riiablo/asset/AssetManagerTest.java @@ -14,10 +14,12 @@ import com.badlogic.gdx.files.FileHandle; import com.riiablo.RiiabloTest; import com.riiablo.asset.adapter.GdxFileHandleAdapter; import com.riiablo.asset.adapter.MpqFileHandleAdapter; +import com.riiablo.asset.loader.Dc6Loader; import com.riiablo.asset.loader.DccLoader; import com.riiablo.asset.param.DcParams; import com.riiablo.asset.resolver.GdxFileHandleResolver; import com.riiablo.file.Dc; +import com.riiablo.file.Dc6; import com.riiablo.file.Dcc; import com.riiablo.logger.Level; import com.riiablo.logger.LogManager; @@ -121,6 +123,7 @@ public class AssetManagerTest extends RiiabloTest { .adapter(FileHandle.class, new GdxFileHandleAdapter()) .adapter(MpqFileHandle.class, new MpqFileHandleAdapter()) .loader(Dcc.class, new DccLoader()) + .loader(Dc6.class, new Dc6Loader()) ; }