mirror of
https://github.com/collinsmith/riiablo.git
synced 2025-07-06 16:27:34 +07:00
Created Dc6 codec
Created Dc6 file codec and Dc6Decoder and tests Amended Dc to remove Dc#dirOffsets and use virtual method instead Dc6 implements offsets for each frame and therefore requires a bit of specialization
This commit is contained in:
@ -19,22 +19,20 @@ public abstract class Dc<D extends Dc.Direction>
|
||||
protected final FileHandle handle;
|
||||
protected final int numDirections;
|
||||
protected final int numFrames;
|
||||
protected final int[] dirOffsets;
|
||||
protected final D[] directions;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Dc(FileHandle handle, int numDirections, int numFrames, int[] dirOffsets, Class<D> dirType) {
|
||||
protected Dc(FileHandle handle, int numDirections, int numFrames, Class<D> dirType) {
|
||||
this.handle = handle;
|
||||
this.numDirections = numDirections;
|
||||
this.numFrames = numFrames;
|
||||
this.dirOffsets = dirOffsets;
|
||||
this.directions = (D[]) Array.newInstance(dirType, numDirections);
|
||||
}
|
||||
|
||||
public Dc<D> read(ByteBuf buffer, int direction) {
|
||||
assert directions[direction] == null;
|
||||
assert buffer.isReadable(dirOffsets[direction + 1] - dirOffsets[direction])
|
||||
: handle + " buffer.isReadable(" + (dirOffsets[direction + 1] - dirOffsets[direction]) + ") = " + buffer.readableBytes();
|
||||
assert buffer.isReadable(dirOffset(direction + 1) - dirOffset(direction))
|
||||
: handle + " buffer.isReadable(" + (dirOffset(direction + 1) - dirOffset(direction)) + ") = " + buffer.readableBytes();
|
||||
retain(); // increment refCnt for each direction read
|
||||
return this;
|
||||
}
|
||||
@ -70,14 +68,7 @@ public abstract class Dc<D extends Dc.Direction>
|
||||
return numFrames;
|
||||
}
|
||||
|
||||
/** Dc file direction offsets table */
|
||||
public int[] dirOffsets() {
|
||||
return dirOffsets;
|
||||
}
|
||||
|
||||
public int dirOffset(int d) {
|
||||
return dirOffsets[d];
|
||||
}
|
||||
public abstract int dirOffset(int d);
|
||||
|
||||
public D direction(int d) {
|
||||
return directions[d];
|
||||
|
259
core/src/main/java/com/riiablo/file/Dc6.java
Normal file
259
core/src/main/java/com/riiablo/file/Dc6.java
Normal file
@ -0,0 +1,259 @@
|
||||
package com.riiablo.file;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.SwappedDataInputStream;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
|
||||
import com.riiablo.codec.util.BBox;
|
||||
import com.riiablo.io.ByteInput;
|
||||
import com.riiablo.logger.LogManager;
|
||||
import com.riiablo.logger.Logger;
|
||||
import com.riiablo.logger.MDC;
|
||||
import com.riiablo.util.DebugUtils;
|
||||
|
||||
public class Dc6 extends Dc<Dc6.Dc6Direction> {
|
||||
private static final Logger log = LogManager.getLogger(Dc6.class);
|
||||
|
||||
@SuppressWarnings("GDXJavaStaticResource")
|
||||
public static Texture MISSING_TEXTURE;
|
||||
|
||||
//final FileHandle handle; // Dc#handle
|
||||
final byte[] signature;
|
||||
final int version;
|
||||
final int format;
|
||||
final byte[] section;
|
||||
//final int numDirections; // Dc#numDirections
|
||||
//final int numFrames; // Dc#numFrames
|
||||
final int[] frameOffsets;
|
||||
|
||||
public static Dc6 read(FileHandle handle, InputStream stream) {
|
||||
SwappedDataInputStream in = new SwappedDataInputStream(stream);
|
||||
try {
|
||||
return read(handle, in);
|
||||
} catch (Throwable t) {
|
||||
return ExceptionUtils.rethrow(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dc6 read(FileHandle handle, SwappedDataInputStream in) throws IOException {
|
||||
byte[] signature = IOUtils.readFully(in, 4);
|
||||
int version = in.readInt();
|
||||
int format = in.readInt();
|
||||
byte[] section = IOUtils.readFully(in, 4);
|
||||
int numDirections = in.readInt();
|
||||
int numFrames = in.readInt();
|
||||
|
||||
log.trace("signature: {}", DebugUtils.toByteArray(signature));
|
||||
log.trace("version: {}", version);
|
||||
log.trace("format: {}", format);
|
||||
log.trace("section: {}", DebugUtils.toByteArray(section));
|
||||
log.trace("numDirections: {}", numDirections);
|
||||
log.trace("numFrames: {}", numFrames);
|
||||
|
||||
final int totalFrames = numDirections * numFrames;
|
||||
final int[] frameOffsets = new int[totalFrames + 1];
|
||||
for (int i = 0, s = totalFrames; i < s; i++) frameOffsets[i] = in.readInt();
|
||||
frameOffsets[totalFrames] = (int) handle.length();
|
||||
log.trace("frameOffsets: {}", frameOffsets);
|
||||
|
||||
return new Dc6(handle, signature, version, format, section, numDirections, numFrames, frameOffsets);
|
||||
}
|
||||
|
||||
Dc6(
|
||||
FileHandle handle,
|
||||
byte[] signature,
|
||||
int version,
|
||||
int format,
|
||||
byte[] section,
|
||||
int numDirections,
|
||||
int numFrames,
|
||||
int[] frameOffsets
|
||||
) {
|
||||
super(handle, numDirections, numFrames, Dc6Direction.class);
|
||||
this.signature = signature;
|
||||
this.version = version;
|
||||
this.format = format;
|
||||
this.section = section;
|
||||
this.frameOffsets = frameOffsets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dirOffset(int d) {
|
||||
return frameOffsets[d * numFrames];
|
||||
}
|
||||
|
||||
public int frameOffset(int d, int f) {
|
||||
return frameOffsets[d * numFrames + f];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dc6 read(ByteBuf buffer, int direction) {
|
||||
super.read(buffer, direction);
|
||||
ByteInput in = ByteInput.wrap(buffer);
|
||||
directions[direction] = new Dc6Direction(this, direction, in);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void uploadTextures(int d) {
|
||||
final Dc6Direction direction = directions[d];
|
||||
final Dc6Frame[] frame = direction.frames;
|
||||
final Pixmap[] pixmap = direction.pixmap;
|
||||
final Texture[] texture = direction.texture;
|
||||
for (int f = 0; f < numFrames; f++) {
|
||||
Texture t = texture[f] = new Texture(pixmap[f]);
|
||||
frame[f].texture.setRegion(t);
|
||||
pixmap[f].dispose();
|
||||
pixmap[f] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Dc6Direction extends Dc.Direction<Dc6Frame> {
|
||||
// Dc
|
||||
final Dc6Frame[] frames;
|
||||
final BBox box;
|
||||
final Pixmap[] pixmap;
|
||||
final Texture[] texture;
|
||||
|
||||
Dc6Direction(Dc6 dc6, int d, ByteInput in) {
|
||||
final int numFrames = dc6.numFrames;
|
||||
box = new BBox().prepare();
|
||||
pixmap = new Pixmap[numFrames];
|
||||
texture = new Texture[numFrames];
|
||||
Dc6Frame[] frames = this.frames = new Dc6Frame[numFrames];
|
||||
|
||||
for (int frame = 0; frame < numFrames; frame++) {
|
||||
try {
|
||||
MDC.put("frame", frame);
|
||||
int offset = dc6.frameOffset(d, frame);
|
||||
int nextOffset = dc6.frameOffset(d, frame + 1);
|
||||
log.tracef("nextOffset - offset: 0x%x", nextOffset - offset);
|
||||
Dc6Frame f = frames[frame] = new Dc6Frame(in.readSlice(nextOffset - offset));
|
||||
box.max(f.box);
|
||||
} finally {
|
||||
MDC.remove("frame");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
log.trace("disposing dcc pixmaps");
|
||||
for (int i = 0, s = pixmap.length; i < s; i++) {
|
||||
if (pixmap[i] == null) continue;
|
||||
pixmap[i].dispose();
|
||||
pixmap[i] = null;
|
||||
}
|
||||
|
||||
log.trace("disposing dcc textures");
|
||||
for (int i = 0, s = texture.length; i < s; i++) {
|
||||
if (texture[i] == null) continue;
|
||||
texture[i].dispose();
|
||||
texture[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dc6Frame[] frames() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dc6Frame frame(int f) {
|
||||
return frames[f];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BBox box() {
|
||||
return box;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Dc6Frame extends Dc.Frame {
|
||||
// Dc
|
||||
final boolean flipY;
|
||||
final int width;
|
||||
final int height;
|
||||
final int xOffset;
|
||||
final int yOffset;
|
||||
|
||||
final BBox box;
|
||||
final TextureRegion texture;
|
||||
|
||||
// Dc6
|
||||
final int unk0; // unused
|
||||
final int nextOffset; // file offset of next frame, unused (header value used in preference)
|
||||
final int length; // unused
|
||||
final ByteInput in;
|
||||
|
||||
Dc6Frame(ByteInput in) {
|
||||
this.in = in;
|
||||
flipY = in.read32() != 0;
|
||||
width = in.readSafe32u();
|
||||
height = in.readSafe32u();
|
||||
xOffset = in.read32();
|
||||
yOffset = in.read32();
|
||||
unk0 = in.readSafe32u();
|
||||
nextOffset = in.readSafe32u();
|
||||
length = in.readSafe32u();
|
||||
box = new BBox().asBox(xOffset, flipY ? yOffset : yOffset - height, width, height);
|
||||
texture = MISSING_TEXTURE == null ? new TextureRegion() : new TextureRegion(MISSING_TEXTURE);
|
||||
|
||||
log.trace("flipY: {}", flipY);
|
||||
log.trace("width: {}", width);
|
||||
log.trace("height: {}", height);
|
||||
log.trace("xOffset: {}", xOffset);
|
||||
log.trace("yOffset: {}", yOffset);
|
||||
log.tracef("unk0: 0x%x", unk0);
|
||||
log.tracef("nextOffset: 0x%x", nextOffset);
|
||||
log.tracef("length: 0x%x", length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flipY() {
|
||||
return flipY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int width() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int height() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int xOffset() {
|
||||
return xOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int yOffset() {
|
||||
return yOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BBox box() {
|
||||
return box;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion texture() {
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
75
core/src/main/java/com/riiablo/file/Dc6Decoder.java
Normal file
75
core/src/main/java/com/riiablo/file/Dc6Decoder.java
Normal file
@ -0,0 +1,75 @@
|
||||
package com.riiablo.file;
|
||||
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.utils.BufferUtils;
|
||||
|
||||
import com.riiablo.codec.util.BBox;
|
||||
import com.riiablo.file.Dc6.Dc6Direction;
|
||||
import com.riiablo.file.Dc6.Dc6Frame;
|
||||
import com.riiablo.graphics.PaletteIndexedPixmap;
|
||||
import com.riiablo.io.ByteInput;
|
||||
|
||||
public class Dc6Decoder {
|
||||
static final boolean DEBUG = !true;
|
||||
static final int MAX_WIDTH = 256;
|
||||
static final int MAX_HEIGHT = 256;
|
||||
|
||||
final byte[] bmp = PlatformDependent.allocateUninitializedArray(MAX_WIDTH * MAX_HEIGHT); // 256x256 px
|
||||
|
||||
public void decode(Dc6 dc6, int d) {
|
||||
decode(dc6, d, dc6.directions[d]);
|
||||
}
|
||||
|
||||
void decode(Dc6 dc6, int d, Dc6Direction dir) {
|
||||
decodeFrames(dir, dc6.numFrames);
|
||||
}
|
||||
|
||||
void decodeFrames(Dc6Direction dir, int numFrames) {
|
||||
final Dc6Frame[] frames = dir.frames;
|
||||
for (int f = 0, s = numFrames; f < s; f++) {
|
||||
decodeFrame(dir, frames[f], f);
|
||||
|
||||
final BBox box = frames[f].box;
|
||||
final Pixmap[] pixmap = dir.pixmap;
|
||||
final Pixmap p = pixmap[f] = new PaletteIndexedPixmap(box.width, box.height);
|
||||
BufferUtils.copy(bmp, 0, p.getPixels().rewind(), box.width * box.height);
|
||||
}
|
||||
}
|
||||
|
||||
void decodeFrame(Dc6Direction dir, Dc6Frame frame, int f) {
|
||||
final ByteInput in = frame.in;
|
||||
|
||||
final int width = frame.width;
|
||||
final int height = frame.height;
|
||||
int x = 0;
|
||||
int y = height - 1;
|
||||
|
||||
int rawIndex = 0;
|
||||
for (final int s = frame.length; rawIndex < s;) {
|
||||
int chunkSize = in.read8u();
|
||||
rawIndex++;
|
||||
if (chunkSize == 0x80) {
|
||||
// eol
|
||||
Arrays.fill(bmp, y * width + x, (y + 1) * width, (byte) 0);
|
||||
x = 0;
|
||||
y--;
|
||||
} else if ((chunkSize & 0x80) != 0) {
|
||||
// number of transparent pixels
|
||||
final int length = (chunkSize & 0x7f);
|
||||
Arrays.fill(bmp, y * width + x, y * width + x + length, (byte) 0);
|
||||
x += length;
|
||||
} else {
|
||||
// number of colors to read
|
||||
assert chunkSize + x <= width : "chunkSize(" + chunkSize + ") + x(" + x + ") > width(" + width + ")";
|
||||
in.readBytes(bmp, y * width + x, chunkSize);
|
||||
rawIndex += chunkSize;
|
||||
x += chunkSize;
|
||||
}
|
||||
}
|
||||
|
||||
assert rawIndex == frame.length : "rawIndex(" + rawIndex + ") != frame.length(" + frame.length + ")";
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ public final class Dcc extends Dc<Dcc.DccDirection> {
|
||||
final byte version;
|
||||
//final int numDirections; // Dc#numDirections
|
||||
//final int numFrames; // Dc#numFrames
|
||||
//final int[] dirOffsets; // Dc#dirOffsets;
|
||||
final int[] dirOffsets;
|
||||
|
||||
public static Dcc read(FileHandle handle, InputStream stream) {
|
||||
SwappedDataInputStream in = new SwappedDataInputStream(stream);
|
||||
@ -80,9 +80,10 @@ public final class Dcc extends Dc<Dcc.DccDirection> {
|
||||
int numFrames,
|
||||
int[] dirOffsets
|
||||
) {
|
||||
super(handle, numDirections, numFrames, dirOffsets, DccDirection.class);
|
||||
super(handle, numDirections, numFrames, DccDirection.class);
|
||||
this.signature = signature;
|
||||
this.version = version;
|
||||
this.dirOffsets = dirOffsets;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -90,6 +91,11 @@ public final class Dcc extends Dc<Dcc.DccDirection> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dirOffset(int d) {
|
||||
return dirOffsets[d];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dcc read(ByteBuf buffer, int direction) {
|
||||
super.read(buffer, direction);
|
||||
|
145
core/src/test/java/com/riiablo/file/Dc6DecoderTest.java
Normal file
145
core/src/test/java/com/riiablo/file/Dc6DecoderTest.java
Normal file
@ -0,0 +1,145 @@
|
||||
package com.riiablo.file;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.params.*;
|
||||
import org.junit.jupiter.params.provider.*;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
import io.netty.util.concurrent.ImmediateEventExecutor;
|
||||
import io.netty.util.concurrent.Promise;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.ApplicationListener;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||
|
||||
import com.riiablo.RiiabloTest;
|
||||
import com.riiablo.asset.AssetDesc;
|
||||
import com.riiablo.asset.AssetUtils;
|
||||
import com.riiablo.asset.param.DcParams;
|
||||
import com.riiablo.asset.param.MpqParams;
|
||||
import com.riiablo.codec.Palette;
|
||||
import com.riiablo.codec.util.BBox;
|
||||
import com.riiablo.graphics.BlendMode;
|
||||
import com.riiablo.graphics.PaletteIndexedBatch;
|
||||
import com.riiablo.mpq_bytebuf.MpqFileHandle;
|
||||
import com.riiablo.mpq_bytebuf.MpqFileResolver;
|
||||
import com.riiablo.util.InstallationFinder;
|
||||
|
||||
public class Dc6DecoderTest {
|
||||
@BeforeEach
|
||||
public void beforeEach() {
|
||||
RiiabloTest.clearGdxContext();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"data\\global\\monsters\\ty\\ra\\tyralitnuhth.dc6",
|
||||
})
|
||||
void draw_pixmaps(String dc6Name) throws Exception {
|
||||
FileHandle testHome = InstallationFinder.getInstance().defaultHomeDir();
|
||||
Dc6Decoder decoder = new Dc6Decoder();
|
||||
EventExecutor executor = ImmediateEventExecutor.INSTANCE;
|
||||
AssetDesc<Dc6> parent = AssetDesc.of(dc6Name, Dc6.class, DcParams.of(-1));
|
||||
MpqFileResolver resolver = new MpqFileResolver(testHome);
|
||||
MpqFileHandle dc6Handle = resolver.resolve(parent);
|
||||
InputStream stream = dc6Handle.bufferStream(executor, dc6Handle.sectorSize()).get();
|
||||
Dc6 dc6 = Dc6.read(dc6Handle, stream);
|
||||
int offset = dc6.dirOffset(0);
|
||||
int nextOffset = dc6.dirOffset(1);
|
||||
ByteBuf buffer = dc6Handle.bufferAsync(executor, offset, nextOffset - offset).get();
|
||||
dc6.read(buffer, 0);
|
||||
|
||||
final Promise<?> promise = executor.newPromise();
|
||||
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration() {{
|
||||
title = dc6Name;
|
||||
forceExit = false;
|
||||
}};
|
||||
ApplicationListener listener = new ApplicationAdapter() {
|
||||
PaletteIndexedBatch batch;
|
||||
ShaderProgram shader;
|
||||
Texture paletteTexture;
|
||||
int frame = 0;
|
||||
float updater = 0f;
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
try {
|
||||
create0();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace(System.err);
|
||||
Gdx.app.exit();
|
||||
}
|
||||
}
|
||||
|
||||
void create0() {
|
||||
decoder.decode(dc6, 0);
|
||||
dc6.uploadTextures(0);
|
||||
|
||||
String paletteName = "data\\global\\palette\\ACT1\\pal.dat";
|
||||
AssetDesc<Palette> paletteDesc = AssetDesc.of(paletteName, Palette.class, MpqParams.of());
|
||||
MpqFileHandle paletteHandle = resolver.resolve(paletteDesc);
|
||||
Palette palette = Palette.loadFromStream(paletteHandle.stream());
|
||||
paletteTexture = palette.render();
|
||||
|
||||
ShaderProgram.pedantic = false;
|
||||
shader = new ShaderProgram(
|
||||
Gdx.files.internal("shaders/indexpalette3.vert"),
|
||||
Gdx.files.internal("shaders/indexpalette3.frag"));
|
||||
if (!shader.isCompiled()) {
|
||||
throw new GdxRuntimeException("Error compiling shader: " + shader.getLog());
|
||||
}
|
||||
batch = new PaletteIndexedBatch(1024, shader);
|
||||
batch.setGamma(1.2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
// Gdx.gl.glClearColor(0.3f, 0.3f, 0.3f, 1);
|
||||
Gdx.gl.glClearColor(1f, 1f, 1f, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
batch.setBlendMode(BlendMode.NONE);
|
||||
batch.begin(paletteTexture);
|
||||
updater += Gdx.graphics.getDeltaTime();
|
||||
final float fdelay = 0.10f;
|
||||
if (updater > fdelay) {
|
||||
updater -= fdelay;
|
||||
frame++;
|
||||
if (frame >= dc6.numFrames) {
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
Dc6.Dc6Direction dir = dc6.directions[0];
|
||||
BBox box = dir.frames[frame].box;
|
||||
batch.draw(dir.texture[frame],
|
||||
dir.box.width + box.xMin, -box.yMax,
|
||||
box.width, box.height);
|
||||
batch.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// also releases dccHandle reference
|
||||
// release twice, once for header, again for direction
|
||||
ReferenceCountUtil.release(dc6);
|
||||
ReferenceCountUtil.release(dc6);
|
||||
AssetUtils.dispose(paletteTexture);
|
||||
AssetUtils.dispose(shader);
|
||||
AssetUtils.dispose(batch);
|
||||
promise.setSuccess(null);
|
||||
}
|
||||
};
|
||||
new LwjglApplication(listener, config);
|
||||
promise.awaitUninterruptibly();
|
||||
resolver.dispose();
|
||||
}
|
||||
}
|
48
core/src/test/java/com/riiablo/file/Dc6Test.java
Normal file
48
core/src/test/java/com/riiablo/file/Dc6Test.java
Normal file
@ -0,0 +1,48 @@
|
||||
package com.riiablo.file;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
import io.netty.util.concurrent.ImmediateEventExecutor;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.riiablo.RiiabloTest;
|
||||
import com.riiablo.asset.AssetDesc;
|
||||
import com.riiablo.asset.param.DcParams;
|
||||
import com.riiablo.logger.Level;
|
||||
import com.riiablo.logger.LogManager;
|
||||
import com.riiablo.mpq_bytebuf.MpqFileHandle;
|
||||
import com.riiablo.mpq_bytebuf.MpqFileResolver;
|
||||
|
||||
public class Dc6Test extends RiiabloTest {
|
||||
@BeforeAll
|
||||
public static void before() {
|
||||
LogManager.setLevel("com.riiablo.file.Dc6", Level.TRACE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("dc6_buffers w/ data\\global\\monsters\\ty\\ra\\tyralitnuhth.dc6")
|
||||
void dc6_buffers() throws Exception {
|
||||
EventExecutor executor = ImmediateEventExecutor.INSTANCE;
|
||||
MpqFileResolver resolver = new MpqFileResolver();
|
||||
try {
|
||||
final String dc6Name = "data\\global\\monsters\\ty\\ra\\tyralitnuhth.dc6";
|
||||
AssetDesc<Dc6> parent = AssetDesc.of(dc6Name, Dc6.class, DcParams.of(-1));
|
||||
MpqFileHandle dc6Handle = resolver.resolve(parent);
|
||||
try {
|
||||
InputStream stream = dc6Handle.bufferStream(executor, dc6Handle.sectorSize()).get();
|
||||
Dc6 dc6 = Dc6.read(dc6Handle, stream);
|
||||
int offset = dc6.dirOffset(0);
|
||||
int nextOffset = dc6.dirOffset(1);
|
||||
ByteBuf buffer = dc6Handle.bufferAsync(executor, offset, nextOffset - offset).get();
|
||||
dc6.read(buffer, 0);
|
||||
} finally {
|
||||
ReferenceCountUtil.release(dc6Handle);
|
||||
}
|
||||
} finally {
|
||||
resolver.dispose();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user