// <auto-generated>
//  automatically generated by the FlatBuffers compiler, do not modify
// </auto-generated>

namespace MyGame.Example
{

using global::System;
using global::System.Collections.Generic;
using global::Google.FlatBuffers;

public struct NestedStruct : IFlatbufferObject
{
  private Struct __p;
  public ByteBuffer ByteBuffer { get { return __p.bb; } }
  public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
  public NestedStruct __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }

  public int A(int j) { return __p.bb.GetInt(__p.bb_pos + 0 + j * 4); }
  public void MutateA(int j, int a) { __p.bb.PutInt(__p.bb_pos + 0 + j * 4, a); }
  public MyGame.Example.TestEnum B { get { return (MyGame.Example.TestEnum)__p.bb.GetSbyte(__p.bb_pos + 8); } }
  public void MutateB(MyGame.Example.TestEnum b) { __p.bb.PutSbyte(__p.bb_pos + 8, (sbyte)b); }
  public MyGame.Example.TestEnum C(int j) { return (MyGame.Example.TestEnum)__p.bb.GetSbyte(__p.bb_pos + 9 + j * 1); }
  public void MutateC(int j, MyGame.Example.TestEnum c) { __p.bb.PutSbyte(__p.bb_pos + 9 + j * 1, (sbyte)c); }
  public long D(int j) { return __p.bb.GetLong(__p.bb_pos + 16 + j * 8); }
  public void MutateD(int j, long d) { __p.bb.PutLong(__p.bb_pos + 16 + j * 8, d); }

  public static Offset<MyGame.Example.NestedStruct> CreateNestedStruct(FlatBufferBuilder builder, int[] A, MyGame.Example.TestEnum B, MyGame.Example.TestEnum[] C, long[] D) {
    builder.Prep(8, 32);
    for (int _idx0 = 2; _idx0 > 0; _idx0--) {
      builder.PutLong(D[_idx0-1]);
    }
    builder.Pad(5);
    for (int _idx0 = 2; _idx0 > 0; _idx0--) {
      builder.PutSbyte((sbyte)C[_idx0-1]);
    }
    builder.PutSbyte((sbyte)B);
    for (int _idx0 = 2; _idx0 > 0; _idx0--) {
      builder.PutInt(A[_idx0-1]);
    }
    return new Offset<MyGame.Example.NestedStruct>(builder.Offset);
  }
  public NestedStructT UnPack() {
    var _o = new NestedStructT();
    this.UnPackTo(_o);
    return _o;
  }
  public void UnPackTo(NestedStructT _o) {
    _o.A = new int[2];
    for (var _j = 0; _j < 2; ++_j) { _o.A[_j] = this.A(_j); }
    _o.B = this.B;
    _o.C = new MyGame.Example.TestEnum[2];
    for (var _j = 0; _j < 2; ++_j) { _o.C[_j] = this.C(_j); }
    _o.D = new long[2];
    for (var _j = 0; _j < 2; ++_j) { _o.D[_j] = this.D(_j); }
  }
  public static Offset<MyGame.Example.NestedStruct> Pack(FlatBufferBuilder builder, NestedStructT _o) {
    if (_o == null) return default(Offset<MyGame.Example.NestedStruct>);
    var _a = _o.A;
    var _c = _o.C;
    var _d = _o.D;
    return CreateNestedStruct(
      builder,
      _a,
      _o.B,
      _c,
      _d);
  }
}

public class NestedStructT
{
  [Newtonsoft.Json.JsonProperty("a")]
  public int[] A { get; set; }
  [Newtonsoft.Json.JsonProperty("b")]
  public MyGame.Example.TestEnum B { get; set; }
  [Newtonsoft.Json.JsonProperty("c")]
  public MyGame.Example.TestEnum[] C { get; set; }
  [Newtonsoft.Json.JsonProperty("d")]
  public long[] D { get; set; }

  public NestedStructT() {
    this.A = new int[2];
    this.B = MyGame.Example.TestEnum.A;
    this.C = new MyGame.Example.TestEnum[2];
    this.D = new long[2];
  }
}


}
