using System;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Data;
using Message;

namespace TMC_Tool
{
  public partial class MainWindow : Window
  {
    private List<byte> setObjGeoDataChanges(List<byte> bin)
    {
      List<byte> mdlGeoBin = new List<byte>();
      buildHeaderBaseBin(mdlGeoBin, "MdlGeo");
      mdlGeoBin[0x20] = 0x30;

      List<List<byte>> objGeoBins = new List<List<byte>>();

      List<byte> objGeoBin = new List<byte>();
      List<List<byte>> objBins = new List<List<byte>>();
      List<byte> declBin = new List<byte>();

      Dictionary<int, uint> vtxStartIndices = new Dictionary<int, uint>();
      Dictionary<int, uint> idxStartIndices = new Dictionary<int, uint>();
      Dictionary<int, byte> declIndices = new Dictionary<int, byte>();

      int IdxGrpCount = 0;

      foreach (var obj in tmcTables.ObjData)
      {
        ObjectGroup grp = tmcData.ObjGrp[obj.OriginalGrpIndex];
        if (obj.Grp == -1)
        {
          if (objGeoBin.Count != 0)
          {
            // objGeoBin構築
            buildBin(objGeoBin, objBins, declBin, false, false);
            objGeoBins.Add(objGeoBin);
          }

          objGeoBin = new List<byte>();
          buildHeaderBaseBin(objGeoBin, "ObjGeo");
          objGeoBin.AddRange(bin.Skip((int)grp.Offset + 0x30).Take(0x20).ToArray());
          objGeoBin[0x20] = 0x60;
          replaceByteList(objGeoBin, BitConverter.GetBytes(obj.ID), 0x34);

          // 名前部分追加
          // 15文字より大きい場合は*と後ろから14文字に
          // 0埋め
          string name = "";
          if (obj.Name.Length > 15)
          {
            name = "*" + obj.Name.Substring(obj.Name.Length - 14);
          }
          else
          {
            name = obj.Name;
          }
          objGeoBin.AddRange(Encoding.ASCII.GetBytes(name));
          objGeoBin.AddRange(new byte[(16 - (objGeoBin.Count % 16)) % 16]);

          #region Decl Build
          declBin = new List<byte>();
          buildHeaderBaseBin(declBin, "GeoDecl");
          declBin[0x20] = 0x30;

          byte declCount = 0;

          List<List<byte>> newBins = new List<List<byte>>();
          foreach (var viData in tmcTables.VIData)
          {
            if (viData.Use == 0) continue;

            if (viData.ObjID == obj.ID)
            {
              List<byte> newBin = bin.Skip((int)(grp.Offset + grp.DeclOffset + grp.Decl[(int)viData.OriginalDecl].Offset)).Take(0x40).ToList();

              declIndices[viData.Index] = declCount;
              declCount++;

              //replaceByteList(newBin, BitConverter.GetBytes(viData.IdxGrp), 0x0C);
              replaceByteList(newBin, BitConverter.GetBytes(IdxGrpCount), 0x0C);
              IdxGrpCount++;

              replaceByteList(newBin, BitConverter.GetBytes(viData.Index), 0x30);

              if (viData.IsAdded)
              {
                replaceByteList(newBin, BitConverter.GetBytes(1), 0x10);
                replaceByteList(newBin, BitConverter.GetBytes(1), 0x14);
              }
              else
              {
                replaceByteList(newBin, BitConverter.GetBytes(grp.Decl[(int)viData.OriginalDecl].IdxCount), 0x10);
                replaceByteList(newBin, BitConverter.GetBytes(grp.Decl[(int)viData.OriginalDecl].VtxCount), 0x14);
              }

              replaceByteList(newBin, BitConverter.GetBytes(Convert.ToInt32(viData.Datasize, 16)), 0x34);

              #region fvfdata追加
              int vdataLayersCount = 0;
              byte[] dataBin = new byte[8];
              byte offset = 0;

              if (viData.Position)
              {
                dataBin = new byte[8];
                if (viData.PositionType == "Float3")
                {
                  dataBin[4] = 2;
                  offset += 0x0C;
                }
                else
                {
                  dataBin[4] = 3;
                  offset += 0x10;
                }

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              if (viData.Normal)
              {
                dataBin = new byte[8];
                dataBin[2] = offset;
                if (viData.PositionType == "Float3")
                {
                  dataBin[4] = 2;
                  offset += 0x0C;
                }
                else
                {
                  dataBin[4] = 3;
                  offset += 0x10;
                }
                dataBin[6] = 3;

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              if (viData.BWeights)
              {
                dataBin = new byte[8];
                dataBin[2] = offset;
                if (viData.BWeightsType == "Float4")
                {
                  dataBin[4] = 3;
                  offset += 0x10;
                }
                else
                {
                  dataBin[4] = 13;
                  offset += 4;
                }
                dataBin[6] = 1;

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              if (viData.BIndices)
              {
                dataBin = new byte[8];
                dataBin[2] = offset;
                dataBin[4] = 5;
                dataBin[6] = 2;
                if (viData.BWeightsType == "Float4")
                  offset += 0x10;
                else
                  offset += 4;

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              if (viData.Tangent)
              {
                dataBin = new byte[8];
                dataBin[2] = offset;
                dataBin[4] = 3;
                dataBin[6] = 6;
                offset += 0x10;

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              if (viData.UVCount > 1)
              {
                dataBin = new byte[8];
                dataBin[2] = offset;
                dataBin[4] = 0x0B;
                dataBin[6] = 5;
                offset += 8;

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              if (viData.UVCount == 1 || viData.UVCount == 3)
              {
                dataBin = new byte[8];
                dataBin[2] = offset;
                dataBin[4] = 0x0A;
                dataBin[6] = 5;
                if (viData.UVCount == 3) dataBin[7] = 1;

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              else if (viData.UVCount == 4)
              {
                dataBin = new byte[8];
                dataBin[2] = offset;
                dataBin[4] = 0x0B;
                dataBin[6] = 5;
                dataBin[7] = 1;

                newBin.AddRange(dataBin);
                vdataLayersCount++;
              }
              #endregion

              replaceByteList(newBin, BitConverter.GetBytes(vdataLayersCount), 0x38);

              if (vdataLayersCount % 2 == 1) newBin.AddRange(new byte[8]);

              newBins.Add(newBin);
            }
          }
          #endregion

          // declBin構築
          buildBin(declBin, newBins, null, false, false);

          // objBin用リスト初期化
          objBins = new List<List<byte>>();
        }
        else
        {
          ObjectPart objPart = grp.Obj[obj.OriginalObjIndex];
          List<byte> objBin = new List<byte>();
          objBin.AddRange(bin.Skip((int)(grp.Offset + objPart.Offset)).Take(0xD0));

          // ID
          objBin[0] = (byte)obj.ID;

          // MtrCol
          objBin[4] = (byte)obj.MtrCol;

          // TexCount
          objBin[0xC] = (byte)obj.TexCount;

          // Tex Offset 初期化
          for (int i = 0; i < 4; i++)
          {
            replaceByteList(objBin, BitConverter.GetBytes(0), 0x10 + (4 * i));
          }

          // Decl
          objBin[0x38] = declIndices[(int)obj.VtxGrp];

          // Transparent
          switch (obj.Transparent)
          {
            case 1:
              objBin[0x40] = 1;
              objBin[0x48] = 0;
              break;
            case 2:
              objBin[0x40] = 0;
              objBin[0x48] = 0xC0;
              break;
            default:
              objBin[0x40] = 0;
              objBin[0x48] = 0;
              break;
          }

          // DoubleSided
          objBin[0x6C] = ((bool)obj.DoubleSided) ? (byte)1 : (byte)0;

          // Idx Start Index
          int idxGrp = tmcTables.VIData[(int)obj.VtxGrp].IdxGrp;
          if (obj.IsVgrpChanged)
          {
            if (idxStartIndices.ContainsKey(idxGrp))
              replaceByteList(objBin, BitConverter.GetBytes(idxStartIndices[idxGrp]), 0x70);
            else
              replaceByteList(objBin, BitConverter.GetBytes(0), 0x70);
            replaceByteList(objBin, BitConverter.GetBytes(0), 0x74);
          }
          else if (obj.IsDeleted)
          {
            replaceByteList(objBin, BitConverter.GetBytes(0), 0x74);
          }
          else
          {
            idxStartIndices[idxGrp] = (uint)(objPart.IdxStartIndex + obj.IdxCount);
          }

          // Vtx Start Index
          if (obj.IsVgrpChanged)
          {
            if (vtxStartIndices.ContainsKey((int)obj.VtxGrp))
              replaceByteList(objBin, BitConverter.GetBytes(vtxStartIndices[(int)obj.VtxGrp]), 0x78);
            else
              replaceByteList(objBin, BitConverter.GetBytes(0), 0x78);
            replaceByteList(objBin, BitConverter.GetBytes(0), 0x7C);
          }
          else if (obj.IsDeleted)
          {
            replaceByteList(objBin, BitConverter.GetBytes(0), 0x7C);
          }
          else
          {
            vtxStartIndices[(int)obj.VtxGrp] = (uint)(objPart.VtxStartIndex + obj.VtxCount);
          }

          if (obj.TexCount > 0)
          {
            // TexParam
            string texTypes = "0";
            if (obj.TexCount > 1) texTypes = obj.TexTypes[(int)obj.TexType];
            objBin[0xCC] = objPart.TexParams[0];
            if (obj.TexType != -1 && texTypes.IndexOf("2") != -1)
              objBin[0xCD] = 8;
            objBin[0xCE] = (byte)(objPart.TexParams[2] / 8 * 8);
            if (obj.ChangeableEnvMap && obj.EnvironmentMap == true) objBin[0xCE]++;
            if (obj.TexType != -1) objBin[0xCF] = (byte)((0x10 * texTypes.Count(c => c == '0')) + (4 * texTypes.Count(c => c == '1')));

            byte?[] texs = new byte?[] { obj.Tex1, obj.Tex2, obj.Tex3, obj.Tex4 };

            // TexTypeから各テクスチャのTypeを設定
            int[] texType = new int[(int)obj.TexCount];
            if (obj.TexTypes[(int)obj.TexType] == "Error")
            {
              for (int i = 0; i < (int)obj.TexCount; i++)
              {
                if (i < objPart.TexCount)
                {
                  texType[i] = objPart.Tex[i].Type;
                }
                else
                {
                  texType[i] = 0;
                }
              }
            }
            else
            {
              for (int i = 0; i < (int)obj.TexCount; i++)
              {
                texType[i] = Int32.Parse(obj.TexTypes[(int)obj.TexType].Replace(" ", "")[i].ToString());
              }
            }

            // テクスチャデータ追加
            for (int i = 0; i < obj.TexCount; i++)
            {
              List<byte> objTexBin = new List<byte>();

              objTexBin.AddRange(BitConverter.GetBytes(i));
              objTexBin.AddRange(BitConverter.GetBytes(texType[i]));
              objTexBin.AddRange(BitConverter.GetBytes((int)texs[i]));
              if (i >= objPart.Tex.Count)
              {
                List<byte> newDataBin = new List<byte>();
                newDataBin.AddRange(new byte[28 * 4]);
                newDataBin[0x10] = 5;
                newDataBin[0x14] = 1;
                newDataBin[0x40] = 1;
                newDataBin[0x44] = 1;
                newDataBin[0x48] = 1;
                replaceByteList(newDataBin, BitConverter.GetBytes((float)12.0), 0x54);
                replaceByteList(newDataBin, BitConverter.GetBytes((float)-1.0), 0x58);
                newDataBin[0x6C] = 2;

                objTexBin.AddRange(newDataBin.Skip(12));
              }
              else
              {
                for (int j = 0; j < 25; j++) objTexBin.AddRange(BitConverter.GetBytes(objPart.Tex[i].Data[j]));
              }

              // オフセット変更
              replaceByteList(objBin, BitConverter.GetBytes(0xD0 + (0x70 * i)), 0x10 + (4 * i));

              objBin.AddRange(objTexBin);
            }
          }
          else
          {
            objBin[0xCC] = 0;
            objBin[0xCD] = 0;
            objBin[0xCE] = 0x80;
            objBin[0xCF] = 0;

            List<byte> objTexBin = new List<byte>();
            objTexBin.AddRange(new byte[0x70]);
            objTexBin[0x04] = 2;
            replaceByteList(objTexBin, BitConverter.GetBytes(-1), 0x08);
            objTexBin[0x10] = 5;
            objTexBin[0x14] = 1;
            objTexBin[0x40] = 1;
            objTexBin[0x44] = 1;
            objTexBin[0x48] = 1;
            replaceByteList(objTexBin, BitConverter.GetBytes((float)12.0), 0x54);
            replaceByteList(objTexBin, BitConverter.GetBytes((float)-1.0), 0x58);
            objTexBin[0x6C] = 2;

            objBin.AddRange(objTexBin);
          }

          objBins.Add(objBin);
        }
      }

      // 最後の追加していないものを追加
      if (objGeoBin.Count != 0)
      {
        // objGeoBin構築
        buildBin(objGeoBin, objBins, declBin, false, false);
        objGeoBins.Add(objGeoBin);
      }

      // MdlGeo構築
      buildBin(mdlGeoBin, objGeoBins, null, false, false);

      return mdlGeoBin;
    }

    private List<byte> setVtxLayDataChanges(List<byte> bin)
    {
      // 削除したものを0で初期化
      foreach (var obj in tmcTables.ObjData)
      {
        if (obj.IsDeleted)
        {
          ObjectPart objPart = tmcData.ObjGrp[obj.OriginalGrpIndex].Obj[obj.OriginalObjIndex];
          int datasize = (int)tmcData.ObjGrp[obj.OriginalGrpIndex].Decl[objPart.DeclIndex].DataSize;
          replaceByteList(bin, new byte[(int)objPart.VtxCount * datasize], (int)tmcData.VtxGrp[objPart.VtxGrpIndex].Offset + objPart.VtxStartIndex * datasize);
        }
      }

      // VtxLay再構築
      List<byte> vtxLayBin = new List<byte>();
      buildHeaderBaseBin(vtxLayBin, "VtxLay");
      vtxLayBin[0x14] = (byte)tmcTables.VIData.Count;
      vtxLayBin[0x18] = (byte)tmcTables.VIData.Count;
      vtxLayBin[0x20] = 0x30;

      List<List<byte>> vtxBins = new List<List<byte>>();
      foreach (var viData in tmcTables.VIData)
      {
        List<byte> newBin = new List<byte>();

        if (!viData.IsAdded)
        {
          newBin.AddRange(bin.Skip((int)tmcData.VtxGrp[viData.OriginalIndex].Offset).Take((int)tmcData.VtxGrp[viData.OriginalIndex].Size));
        }

        if (newBin.Count == 0)
        {
          int addSize = (int)(tmcData.VtxGrp[viData.OriginalIndex].DataSize + 15) / 16 * 16;
          newBin.AddRange(new byte[addSize]);
        }

        vtxBins.Add(newBin);
      }
      buildBin(vtxLayBin, vtxBins, null, true, false);

      return vtxLayBin;
    }

    private List<byte> setIdxLayDataChanges(List<byte> bin)
    {
      // 削除したものを0で初期化
      foreach (var obj in tmcTables.ObjData)
      {
        if (obj.IsDeleted)
        {
          ObjectPart objPart = tmcData.ObjGrp[obj.OriginalGrpIndex].Obj[obj.OriginalObjIndex];
          replaceByteList(bin, new byte[(int)objPart.IdxCount * 2], (int)tmcData.IdxGrp[objPart.IdxGrpIndex].Offset + objPart.IdxStartIndex * 2);
        }
      }

      // IdxLay再構築
      List<byte> idxLayBin = new List<byte>();
      buildHeaderBaseBin(idxLayBin, "IdxLay");
      idxLayBin[0x20] = 0x30;

      byte count = 0;
      List<List<byte>> idxBins = new List<List<byte>>();
      foreach (var viData in tmcTables.VIData)
      {
        if (viData.Use == 0) continue;

        List<byte> newBin = new List<byte>();

        if (!viData.IsAdded && tmcData.IdxGrp[viData.OriginalIdxGrp].Size > 0)
        {
          newBin.AddRange(bin.Skip((int)tmcData.IdxGrp[viData.OriginalIdxGrp].Offset).Take((int)tmcData.IdxGrp[viData.OriginalIdxGrp].Size));
        }

        if (newBin.Count == 0) newBin.AddRange(new byte[0x10]);

        idxBins.Add(newBin);
        count++;
      }
      idxLayBin[0x14] = count;
      idxLayBin[0x18] = count;
      buildBin(idxLayBin, idxBins, null, true, false);

      return idxLayBin;
    }

    private List<byte> setMtrColDataChanges()
    {
      List<byte> mtrColBin = new List<byte>();
      buildHeaderBaseBin(mtrColBin, "MtrCol");
      mtrColBin[0x14] = (byte)tmcData.ColGrp.Count;
      mtrColBin[0x18] = (byte)tmcData.ColGrp.Count;
      mtrColBin[0x20] = 0x30;
      mtrColBin.AddRange(new byte[4 * ((tmcData.ColGrp.Count + 3) / 4 * 4)]);

      int colCount = 0;
      foreach (var col in tmcData.ColGrp)
      {
        List<byte> newCol = new List<byte>();

        foreach (var color in col.Color)
        {
          foreach (var c in color)
          {
            newCol.AddRange(BitConverter.GetBytes(c));
          }
        }
        newCol.AddRange(BitConverter.GetBytes(col.ID));

        Dictionary<int, int> counts = new Dictionary<int, int>();
        foreach (var obj in tmcTables.ObjData)
        {
          if (obj.Grp == -1)
          {
            counts[obj.ID] = 0;
          }
          else
          {
            if (obj.MtrCol == col.ID) counts[obj.Grp]++;
          }
        }

        int useCount = 0;
        foreach (KeyValuePair<int, int> count in counts)
        {
          if (count.Value != 0)
          {
            useCount++;
          }
        }
        newCol.AddRange(BitConverter.GetBytes(useCount));

        foreach (KeyValuePair<int, int> count in counts)
        {
          if (count.Value != 0)
          {
            newCol.AddRange(BitConverter.GetBytes(count.Key));
            newCol.AddRange(BitConverter.GetBytes(count.Value));
          }
        }

        newCol.AddRange(new byte[(16 - (newCol.Count % 16)) % 16]);

        replaceByteList(mtrColBin, BitConverter.GetBytes(mtrColBin.Count), 0x30 + (4 * colCount));
        mtrColBin.AddRange(newCol);
        colCount++;
      }

      // サイズ変更
      replaceByteList(mtrColBin, BitConverter.GetBytes(mtrColBin.Count), 0x10);

      return mtrColBin;
    }

    private List<byte> setMdlInfoDataChanges(List<byte> bin)
    {
      List<byte> mtdlInfoBin = new List<byte>();
      buildHeaderBaseBin(mtdlInfoBin, "MdlInfo");

      List<List<byte>> objInfoBins = new List<List<byte>>();
      int objInfoIndex = 0;

      List<byte> objInfoBin = new List<byte>();
      List<byte> parentInfoBin = new List<byte>();
      List<List<byte>> infoBins = new List<List<byte>>();
      int infoIndex = 0;
      SortedSet<int> CastShadowSet = new SortedSet<int>();
      SortedSet<int> ReceiveShadowSet = new SortedSet<int>();

      ObjInfo objInfo = null;
      Info info;
      foreach (var obj in tmcTables.ObjData)
      {
        if (obj.Grp == -1)
        {
          if (infoBins.Count > 0 || objInfoBin.Count > 0)
          {
            replaceByteList(objInfoBin, BitConverter.GetBytes(CastShadowSet.Sum()), 0x68);
            replaceByteList(objInfoBin, BitConverter.GetBytes(ReceiveShadowSet.Sum()), 0x6C);

            buildBin(objInfoBin, infoBins, null, false, false);
            objInfoBins.Add(objInfoBin);

            objInfoBin = new List<byte>();
            parentInfoBin = new List<byte>();
            infoBins = new List<List<byte>>();
            infoIndex = 0;
            CastShadowSet = new SortedSet<int>();
            ReceiveShadowSet = new SortedSet<int>();
          }
          objInfo = tmcData.ObjInfo[obj.OriginalGrpIndex];

          buildHeaderBaseBin(objInfoBin, "ObjInfo");
          parentInfoBin = bin.Skip((int)(objInfo.Offset + 0x30)).Take(0x120).ToList();
          replaceByteList(parentInfoBin, BitConverter.GetBytes(objInfoIndex), 4);
          replaceByteList(parentInfoBin, BitConverter.GetBytes(int.Parse(obj.Z1, NumberStyles.AllowHexSpecifier)), 0x14);
          replaceByteList(parentInfoBin, BitConverter.GetBytes(obj.Z2), 0x28);
          objInfoBin.AddRange(parentInfoBin);
          replaceByteList(objInfoBin, BitConverter.GetBytes(objInfoBin.Count), 0x20);

          objInfoIndex++;
        }
        else
        {
          info = tmcData.ObjInfo[obj.OriginalGrpIndex].Info[obj.OriginalObjIndex];

          List<byte> infoBin = new List<byte>();
          infoBin = bin.Skip((int)(objInfo.Offset + info.Offset)).Take(0xB0).ToList();
          replaceByteList(infoBin, BitConverter.GetBytes(infoIndex), 0);
          replaceByteList(infoBin, BitConverter.GetBytes(int.Parse(obj.Z1, NumberStyles.AllowHexSpecifier)), 0x04);
          replaceByteList(infoBin, BitConverter.GetBytes(obj.Z2), 0x18);
          replaceByteList(infoBin, BitConverter.GetBytes(obj.CastShadow), 0x28);
          replaceByteList(infoBin, BitConverter.GetBytes(obj.ReceiveShadow), 0x2C);
          infoBins.Add(infoBin);

          CastShadowSet.Add(obj.CastShadow);
          ReceiveShadowSet.Add(obj.ReceiveShadow);

          infoIndex++;
        }
      }
      buildBin(objInfoBin, infoBins, null, false, false);
      objInfoBins.Add(objInfoBin);

      mtdlInfoBin[0x20] = 0x30;
      buildBin(mtdlInfoBin, objInfoBins, null, false, false);

      return mtdlInfoBin;
    }

    private List<byte> setCpfDataChanges(List<byte> bin)
    {
      List<byte> cpfBin = new List<byte>();



      Dictionary<int, Dictionary<string, int>> cpChanges = new Dictionary<int, Dictionary<string, int>>();

      #region Check nodecp
      foreach (var obj in tmcTables.ObjData)
      {
        if (obj.Toggle == -1) continue;

        int toggleValue = 0;

        if (tmcData.ObjGrp[obj.OriginalGrpIndex].NodeCp != -1)
        {
          foreach (var cp in tmcData.NodeCp[tmcData.ObjGrp[obj.OriginalGrpIndex].NodeCp].cp)
          {
            if (cp.Data1 == 0xBB474F4B && cp.Param == 0)
            {
              toggleValue = 1;
            }
            else if (cp.Data1 == 0xBB474F4B && cp.Param == 1)
            {
              toggleValue = 2;
            }
            else if (cp.Data1 == 0xA50A10E2 && cp.Param == 0)
            {
              toggleValue = 3;
            }
            else if (cp.Data1 == 0xA50A10E2 && cp.Param == 1)
            {
              toggleValue = 4;
            }
          }
        }

        Dictionary<string, int> newCp = new Dictionary<string, int>();
        if (toggleValue != obj.Toggle)
        {
          newCp["Toggle"] = obj.Toggle;
          cpChanges[obj.Index] = newCp;
        }
      }
      #endregion

      if (cpChanges.Count > 0 || objGrpRebuild)
      {
        List<byte> nodecpHeaderBin = new List<byte>();
        Dictionary<int, List<byte>> nodecpBins = new Dictionary<int, List<byte>>();

        cpfBin.AddRange(bin.Take((int)tmcData.cpfOffsets[0]));

        if (tmcData.NodeCp.Count != 0)
          nodecpHeaderBin.AddRange(bin.Skip((int)tmcData.cpfOffsets[0]).Take((int)tmcData.NodeCp[0].Offset));
        else if (tmcData.cpfOffsets.Length > 1 && tmcData.cpfOffsets[1] != 0)
          nodecpHeaderBin.AddRange(bin.Skip((int)tmcData.cpfOffsets[0]).Take((int)(tmcData.cpfOffsets[1] - tmcData.cpfOffsets[0])));
        else
          nodecpHeaderBin.AddRange(bin.Skip((int)tmcData.cpfOffsets[0]));

        int count = 0;
        for (int i = 0; i < tmcTables.Nodes.Count; i++)
        {
          int nodecp = Array.FindIndex(tmcData.NodeCp.ToArray(), node => node.Index == tmcTables.Nodes[i].OriginalIndex);

          if (i == 0xF9) Console.WriteLine(nodecp);

          if (nodecp != -1)
          {
            count++;
            nodecpBins[i] = new List<byte>();
            nodecpBins[i].AddRange(bin.Skip(cpfBin.Count + (int)tmcData.NodeCp[nodecp].Offset).Take((int)tmcData.NodeCp[nodecp].Size));
            // 同じオフセットのものも別のものとして取得
          }
        }
        Console.WriteLine(count);

        // nodecpを変更
        if (cpChanges.Count > 0) setNodeCpChanges(nodecpBins, cpChanges);

        // nodecpのCount2変更
        replaceByteList(nodecpHeaderBin, BitConverter.GetBytes(nodecpBins.Count), 0x18);

        for (int i = 0; i < tmcTables.Nodes.Count; i++)
        {
          // オフセットを変更
          if (nodecpBins.ContainsKey(i))
          {
            replaceByteList(nodecpHeaderBin, BitConverter.GetBytes(nodecpHeaderBin.Count), 0x30 + (i * 4));
            nodecpHeaderBin.AddRange(nodecpBins[i]);
          }
          else
          {
            replaceByteList(nodecpHeaderBin, new byte[4], 0x30 + (i * 4));
          }
        }

        // nodecpの個数変更
        replaceByteList(nodecpHeaderBin, BitConverter.GetBytes(tmcTables.Nodes.Count), 0x14);
        replaceByteList(nodecpHeaderBin, BitConverter.GetBytes(nodecpBins.Count), 0x18);

        // nodecpのサイズ変更
        replaceByteList(nodecpHeaderBin, BitConverter.GetBytes(nodecpHeaderBin.Count), 0x10);

        cpfBin.AddRange(nodecpHeaderBin);
        replaceByteList(cpfBin, BitConverter.GetBytes(cpfBin.Count), 0x34);
      }
      else
      {
        if (tmcData.cpfOffsets.Length > 1 && tmcData.cpfOffsets[1] != 0)
          cpfBin.AddRange(bin.Take((int)tmcData.cpfOffsets[1]));
        else
          cpfBin.AddRange(bin);
      }

      #region matecp
      if (tmcData.cpfOffsets.Length > 1 && tmcData.cpfOffsets[1] != 0)
      {
        int objGeoCount = tmcTables.ObjData.Where(obj => obj.Grp == -1).Count();

        // matecp再構築
        List<byte> matecpBin = new List<byte>();
        buildHeaderBaseBin(matecpBin, "matecp");
        matecpBin[0x20] = 0x30;

        // itable再構築
        List<byte> itableBin = new List<byte>();
        List<int> itableOffsets = new List<int>();
        buildHeaderBaseBin(itableBin, "itable");
        itableBin[0x14] = (byte)objGeoCount;
        itableBin[0x18] = (byte)objGeoCount;
        itableBin[0x20] = 0x30;
        itableBin.AddRange(new byte[4 * ((objGeoCount + 3) / 4 * 4)]);

        List<byte> objCounts = new List<byte>();
        foreach (var obj in tmcTables.ObjData)
        {
          if (obj.Grp == -1)
          {
            if (itableBin.Count % 16 != 0)
            {
              itableBin.AddRange(new byte[16 - (itableBin.Count % 16)]);
            }
            itableOffsets.Add(itableBin.Count);
            replaceByteList(itableBin, BitConverter.GetBytes(itableBin.Count), 0x30 + (4 * obj.ID));
            itableBin.AddRange(BitConverter.GetBytes(0));

            objCounts.Add(0);
          }
          else
          {
            itableBin.AddRange(BitConverter.GetBytes((int)obj.Matecp));

            objCounts[obj.Grp]++;
          }
        }
        if (itableBin.Count % 16 != 0)
        {
          itableBin.AddRange(new byte[16 - (itableBin.Count % 16)]);
        }
        for (int i = 0; i < objCounts.Count; i++)
        {
          itableBin[itableOffsets[i]] = objCounts[i];
        }
        replaceByteList(itableBin, BitConverter.GetBytes(itableBin.Count), 0x10);

        // customp再構築
        List<List<byte>> cpBins = new List<List<byte>>();
        foreach (var customp in tmcData.MateCp)
        {
          List<byte> cpBin = new List<byte>();
          buildHeaderBaseBin(cpBin, "customp");

          cpBin[0x14] = (byte)customp.cp.Count;
          cpBin[0x18] = (byte)customp.cp.Count;
          cpBin[0x20] = 0x30;

          cpBin.AddRange(new byte[4 * ((customp.cp.Count + 3) / 4 * 4)]);
          cpBin[0x28] = (byte)cpBin.Count;
          cpBin.AddRange(new byte[8 * ((customp.cp.Count + 1) / 2 * 2)]);

          for (int i = 0; i < customp.cp.Count; i++)
          {
            replaceByteList(cpBin, BitConverter.GetBytes(cpBin.Count), 0x30 + (4 * i));
            replaceByteList(cpBin, BitConverter.GetBytes(customp.cp[i].Data1), cpBin[0x28] + (8 * i));
            replaceByteList(cpBin, BitConverter.GetBytes(i), cpBin[0x28] + 4 + (8 * i));
            cpBin.AddRange(BitConverter.GetBytes(customp.cp[i].Data2));
            cpBin.AddRange(BitConverter.GetBytes(customp.cp[i].Param));

            if (cpBin.Count % 16 != 0) cpBin.AddRange(new byte[16 - (cpBin.Count % 16)]);
          }
          replaceByteList(cpBin, BitConverter.GetBytes(cpBin.Count), 0x10);

          cpBins.Add(cpBin);
        }

        buildBin(matecpBin, cpBins, itableBin, false, false);

        cpfBin.AddRange(matecpBin);
        replaceByteList(cpfBin, BitConverter.GetBytes(cpfBin.Count), 0x10);
      }
      #endregion

      return cpfBin;
    }

    private void setNodeCpChanges(Dictionary<int, List<byte>> nodecpBins, Dictionary<int, Dictionary<string, int>> cpChanges)
    {
      foreach (var param in cpChanges)
      {
        int node = Array.FindIndex(tmcTables.Nodes.ToArray(), elem => elem.Name == tmcTables.ObjData[param.Key].Name);
        int originalObjID = tmcTables.ObjData[param.Key].OriginalGrpIndex;

        Customp nodecp = null;
        if (tmcData.ObjGrp[originalObjID].NodeCp != -1) nodecp = tmcData.NodeCp[tmcData.ObjGrp[originalObjID].NodeCp];

        uint toggleParam = 0;
        int toggleFlag = 1;
        var exclusions = new List<uint>();

        if (param.Value.ContainsKey("Toggle") && (param.Value["Toggle"] == 1 || param.Value["Toggle"] == 2))
        {
          toggleParam = 0xBB474F4B;
          toggleFlag = param.Value["Toggle"];
          exclusions.Add(0xA50A10E2);
        }
        else if (param.Value.ContainsKey("Toggle") && (param.Value["Toggle"] == 3 || param.Value["Toggle"] == 4))
        {
          toggleParam = 0xA50A10E2;
          toggleFlag = param.Value["Toggle"] - 2;
          exclusions.Add(0xBB474F4B);
        }

        if (toggleParam != 0)
        {
          // 既にcustompがあるか
          if (tmcData.ObjGrp[originalObjID].NodeCp == -1)
          {
            //int node = tmcData.ObjGrp[originalObjID].Node;
            // custompを追加
            nodecpBins[node] = new List<byte>();
            buildHeaderBaseBin(nodecpBins[node], "customp");
            nodecpBins[node].AddRange(new byte[0x10]);
            nodecpBins[node][0x10] = 0x60;
            nodecpBins[node][0x14] = 1;
            nodecpBins[node][0x18] = 1;
            nodecpBins[node][0x20] = 0x30;
            nodecpBins[node][0x28] = 0x40;
            nodecpBins[node][0x30] = 0x50;

            nodecpBins[node].AddRange(BitConverter.GetBytes(toggleParam));
            nodecpBins[node].AddRange(new byte[12]);
            nodecpBins[node].AddRange(BitConverter.GetBytes(1));
            nodecpBins[node].AddRange(BitConverter.GetBytes(toggleFlag - 1));
            nodecpBins[node].AddRange(new byte[8]);

            //Console.WriteLine("New : " + node + " / 0x" + nodecpBins[node].Count.ToString("X2"));
          }
          else
          {
            // custompにパラメーターを追加
            List<byte> offsets = new List<byte>();
            List<byte> Data1 = new List<byte>();
            List<byte> Data2 = new List<byte>();

            int count = 0;
            byte paramCount = 0;
            bool added = false;
            int baseSize = 0x30 + ((4 * nodecp.cp.Count + 1) + 15) / 16 * 16 + ((8 * nodecp.cp.Count + 1) + 15) / 16 * 16;

            for (int i = 0; i <= nodecp.cp.Count; i++)
            {
              // offsets    4 bytes
              // Data1      8 bytes
              // Data2   0x10 bytes

              if (!added && (count == nodecp.cp.Count || nodecp.cp[count].Data1 >= toggleParam))
              {
                offsets.AddRange(BitConverter.GetBytes(baseSize + Data2.Count));
                Data1.AddRange(BitConverter.GetBytes(toggleParam));
                Data1.AddRange(BitConverter.GetBytes(i));
                Data2.AddRange(BitConverter.GetBytes(1));
                if (toggleFlag == 1)
                  Data2.AddRange(BitConverter.GetBytes(0));
                else if (toggleFlag == 2)
                  Data2.AddRange(BitConverter.GetBytes(1));
                Data2.AddRange(new byte[8]);
                added = true;
                paramCount++;
                if (count < nodecp.cp.Count && nodecp.cp[count].Data1 == toggleParam)
                {
                  count++;
                }
              }
              else if (count < nodecp.cp.Count && !exclusions.Contains(nodecp.cp[count].Data1))
              {
                offsets.AddRange(BitConverter.GetBytes(baseSize + Data2.Count));
                Data1.AddRange(BitConverter.GetBytes(nodecp.cp[count].Data1));
                Data1.AddRange(BitConverter.GetBytes(i));
                Data2.AddRange(BitConverter.GetBytes(nodecp.cp[count].Data2));
                Data2.AddRange(BitConverter.GetBytes(nodecp.cp[count].Param));
                Data2.AddRange(new byte[(16 - (Data2.Count % 16)) % 16]);
                count++;
                paramCount++;
              }
            }

            offsets.AddRange(new byte[(16 - (offsets.Count % 16)) % 16]);
            Data1.AddRange(new byte[(16 - (Data1.Count % 16)) % 16]);

            List<byte> header = new List<byte>();
            buildHeaderBaseBin(header, "customp");
            header[0x10] = (byte)(0x30 + offsets.Count + Data1.Count + Data2.Count);
            header[0x14] = paramCount;
            header[0x18] = paramCount;
            header[0x20] = 0x30;
            header[0x28] = (byte)(0x30 + offsets.Count);

            nodecpBins[node].Clear();
            nodecpBins[node].AddRange(header);
            nodecpBins[node].AddRange(offsets);
            nodecpBins[node].AddRange(Data1);
            nodecpBins[node].AddRange(Data2);

            //Console.WriteLine("Add : " + nodecp.Index + " / 0x" + nodecpBins[nodecp.Index].Count.ToString("X2"));
          }
        }
        else
        {
          // custompに他の値があるか
          if (nodecp.cp.Count == 1)
          {
            // custompを削除
            nodecpBins.Remove(node);
            //Console.WriteLine("Delete : " + objID + " / 0x" + nodecp.Offset.ToString("X2"));
          }
          else
          {
            // custompのパラメーターのみ削除
            List<byte> offsets = new List<byte>();
            List<byte> Data1 = new List<byte>();
            List<byte> Data2 = new List<byte>();

            byte paramCount = 0;
            int baseSize = 0x30 + (((nodecp.cp.Count - 1) * 4) + 15) / 16 * 16 + (((nodecp.cp.Count - 1) * 8) + 15) / 16 * 16;

            for (int i = 0; i < nodecp.cp.Count; i++)
            {
              if (nodecp.cp[i].Data1 != 0xBB474F4B && nodecp.cp[i].Data1 != 0xA50A10E2)
              {
                offsets.AddRange(BitConverter.GetBytes(baseSize + Data2.Count));
                Data1.AddRange(BitConverter.GetBytes(nodecp.cp[i].Data1));
                Data1.AddRange(BitConverter.GetBytes(i));
                Data2.AddRange(BitConverter.GetBytes(nodecp.cp[i].Data2));
                Data2.AddRange(BitConverter.GetBytes(nodecp.cp[i].Param));
                Data2.AddRange(new byte[(16 - (Data2.Count % 16)) % 16]);

                paramCount++;
              }
            }

            offsets.AddRange(new byte[(16 - (offsets.Count % 16)) % 16]);
            Data1.AddRange(new byte[(16 - (Data1.Count % 16)) % 16]);

            List<byte> header = new List<byte>();
            buildHeaderBaseBin(header, "customp");
            header[0x10] = (byte)(0x30 + offsets.Count + Data1.Count + Data2.Count);
            header[0x14] = paramCount;
            header[0x18] = paramCount;
            header[0x20] = 0x30;
            header[0x28] = (byte)(0x30 + offsets.Count);

            nodecpBins[node].Clear();
            nodecpBins[node].AddRange(header);
            nodecpBins[node].AddRange(offsets);
            nodecpBins[node].AddRange(Data1);
            nodecpBins[node].AddRange(Data2);
          }
        }
      }
    }

    private List<byte> setMcaPackDataChanges()
    {
      List<byte> mcapackBin = new List<byte>();
      buildHeaderBaseBin(mcapackBin, "MCAPACK");
      mcapackBin[0x14] = (byte)tmcData.Mat.Count;
      mcapackBin[0x18] = (byte)tmcData.Mat.Count;
      mcapackBin[0x20] = 0x40;
      mcapackBin.AddRange(BitConverter.GetBytes(1));
      mcapackBin.AddRange(BitConverter.GetBytes(-1));
      mcapackBin.AddRange(BitConverter.GetBytes(-1));
      mcapackBin.AddRange(BitConverter.GetBytes(-1));
      mcapackBin.AddRange(new byte[4 * ((tmcData.Mat.Count + 3) / 4 * 4)]);
      replaceByteList(mcapackBin, BitConverter.GetBytes(mcapackBin.Count), 0x28);


      List<byte> mcaindexBin = new List<byte>();
      buildHeaderBaseBin(mcaindexBin, "MCAINDEX");
      mcaindexBin[0x20] = 0x30;

      List<List<byte>> newIndices = new List<List<byte>>();
      List<byte> newIndex = new List<byte>();
      foreach (var obj in tmcTables.ObjData)
      {
        if (obj.Grp == -1)
        {
          if (obj.ID > 0)
          {
            newIndex.AddRange(new byte[(16 - (newIndex.Count % 16)) % 16]);
            newIndices.Add(newIndex);
          }
          newIndex = new List<byte>();
        }
        else
        {
          newIndex.AddRange(BitConverter.GetBytes((int)obj.Mcamtrl));
        }
      }
      newIndex.AddRange(new byte[(16 - (newIndex.Count % 16)) % 16]);
      newIndices.Add(newIndex);

      // mcaindexBin構築
      buildBin(mcaindexBin, newIndices, null, false, true);
      mcapackBin.AddRange(mcaindexBin);

      foreach (var mat in tmcData.Mat)
      {
        List<byte> newMat = new List<byte>();
        buildHeaderBaseBin(newMat, "MCAMTRL");
        newMat[0x14] = 0x21;
        newMat[0x18] = (byte)mat.Param.Count;
        newMat[0x20] = 0x30;
        newMat.AddRange(new byte[0x90]);

        foreach (var param in mat.Param)
        {
          if (param == null) continue;

          List<byte> newParam = new List<byte>();
          buildHeaderBaseBin(newParam, "MCAPARAM");
          if (param.Params != null)
          {
            newParam[0x14] = (byte)param.Params.Count;
            newParam[0x18] = (byte)param.Params.Count;
            newParam[0x20] = 0x60;
            newParam[0x28] = 0x40;
          }
          newParam.AddRange(BitConverter.GetBytes(param.Data1));
          newParam.Add(param.Data2);
          newParam.AddRange(Enumerable.Repeat<byte>(0xFF, 11).ToArray());

          if (param.Data3 != null)
          {
            foreach (var data in param.Data3)
            {
              newParam.AddRange(BitConverter.GetBytes(data));
            }
            newParam.AddRange(new byte[(16 - (newParam.Count % 16)) % 16]);
          }

          if (param.Params != null)
          {
            foreach (var ps in param.Params)
            {
              foreach (var p in ps)
              {
                newParam.AddRange(BitConverter.GetBytes(p));
              }
            }
          }

          // サイズ変更
          replaceByteList(newParam, BitConverter.GetBytes(newParam.Count), 0x10);

          // オフセット変更と追加
          replaceByteList(newMat, BitConverter.GetBytes(newMat.Count), 0x30 + (4 * param.ID));
          newMat.AddRange(newParam);
        }

        // サイズ変更
        replaceByteList(newMat, BitConverter.GetBytes(newMat.Count), 0x10);

        // オフセット変更と追加
        replaceByteList(mcapackBin, BitConverter.GetBytes(mcapackBin.Count), 0x40 + (4 * mat.ID));
        mcapackBin.AddRange(newMat);
      }

      // サイズ変更
      replaceByteList(mcapackBin, BitConverter.GetBytes(mcapackBin.Count), 0x10);

      return mcapackBin;
    }

    private List<byte> setHieLayDataChanges(Dictionary<int, int> convertNodeIdx)
    {
      List<byte> partBin = new List<byte>();
      buildHeaderBaseBin(partBin, "HieLay");

      List<byte> optionBin = new List<byte>();
      optionBin.AddRange(BitConverter.GetBytes(1));
      optionBin.AddRange(new byte[0x0C]);

      List<List<byte>> childBins = new List<List<byte>>();
      for (int i = 0; i < tmcTables.Nodes.Count; i++)
      {
        var hie = tmcData.Hie[tmcTables.Nodes[i].OriginalIndex];

        List<byte> newBin = new List<byte>();

        List<float> m = matrix3DToList(hie.Matrix);
        foreach (float f in m)
        {
          newBin.AddRange(BitConverter.GetBytes(f));
        }

        if (hie.Parent == -1)
        {
          newBin.AddRange(BitConverter.GetBytes(hie.Parent));
        }
        else
        {
          newBin.AddRange(BitConverter.GetBytes(convertNodeIdx[hie.Parent]));
        }

        newBin.AddRange(BitConverter.GetBytes(tmcTables.Nodes[i].Children.Count));

        newBin.AddRange(BitConverter.GetBytes(hie.BoneLevel));

        newBin.AddRange(new byte[4]);

        foreach (var child in tmcTables.Nodes[i].Children)
        {
          int childIdx = Array.FindIndex(tmcTables.Nodes.ToArray(), elem => elem.Name == child);
          if (childIdx != -1) newBin.AddRange(BitConverter.GetBytes(childIdx));
        }
        if (newBin.Count % 16 != 0) newBin.AddRange(new byte[16 - newBin.Count % 16]);

        if (hie.BoneLevel == 0)
        {
          optionBin.AddRange(BitConverter.GetBytes(i));
        }

        childBins.Add(newBin);
      }

      optionBin.AddRange(new byte[0x0C]);

      buildBin(partBin, childBins, optionBin, false, false);

      return partBin;
    }

    private List<byte> setNodeLayDataChanges()
    {
      List<byte> nodeLayBin = new List<byte>();
      buildHeaderBaseBin(nodeLayBin, "NodeLay");
      nodeLayBin.AddRange(new byte[0x10]);
      nodeLayBin[0x30] = 1;
      nodeLayBin[0x32] = 2;

      List<List<byte>> nodeObjBins = new List<List<byte>>();

      int count = 0;
      foreach (var node in tmcTables.Nodes)
      {
        var originalNode = tmcData.Node[node.OriginalIndex];

        List<byte> nodeObjBin = new List<byte>();
        buildHeaderBaseBin(nodeObjBin, "NodeObj");
        nodeObjBin.AddRange(BitConverter.GetBytes(0));
        nodeObjBin.AddRange(BitConverter.GetBytes(-1));
        nodeObjBin.AddRange(BitConverter.GetBytes(count));
        nodeObjBin.AddRange(BitConverter.GetBytes(0));
        nodeObjBin.AddRange(Encoding.ASCII.GetBytes(node.Name));
        nodeObjBin.AddRange(new byte[16 - (nodeObjBin.Count % 16)]);

        if (node.ObjIndex != -1)
        {
          replaceByteList(nodeObjBin, BitConverter.GetBytes(nodeObjBin.Count), 0x20);
          nodeObjBin[0x14] = 1;
          nodeObjBin[0x18] = 1;
          nodeObjBin.AddRange(BitConverter.GetBytes(nodeObjBin.Count + 0x10));
          nodeObjBin.AddRange(new byte[12]);

          nodeObjBin.AddRange(BitConverter.GetBytes(node.ObjIndex));
          nodeObjBin.AddRange(BitConverter.GetBytes(originalNode.ChildCount));
          nodeObjBin.AddRange(BitConverter.GetBytes(count));
          nodeObjBin.AddRange(BitConverter.GetBytes(0));

          List<float> m = matrix3DToList(originalNode.Matrix);
          foreach (float f in m)
          {
            nodeObjBin.AddRange(BitConverter.GetBytes(f));
          }

          foreach (var idx in tmcData.BlendIdxGrp[originalNode.ObjIndex].Idx)
          {
            nodeObjBin.AddRange(BitConverter.GetBytes(idx));
          }

          if (nodeObjBin.Count % 16 > 0) nodeObjBin.AddRange(new byte[16 - (nodeObjBin.Count % 16)]);
        }

        replaceByteList(nodeObjBin, BitConverter.GetBytes(nodeObjBin.Count), 0x10);

        nodeObjBins.Add(nodeObjBin);

        count++;
      }
      buildBin(nodeLayBin, nodeObjBins, null, false, false);

      return nodeLayBin;
    }

    private List<byte> setMtxDataChanges(List<byte> bin, string type)
    {
      List<byte> partBin = new List<byte>();
      buildHeaderBaseBin(partBin, type);

      var mtxGrp = tmcData.MtxGrp;
      if (type == "BnOfsMtx") mtxGrp = tmcData.BnOfsMtxGrp;

      List<List<byte>> childBins = new List<List<byte>>();
      foreach (var node in tmcTables.Nodes)
      {
        List<byte> newBin = new List<byte>();

        newBin.AddRange(bin.Skip((int)mtxGrp[node.OriginalIndex].Offset).Take(0x40).ToArray());

        childBins.Add(newBin);
      }
      buildBin(partBin, childBins, null, false, false);

      return partBin;
    }

    private List<byte> setRenPackDataChanges(List<byte> bin)
    {
      replaceByteList(bin, BitConverter.GetBytes(tmcTables.ObjCounts.Count), 0x14);
      return bin;
    }

    private List<byte> setAcsclsDataChanges(List<byte> bin, Dictionary<int, int> convertNodeIdx)
    {
      List<List<byte>> childBins = new List<List<byte>>();
      HeaderData h = null;
      if (bin.Count != 0)
      {
        h = new HeaderData(0, bin.ToArray());
        uint lastOffset = h.Size;
        for (int i = (int)h.Count1 - 1; i >= 0; i--)
        {
          List<byte> childBin = new List<byte>();
          if (h.Offsets[i] != 0)
          {
            childBin.AddRange(bin.Skip((int)h.Offsets[i]).Take((int)(lastOffset - h.Offsets[i])));
            lastOffset = h.Offsets[i];
          }
          childBins.Insert(0, childBin);
        }
      }
      else
      {
        for (int i = 0; i < 4; i++)
        {
          List<byte> childBin = new List<byte>();
          childBins.Add(childBin);
        }
      }

      if (h.Offsets[2] != 0)
      {
        // childBins[0]のインデックスを変更
        var physicsH = new HeaderData(0, childBins[0].ToArray());
        var physicsSubH = new HeaderData(physicsH.HSize, childBins[0].ToArray());
        for (int i = 0; i < physicsH.Count1; i++)
        {
          replaceByteList(childBins[0], BitConverter.GetBytes(convertNodeIdx[tmcData.Physics[i].Node]), (int)(physicsSubH.Start + physicsSubH.Offset1 + (0x0C * i) + 4));
        }

        foreach (var physics in tmcData.Physics)
        {
          if (physics.Type != 2)
          {
            replaceByteList(childBins[0], BitConverter.GetBytes(convertNodeIdx[physics.RootNode]), (int)physics.Offset + 0x30 + 0x60);
          }
          else
          {
            replaceByteList(childBins[0], BitConverter.GetBytes(convertNodeIdx[physics.RootNode]), (int)physics.Offset + 0x30 + 0x70);
          }
        }
      }

      if (h.Offsets[2] != 0)
      {
        // childBins[2]のインデックスを変更
        List<byte> indicesBin = new List<byte>();
        buildHeaderBaseBin(indicesBin, "");
        replaceByteList(indicesBin, BitConverter.GetBytes(tmcData.AcsclsIndices[1].Length), 0x14);
        replaceByteList(indicesBin, BitConverter.GetBytes(tmcData.AcsclsIndices[1].Length), 0x18);
        indicesBin[0x20] = 0x30;
        foreach (var physics in tmcData.AcsclsIndices[1])
        {
          indicesBin.AddRange(BitConverter.GetBytes(convertNodeIdx[physics]));
        }
        if (indicesBin.Count % 16 > 0) indicesBin.AddRange(new byte[16 - (indicesBin.Count % 16)]);
        replaceByteList(indicesBin, BitConverter.GetBytes(indicesBin.Count), 0x10);
        childBins[2] = indicesBin;
      }



      List < byte> partBin = new List<byte>();
      buildHeaderBaseBin(partBin, "ACSCLS");
      partBin.AddRange(new byte[0x10]);
      partBin[0x30] = 0x0C;

      buildBin(partBin, childBins, null, false, true);

      // Headerの全体サイズを変更
      replaceByteList(partBin, BitConverter.GetBytes(partBin.Count), 0x10);

      return partBin;
    }
  }
}
