본문으로 건너뛰기

컬럼 묶음과 빈 칸

시트가 코드가 되는 모습으로


At.X · At.Y 처럼 점 앞이 같은 컬럼들은 한 레코드가 됩니다. 시트에서는 여전히 컬럼 여럿이고, 코드에서는 멤버를 가진 타입 하나입니다.

레코드 하나와, 비워도 되는 값 하나입니다. 타입 뒤의 ? 가 그 칸을 비워도 된다는 뜻이고, 비우는 방법은 - 입니다.

테이블 Spawn

[System.Serializable]
public partial class SpawnRecord
{
#region Values
/// <summary>
/// primary index
/// </summary>
public int Index => _index;

/// <summary>
/// x position
/// </summary>
public AtEntry At => _at;

/// <summary>
/// radius, or blank
/// </summary>
public float Radius => _radius;
/// <summary>Whether this row has a value for <see cref="Radius"/>.</summary>
public bool HasRadius => _radiusHasValue;
#endregion

/// <summary>One element of <see cref="At"/>.</summary>
[System.Serializable]
public struct AtEntry
{
/// x position
public float X;
/// y position
public float Y;

public override string ToString()
{
var sb = new StringBuilder("{");
sb.Append("\"X\":"); ToStringHelper.ToString(X, sb);
sb.Append(",\"Y\":"); ToStringHelper.ToString(Y, sb);
sb.Append("}");
return sb.ToString();
}
}

#region Storage
internal int _index;
internal AtEntry _at;
internal float _radius;
internal bool _radiusHasValue;
#endregion

#region ToString
public override string ToString()
{
var sb = new StringBuilder("{");
sb.Append("\"Index\":"); ToStringHelper.ToString(Index, sb);
sb.Append(",\"At\":"); ToStringHelper.ToString(At, sb);
sb.Append(",\"Radius\":"); ToStringHelper.ToString(Radius, sb);
sb.Append("}");
return sb.ToString();
}
#endregion
}

SpawnTable.cs

중첩은 파일에 아무 값도 더하지 않습니다. 레코드는 멤버마다 컬럼 하나로 저장되므로, At.XAt.Y 를 따로 적었을 때와 파일의 바이트가 같습니다. 달라지는 것은 코드를 읽는 쪽의 모습뿐입니다.

? 가 붙은 컬럼은 언어마다 그 언어의 「없음」으로 나옵니다 — 옵셔널 타입이 있는 언어는 그것을 쓰고, 없는 언어는 값이 있는지 확인하는 방법을 따로 냅니다.


레코드도 배열이 되고, 레코드 안에 레코드가 옵니다.

  • Slot[0].Id · Slot[1].Id — 레코드의 배열
  • Home.At.X — 레코드 안의 레코드

테이블 Deck

[System.Serializable]
public partial class DeckRecord
{
#region Values
/// <summary>
/// primary index
/// </summary>
public int Index => _index;

/// <summary>
/// element 1
/// </summary>
public SlotEntry[] Slot => _slot;

/// <summary>
/// two levels in
/// </summary>
public HomeEntry Home => _home;
#endregion

/// <summary>One element of <see cref="Slot"/>.</summary>
[System.Serializable]
public struct SlotEntry
{
/// element 1
public int Id;
/// element 1
public string Label;

public override string ToString()
{
var sb = new StringBuilder("{");
sb.Append("\"Id\":"); ToStringHelper.ToString(Id, sb);
sb.Append(",\"Label\":"); ToStringHelper.ToString(Label, sb);
sb.Append("}");
return sb.ToString();
}
}

internal static SlotEntry[] NewSlotEntryArray(int length)
{
var result = new SlotEntry[length];
for (int i = 0; i < result.Length; i++)
{
result[i].Label = "";
}
return result;
}

/// <summary>A record inside <see cref="Home"/>.</summary>
[System.Serializable]
public struct HomeAtEntry
{
/// two levels in
public float X;
/// two levels in
public float Y;

public override string ToString()
{
var sb = new StringBuilder("{");
sb.Append("\"X\":"); ToStringHelper.ToString(X, sb);
sb.Append(",\"Y\":"); ToStringHelper.ToString(Y, sb);
sb.Append("}");
return sb.ToString();
}
}
/// <summary>One element of <see cref="Home"/>.</summary>
[System.Serializable]
public struct HomeEntry
{
/// two levels in
public HomeAtEntry At;

public override string ToString()
{
var sb = new StringBuilder("{");
sb.Append("\"At\":"); ToStringHelper.ToString(At, sb);
sb.Append("}");
return sb.ToString();
}
}

private static HomeEntry NewHomeEntry()
{
var result = default(HomeEntry);
return result;
}

#region Storage
internal int _index;
internal SlotEntry[] _slot = System.Array.Empty<SlotEntry>();
internal HomeEntry _home = NewHomeEntry();
#endregion

#region ToString
public override string ToString()
{
var sb = new StringBuilder("{");
sb.Append("\"Index\":"); ToStringHelper.ToString(Index, sb);
sb.Append(",\"Slot\":"); ToStringHelper.ToString(Slot, sb);
sb.Append(",\"Home\":"); ToStringHelper.ToString(Home, sb);
sb.Append("}");
return sb.ToString();
}
#endregion
}

DeckTable.cs

깊이는 파일에 값을 더하지 않습니다. 몇 단계를 내려가든 저장되는 것은 잎마다 컬럼 하나입니다 — 생성된 코드에 단계마다 타입이 하나씩 생길 뿐입니다.