// <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::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];
  }
}


}
