private Object read(
      DataInput objBuffer,
      Type propertyType,
      boolean array,
      UnrealPackageReadOnly.ExportEntry arrayInner,
      String structName,
      UnrealPackageReadOnly up)
      throws IOException {
    switch (propertyType) {
      case NONE:
        return null;
      case BYTE:
        return objBuffer.readUnsignedByte();
      case INT:
        return objBuffer.readInt();
      case BOOL:
        return array;
      case FLOAT:
        return objBuffer.readFloat();
      case OBJECT:
        return objBuffer.readCompactInt();
      case NAME:
        return objBuffer.readCompactInt();
      case ARRAY:
        int arraySize = objBuffer.readCompactInt();
        List<Object> arrayList = new ArrayList<>(arraySize);

        String a = arrayInner.getObjectClass().getObjectName().getName();
        Property f = unrealClassLoader.getProperty(arrayInner.getObjectFullName());

        array = false;
        arrayInner = null;
        structName = null;
        propertyType = Type.valueOf(a.replace("Property", "").toUpperCase());
        if (propertyType == Type.STRUCT) {
          StructProperty structProperty = (StructProperty) f;
          structName = structProperty.getStructType().getObjectFullName();
        }
        if (propertyType == Type.ARRAY) {
          array = true;
          ArrayProperty arrayProperty = (ArrayProperty) f;
          arrayInner = (UnrealPackageReadOnly.ExportEntry) arrayProperty.getInner();
        }

        for (int i = 0; i < arraySize; i++) {
          arrayList.add(read(objBuffer, propertyType, array, arrayInner, structName, up));
        }
        return arrayList;
      case STRUCT:
        return readStruct(objBuffer, structName, up);
        /*case VECTOR:
            return readStruct(objBuffer, "Vector", up);
        case ROTATOR:
            return readStruct(objBuffer, "Rotator", up);*/
      case STR:
        return objBuffer.readLine();
      default:
        throw new IllegalStateException("Unk type(" + structName + "): " + propertyType);
    }
  }
 private Object read(
     DataInput objBuffer,
     Type propertyType,
     boolean array,
     UnrealPackageReadOnly.ExportEntry arrayInner,
     String structName,
     UnrealPackageReadOnly up,
     String objClass,
     String pname)
     throws IOException {
   System.out.println("\t" + objClass + "->" + pname + " [" + propertyType.name() + "]");
   return read(objBuffer, propertyType, array, arrayInner, structName, up);
 }
  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;
  }