// automatically generated by the FlatBuffers compiler, do not modify

package MyGame.Example;

import com.google.flatbuffers.BaseVector;
import com.google.flatbuffers.BooleanVector;
import com.google.flatbuffers.ByteVector;
import com.google.flatbuffers.Constants;
import com.google.flatbuffers.DoubleVector;
import com.google.flatbuffers.FlatBufferBuilder;
import com.google.flatbuffers.FloatVector;
import com.google.flatbuffers.IntVector;
import com.google.flatbuffers.LongVector;
import com.google.flatbuffers.ShortVector;
import com.google.flatbuffers.StringVector;
import com.google.flatbuffers.Struct;
import com.google.flatbuffers.Table;
import com.google.flatbuffers.UnionVector;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

@SuppressWarnings("unused")
public final class ArrayStruct extends Struct {
  public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
  public ArrayStruct __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }

  public float a() { return bb.getFloat(bb_pos + 0); }
  public void mutateA(float a) { bb.putFloat(bb_pos + 0, a); }
  public int b(int j) { return bb.getInt(bb_pos + 4 + j * 4); }
  public void mutateB(int j, int b) { bb.putInt(bb_pos + 4 + j * 4, b); }
  public byte c() { return bb.get(bb_pos + 64); }
  public void mutateC(byte c) { bb.put(bb_pos + 64, c); }
  public MyGame.Example.NestedStruct d(int j) { return d(new MyGame.Example.NestedStruct(), j); }
  public MyGame.Example.NestedStruct d(MyGame.Example.NestedStruct obj, int j) { return obj.__assign(bb_pos + 72 + j * 32, bb); }
  public int e() { return bb.getInt(bb_pos + 136); }
  public void mutateE(int e) { bb.putInt(bb_pos + 136, e); }
  public long f(int j) { return bb.getLong(bb_pos + 144 + j * 8); }
  public void mutateF(int j, long f) { bb.putLong(bb_pos + 144 + j * 8, f); }

  public static int createArrayStruct(FlatBufferBuilder builder, float a, int[] b, byte c, int[][] d_a, byte[] d_b, byte[][] d_c, long[][] d_d, int e, long[] f) {
    builder.prep(8, 160);
    for (int _idx0 = 2; _idx0 > 0; _idx0--) {
      builder.putLong(f[_idx0-1]);
    }
    builder.pad(4);
    builder.putInt(e);
    for (int _idx0 = 2; _idx0 > 0; _idx0--) {
      builder.prep(8, 32);
      for (int _idx1 = 2; _idx1 > 0; _idx1--) {
        builder.putLong(d_d[_idx0-1][_idx1-1]);
      }
      builder.pad(5);
      for (int _idx1 = 2; _idx1 > 0; _idx1--) {
        builder.putByte(d_c[_idx0-1][_idx1-1]);
      }
      builder.putByte(d_b[_idx0-1]);
      for (int _idx1 = 2; _idx1 > 0; _idx1--) {
        builder.putInt(d_a[_idx0-1][_idx1-1]);
      }
    }
    builder.pad(7);
    builder.putByte(c);
    for (int _idx0 = 15; _idx0 > 0; _idx0--) {
      builder.putInt(b[_idx0-1]);
    }
    builder.putFloat(a);
    return builder.offset();
  }

  public static final class Vector extends BaseVector {
    public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; }

    public ArrayStruct get(int j) { return get(new ArrayStruct(), j); }
    public ArrayStruct get(ArrayStruct obj, int j) {  return obj.__assign(__element(j), bb); }
  }
  public ArrayStructT unpack() {
    ArrayStructT _o = new ArrayStructT();
    unpackTo(_o);
    return _o;
  }
  public void unpackTo(ArrayStructT _o) {
    float _oA = a();
    _o.setA(_oA);
    int[] _oB = _o.getB();
    for (int _j = 0; _j < 15; ++_j) { _oB[_j] = b(_j); }
    byte _oC = c();
    _o.setC(_oC);
    MyGame.Example.NestedStructT[] _oD = _o.getD();
    for (int _j = 0; _j < 2; ++_j) { _oD[_j] = d(_j).unpack(); }
    int _oE = e();
    _o.setE(_oE);
    long[] _oF = _o.getF();
    for (int _j = 0; _j < 2; ++_j) { _oF[_j] = f(_j); }
  }
  public static int pack(FlatBufferBuilder builder, ArrayStructT _o) {
    if (_o == null) return 0;
    int[] _b = _o.getB();
    int[][] _d_a = new int[2][2];
    for (int idx0 = 0; idx0 < 2; ++idx0) {for (int idx1 = 0; idx1 < 2; ++idx1) {_d_a[idx0][idx1] = _o.getD()[idx0].getA()[idx1];}}
    byte[] _d_b = new byte[2];
    for (int idx0 = 0; idx0 < 2; ++idx0) {_d_b[idx0] = _o.getD()[idx0].getB();}
    byte[][] _d_c = new byte[2][2];
    for (int idx0 = 0; idx0 < 2; ++idx0) {for (int idx1 = 0; idx1 < 2; ++idx1) {_d_c[idx0][idx1] = _o.getD()[idx0].getC()[idx1];}}
    long[][] _d_d = new long[2][2];
    for (int idx0 = 0; idx0 < 2; ++idx0) {for (int idx1 = 0; idx1 < 2; ++idx1) {_d_d[idx0][idx1] = _o.getD()[idx0].getD()[idx1];}}
    long[] _f = _o.getF();
    return createArrayStruct(
      builder,
      _o.getA(),
      _b,
      _o.getC(),
      _d_a,
      _d_b,
      _d_c,
      _d_d,
      _o.getE(),
      _f);
  }
}

