public void writeProperties(DataOutput buffer, List<L2Property> list, UnrealPackageReadOnly up) throws UnrealException { try { for (L2Property property : list) { Property template = property.getTemplate(); for (int i = 0; i < property.getSize(); i++) { Object obj = property.getAt(i); if (obj == null) continue; ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutput objBuffer = new DataOutputStream(baos, buffer.getCharset()); AtomicBoolean array = new AtomicBoolean(i > 0); AtomicReference<String> structName = new AtomicReference<>(); AtomicReference<Type> type = new AtomicReference<>( Type.valueOf( template.getClass().getSimpleName().replace("Property", "").toUpperCase())); write(objBuffer, template, obj, array, structName, type, up); byte[] bytes = baos.toByteArray(); int size = getPropertySize(bytes.length); int ord = type.get().ordinal(); if (ord == 8) // FIXME ord = 5; int info = (array.get() ? 1 << 7 : 0) | (size << 4) | ord; buffer.writeCompactInt(up.nameReference(template.getEntry().getObjectName().getName())); buffer.writeByte(info); if (type.get() == Type.STRUCT) buffer.writeCompactInt(up.nameReference(structName.get())); switch (size) { case 5: buffer.writeByte(bytes.length); break; case 6: buffer.writeShort(bytes.length); break; case 7: buffer.writeInt(bytes.length); break; } if (i > 0) buffer.writeByte(i); buffer.write(bytes); } } buffer.writeCompactInt(up.nameReference("None")); } catch (IOException e) { throw new UnrealException(e); } }
public List<L2Property> readProperties( DataInput dataInput, String objClass, UnrealPackageReadOnly up) throws UnrealException { List<L2Property> properties = new ArrayList<>(); List<Property> classTemplate = unrealClassLoader.getStructProperties(objClass); Collections.reverse(classTemplate); try { String name; while (!(name = up.getNameTable().get(dataInput.readCompactInt()).getName()).equals("None")) { int info = dataInput.readUnsignedByte(); Type propertyType = Type.values()[info & 0b1111]; // TODO int sizeType = (info >> 4) & 0b111; boolean array = info >> 7 == 1; String structName = propertyType.equals(Type.STRUCT) ? up.getNameTable().get(dataInput.readCompactInt()).getName() : null; int size = readPropertySize(sizeType, dataInput); int arrayIndex = array && !propertyType.equals(Type.BOOL) ? dataInput.readCompactInt() : 0; byte[] objBytes = new byte[size]; dataInput.readFully(objBytes); final String n = name; PropertiesUtil.getAt(properties, n); L2Property property = PropertiesUtil.getAt(properties, n); if (property == null) { Property template = classTemplate .stream() .filter(pt -> pt.getEntry().getObjectName().getName().equalsIgnoreCase((n))) .findAny() .orElse(null); if (template == null) throw new UnrealException(objClass + ": Property template not found: " + name); property = new L2Property(template, up); properties.add(property); } if (structName != null && !"Vector".equals(structName) && !"Rotator".equals(structName) && !"Color".equals(structName)) { StructProperty structProperty = (StructProperty) property.getTemplate(); structName = structProperty.getStructType().getObjectFullName(); } UnrealPackageReadOnly.ExportEntry arrayInner = null; if (propertyType.equals(Type.ARRAY)) { ArrayProperty arrayProperty = (ArrayProperty) property.getTemplate(); arrayInner = (UnrealPackageReadOnly.ExportEntry) arrayProperty.getInner(); } DataInput objBuffer = new DataInputStream(new ByteArrayInputStream(objBytes), dataInput.getCharset()); property.putAt( arrayIndex, read( objBuffer, propertyType, array, arrayInner, structName, up, objClass, property.getName())); property.setType(propertyType); } } catch (IOException e) { throw new UnrealException(e); } return properties; }
public List<L2Property> readStructBin( DataInput objBuffer, String structName, UnrealPackageReadOnly up) throws UnrealException { List<Property> properties = unrealClassLoader.getStructProperties(structName); try { switch (structName) { case "Core.Object.Vector": { L2Property x = new L2Property(properties.get(0), up); x.putAt(0, objBuffer.readFloat()); L2Property y = new L2Property(properties.get(1), up); y.putAt(0, objBuffer.readFloat()); L2Property z = new L2Property(properties.get(2), up); z.putAt(0, objBuffer.readFloat()); return Arrays.asList(x, y, z); } case "Core.Object.Rotator": { L2Property pitch = new L2Property(properties.get(0), up); pitch.putAt(0, objBuffer.readInt()); L2Property yaw = new L2Property(properties.get(1), up); yaw.putAt(0, objBuffer.readInt()); L2Property roll = new L2Property(properties.get(2), up); roll.putAt(0, objBuffer.readInt()); return Arrays.asList(pitch, yaw, roll); } case "Core.Object.Color": { L2Property b = new L2Property(properties.get(0), up); b.putAt(0, objBuffer.readUnsignedByte()); L2Property g = new L2Property(properties.get(1), up); g.putAt(0, objBuffer.readUnsignedByte()); L2Property r = new L2Property(properties.get(2), up); r.putAt(0, objBuffer.readUnsignedByte()); L2Property a = new L2Property(properties.get(3), up); a.putAt(0, objBuffer.readUnsignedByte()); return Arrays.asList(b, g, r, a); } case "Fire.FireTexture.Spark": { L2Property type = new L2Property(properties.get(0), up); type.putAt(0, objBuffer.readUnsignedByte()); L2Property heat = new L2Property(properties.get(1), up); heat.putAt(0, objBuffer.readUnsignedByte()); L2Property x = new L2Property(properties.get(2), up); x.putAt(0, objBuffer.readUnsignedByte()); L2Property y = new L2Property(properties.get(3), up); y.putAt(0, objBuffer.readUnsignedByte()); L2Property byteA = new L2Property(properties.get(4), up); byteA.putAt(0, objBuffer.readUnsignedByte()); L2Property byteB = new L2Property(properties.get(5), up); byteB.putAt(0, objBuffer.readUnsignedByte()); L2Property byteC = new L2Property(properties.get(6), up); byteC.putAt(0, objBuffer.readUnsignedByte()); L2Property byteD = new L2Property(properties.get(7), up); byteD.putAt(0, objBuffer.readUnsignedByte()); return Arrays.asList(type, heat, x, y, byteA, byteB, byteC, byteD); } default: throw new UnsupportedOperationException("Not implemented"); // TODO } } catch (IOException e) { throw new UnrealException(e); } }