Skip to content

Commit

Permalink
Extract shared logic of type readers
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadelessFox committed Dec 11, 2024
1 parent 14d29f1 commit 00091d0
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 188 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.shade.decima.game.hfw;

import com.shade.decima.game.hfw.rtti.HFWTypeFactory;
import com.shade.decima.game.hfw.rtti.HFWTypeReader;
import com.shade.decima.game.hfw.rtti.HorizonForbiddenWest;
import com.shade.decima.game.hfw.rtti.RTTIBinaryReader;
import com.shade.decima.game.hfw.storage.*;
import com.shade.util.NotNull;
import com.shade.util.io.BinaryReader;
Expand All @@ -21,7 +21,7 @@ public static void main(String[] args) throws IOException {
StreamingGraphResource graph;

try (var reader = BinaryReader.open(resolver.resolve("cache:package/streaming_graph.core"))) {
var object = new RTTIBinaryReader().readObject(reader, factory).object();
var object = new HFWTypeReader().readObject(reader, factory).object();
graph = new StreamingGraphResource((HorizonForbiddenWest.StreamingGraphResource) object, factory);
}

Expand All @@ -33,7 +33,7 @@ public static void main(String[] args) throws IOException {
ObjectStreamingSystem system = new ObjectStreamingSystem(device, graph);
StreamingObjectReader reader = new StreamingObjectReader(system, factory);

RTTIBinaryReader.ObjectInfo result = reader.readObject("00377119-c8e7-45d7-b37d-0f6e240c3116");
HFWTypeReader.ObjectInfo result = reader.readObject("00377119-c8e7-45d7-b37d-0f6e240c3116");
System.out.println(result);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.shade.decima.game.hfw.rtti;

import com.shade.decima.game.hfw.rtti.HorizonForbiddenWest.GGUUID;
import com.shade.decima.rtti.data.ExtraBinaryDataHolder;
import com.shade.decima.rtti.data.Ref;
import com.shade.decima.rtti.factory.TypeFactory;
import com.shade.decima.rtti.io.AbstractTypeReader;
import com.shade.decima.rtti.runtime.*;
import com.shade.util.NotImplementedException;
import com.shade.util.NotNull;
Expand All @@ -20,7 +20,7 @@

import static com.shade.decima.game.hfw.rtti.HorizonForbiddenWest.RTTIRefObject;

public class RTTIBinaryReader {
public class HFWTypeReader extends AbstractTypeReader {
public record ObjectInfo(@NotNull RTTIRefObject object, @NotNull ClassTypeInfo info) {}

@NotNull
Expand All @@ -45,19 +45,9 @@ public ObjectInfo readObject(@NotNull BinaryReader reader, @NotNull TypeFactory
}

@NotNull
private Object readType(@NotNull TypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
return switch (info) {
case AtomTypeInfo t -> readAtom(t, reader, factory);
case EnumTypeInfo t -> readEnum(t, reader, factory);
case ClassTypeInfo t -> readCompound(t, reader, factory);
case ContainerTypeInfo t -> readContainer(t, reader, factory);
case PointerTypeInfo t -> readPointer(t, reader, factory);
};
}

@NotNull
@Override
@SuppressWarnings("DuplicateBranchesInSwitch")
private Object readAtom(@NotNull AtomTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
protected Object readAtom(@NotNull AtomTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
return switch (info.name().name()) {
// Simple types
case "bool" -> reader.readByteBoolean();
Expand Down Expand Up @@ -100,30 +90,32 @@ private Object readAtom(@NotNull AtomTypeInfo info, @NotNull BinaryReader reader
}

@NotNull
private Object readEnum(@NotNull EnumTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
@Override
protected Object readEnum(@NotNull EnumTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
throw new NotImplementedException();
}

@NotNull
protected Object readCompound(@NotNull ClassTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
Object object = info.newInstance();
for (ClassAttrInfo attr : info.serializableAttrs()) {
attr.set(object, readType(attr.type().get(), reader, factory));
}
if (object instanceof ExtraBinaryDataHolder holder) {
holder.deserialize(reader, factory);
}
return object;
}

@NotNull
private Object readContainer(@NotNull ContainerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
@Override
protected Object readContainer(@NotNull ContainerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
return switch (info.name().name()) {
case "HashMap", "HashSet" -> readHashContainer(info, reader, factory);
default -> readSimpleContainer(info, reader, factory);
};
}

@Nullable
@Override
protected Object readPointer(@NotNull PointerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
if (!reader.readByteBoolean()) {
return null;
} else if (info.name().name().equals("UUIDRef")) {
return new UUIDRef<>((GGUUID) readCompound(factory.get(GGUUID.class), reader, factory));
} else {
return new InternalLink<>();
}
}

@NotNull
private Object readSimpleContainer(@NotNull ContainerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
var itemInfo = info.itemType().get();
Expand All @@ -143,7 +135,7 @@ private Object readSimpleContainer(@NotNull ContainerTypeInfo info, @NotNull Bin

var array = Array.newInstance((Class<?>) itemType, count);
for (int i = 0; i < count; i++) {
Array.set(array, i, readType(itemInfo, reader, factory));
Array.set(array, i, read(itemInfo, reader, factory));
}

if (info.type() == List.class) {
Expand All @@ -158,17 +150,6 @@ private Object readHashContainer(@NotNull ContainerTypeInfo info, @NotNull Binar
throw new NotImplementedException();
}

@Nullable
protected Object readPointer(@NotNull PointerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
if (!reader.readByteBoolean()) {
return null;
} else if (info.name().name().equals("UUIDRef")) {
return new UUIDRef<>((GGUUID) readCompound(factory.get(GGUUID.class), reader, factory));
} else {
return new InternalLink<>();
}
}

@NotNull
private static String readString(@NotNull BinaryReader reader) throws IOException {
var length = reader.readInt();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.shade.decima.game.hfw.storage;

import com.shade.decima.game.hfw.rtti.HorizonForbiddenWest.*;
import com.shade.decima.game.hfw.rtti.RTTIBinaryReader;
import com.shade.decima.game.hfw.rtti.HFWTypeReader;
import com.shade.decima.rtti.factory.TypeFactory;
import com.shade.decima.rtti.runtime.ClassTypeInfo;
import com.shade.decima.rtti.runtime.PointerTypeInfo;
Expand All @@ -20,7 +19,7 @@

import static com.shade.decima.game.hfw.rtti.HorizonForbiddenWest.*;

public class StreamingObjectReader extends RTTIBinaryReader {
public class StreamingObjectReader extends HFWTypeReader {
private static final Logger log = LoggerFactory.getLogger(StreamingObjectReader.class);
private static final boolean DEBUG = true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.shade.decima.game.Asset;
import com.shade.decima.game.AssetId;
import com.shade.decima.game.hrzr.rtti.HRZRTypeFactory;
import com.shade.decima.game.hrzr.rtti.RTTIBinaryReader;
import com.shade.decima.game.hrzr.rtti.HRZRTypeReader;
import com.shade.decima.game.hrzr.storage.PackFileManager;
import com.shade.decima.game.hrzr.storage.PathResolver;
import com.shade.decima.rtti.factory.TypeNotFoundException;
Expand All @@ -29,6 +29,7 @@ public static void main(String[] args) throws IOException {
log.info("Loading archives");
try (var manager = new PackFileManager(resolver)) {
var factory = new HRZRTypeFactory();
var reader = new HRZRTypeReader();
var assets = new HashMap<AssetId, Asset>();

for (Asset asset : manager.assets()) {
Expand All @@ -43,13 +44,11 @@ public static void main(String[] args) throws IOException {
var id = asset.id();
var data = BinaryReader.wrap(manager.load(id));

try (RTTIBinaryReader reader = new RTTIBinaryReader(data, factory)) {
try {
List<Object> objects = reader.read();
log.info("[{}/{}] Read {} objects", index, slice.size(), objects.size());
} catch (TypeNotFoundException e) {
log.error("[{}/{}] Unable to read: {}", index, slice.size(), e.getMessage());
}
try {
List<Object> objects = reader.read(data, factory);
log.info("[{}/{}] Read {} objects", index, slice.size(), objects.size());
} catch (TypeNotFoundException e) {
log.error("[{}/{}] Unable to read: {}", index, slice.size(), e.getMessage());
}

index++;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.shade.decima.game.hrzr.rtti;

import com.shade.decima.rtti.data.ExtraBinaryDataHolder;
import com.shade.decima.rtti.data.Ref;
import com.shade.decima.rtti.data.Value;
import com.shade.decima.rtti.factory.TypeFactory;
import com.shade.decima.rtti.runtime.*;
import com.shade.decima.rtti.io.AbstractTypeReader;
import com.shade.decima.rtti.runtime.AtomTypeInfo;
import com.shade.decima.rtti.runtime.ContainerTypeInfo;
import com.shade.decima.rtti.runtime.EnumTypeInfo;
import com.shade.decima.rtti.runtime.PointerTypeInfo;
import com.shade.util.NotImplementedException;
import com.shade.util.NotNull;
import com.shade.util.Nullable;
import com.shade.util.hash.Hashing;
import com.shade.util.io.BinaryReader;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Array;
import java.nio.charset.StandardCharsets;
Expand All @@ -24,32 +26,24 @@

import static com.shade.decima.game.hrzr.rtti.HorizonZeroDawnRemastered.*;

public class RTTIBinaryReader implements Closeable {
private final BinaryReader reader;
private final TypeFactory factory;

public class HRZRTypeReader extends AbstractTypeReader {
private final List<Ref<?>> pointers = new ArrayList<>();

public RTTIBinaryReader(@NotNull BinaryReader reader, @NotNull TypeFactory factory) {
this.reader = reader;
this.factory = factory;
}

@NotNull
public List<Object> read() throws IOException {
public List<Object> read(@NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
List<Object> objects = new ArrayList<>();
readObjects(objects);
readObjects(objects, reader, factory);
resolvePointers(objects);
return objects;
}

private void readObjects(@NotNull List<Object> objects) throws IOException {
private void readObjects(@NotNull List<Object> objects, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
while (reader.remaining() > 0) {
var hash = reader.readLong();
var size = reader.readInt();

var start = reader.position();
var object = readCompound(factory.get(HRZRTypeId.of(hash)));
var object = readCompound(factory.get(HRZRTypeId.of(hash)), reader, factory);
var end = reader.position();

if (end - start != size) {
Expand Down Expand Up @@ -82,25 +76,10 @@ private void resolvePointers(@NotNull List<Object> objects) {
pointers.clear();
}

@Override
public void close() throws IOException {
reader.close();
}

@Nullable
private Object readType(@NotNull TypeInfo info) throws IOException {
return switch (info) {
case AtomTypeInfo t -> readAtom(t);
case EnumTypeInfo t -> readEnum(t);
case ClassTypeInfo t -> readCompound(t);
case ContainerTypeInfo t -> readContainer(t);
case PointerTypeInfo t -> readPointer(t);
};
}

@NotNull
@Override
@SuppressWarnings("DuplicateBranchesInSwitch")
private Object readAtom(@NotNull AtomTypeInfo info) throws IOException {
protected Object readAtom(@NotNull AtomTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
return switch (info.name().name()) {
// Simple types
case "bool" -> reader.readByteBoolean();
Expand Down Expand Up @@ -133,7 +112,8 @@ private Object readAtom(@NotNull AtomTypeInfo info) throws IOException {
}

@NotNull
private Object readEnum(@NotNull EnumTypeInfo info) throws IOException {
@Override
protected Object readEnum(@NotNull EnumTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
int value = switch (info.size()) {
case Byte.BYTES -> reader.readByte();
case Short.BYTES -> reader.readShort();
Expand All @@ -153,28 +133,17 @@ private static <T> T uncheckedCast(Object object) {
}

@NotNull
private Object readCompound(@NotNull ClassTypeInfo info) throws IOException {
Object object = info.newInstance();
for (ClassAttrInfo attr : info.serializableAttrs()) {
attr.set(object, readType(attr.type().get()));
}
if (object instanceof ExtraBinaryDataHolder holder) {
holder.deserialize(reader, factory);
}
return object;
}

@NotNull
private Object readContainer(@NotNull ContainerTypeInfo info) throws IOException {
@Override
protected Object readContainer(@NotNull ContainerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
return switch (info.name().name()) {
// TODO: Containers seem to have a special flag denoting whether it's an array or a map
case "HashMap", "HashSet" -> readHashContainer(info);
default -> readSimpleContainer(info);
case "HashMap", "HashSet" -> readHashContainer(info, reader, factory);
default -> readSimpleContainer(info, reader, factory);
};
}

@NotNull
private Object readSimpleContainer(@NotNull ContainerTypeInfo info) throws IOException {
private Object readSimpleContainer(@NotNull ContainerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
var itemInfo = info.itemType().get();
var itemType = itemInfo.type();
var count = reader.readInt();
Expand All @@ -195,7 +164,7 @@ private Object readSimpleContainer(@NotNull ContainerTypeInfo info) throws IOExc
// Slow path
var array = Array.newInstance((Class<?>) itemType, count);
for (int i = 0; i < count; i++) {
Array.set(array, i, readType(itemInfo));
Array.set(array, i, read(itemInfo, reader, factory));
}

if (info.type() == List.class) {
Expand All @@ -206,7 +175,7 @@ private Object readSimpleContainer(@NotNull ContainerTypeInfo info) throws IOExc
}

@NotNull
private Object readHashContainer(@NotNull ContainerTypeInfo info) throws IOException {
private Object readHashContainer(@NotNull ContainerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
var itemInfo = info.itemType().get();
var itemType = itemInfo.type();
var count = reader.readInt();
Expand All @@ -217,23 +186,24 @@ private Object readHashContainer(@NotNull ContainerTypeInfo info) throws IOExcep
// We don't actually need to store or use it - but we'll have to compute it
// when serialization support is added
int hash = reader.readInt();
Array.set(array, i, readType(itemInfo));
Array.set(array, i, read(itemInfo, reader, factory));
}

// TODO: Use specialized type (Map, Set, etc.)
return Arrays.asList((Object[]) array);
}

@Nullable
private Ref<?> readPointer(@NotNull PointerTypeInfo info) throws IOException {
@Override
protected Ref<?> readPointer(@NotNull PointerTypeInfo info, @NotNull BinaryReader reader, @NotNull TypeFactory factory) throws IOException {
var type = reader.readByte();
var gguuid = factory.get(GGUUID.class);
var ref = switch (type) {
case 0 -> null;
case 1 -> new InternalLink<>((GGUUID) readCompound(gguuid));
case 2 -> new ExternalLink<>((GGUUID) readCompound(gguuid), readString(reader));
case 3 -> new StreamingRef<>((GGUUID) readCompound(gguuid), readString(reader));
case 5 -> new UUIDRef<>((GGUUID) readCompound(gguuid));
case 1 -> new InternalLink<>((GGUUID) readCompound(gguuid, reader, factory));
case 2 -> new ExternalLink<>((GGUUID) readCompound(gguuid, reader, factory), readString(reader));
case 3 -> new StreamingRef<>((GGUUID) readCompound(gguuid, reader, factory), readString(reader));
case 5 -> new UUIDRef<>((GGUUID) readCompound(gguuid, reader, factory));
default -> throw new IllegalArgumentException("Unknown pointer type: " + type);
};
pointers.add(ref);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.shade.decima.game.until_dawn;
package com.shade.decima.game.until_dawn.rtti;

import com.shade.decima.game.until_dawn.rtti.UntilDawn;
import com.shade.decima.rtti.factory.AbstractTypeFactory;
import com.shade.decima.rtti.factory.TypeId;
import com.shade.decima.rtti.runtime.TypeInfo;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.shade.decima.game.until_dawn;
package com.shade.decima.game.until_dawn.rtti;

import com.shade.decima.rtti.factory.TypeId;
import com.shade.util.NotNull;
Expand Down
Loading

0 comments on commit 00091d0

Please sign in to comment.