본문으로 건너뛰기

그 밖에 정해지는 것과 헷갈리는 자리

「시트 작성」으로 돌아가기


Target Side (서버/클라 분리)

같은 시트로 서버용과 클라이언트용 산출물을 따로 뽑을 수 있습니다. 지정하는 곳이 세 군데입니다 — 시트의 엔티티, 시트의 필드, 그리고 recipe의 출력 항목. 여기에 실행 시점의 --target-side가 더해집니다.

엔티티 단위 — 선언 셀의 side 메타:

선언 셀의미
:table ServerTuning(side=s)서버 빌드에만 포함
:table ClientStrings(side=c)클라이언트 빌드에만 포함
:table Item 또는 :table Item(side="c,s")양쪽 모두

필드 단위:target 행:

행 키indexNamePrice
:typeintstringint
:targetcscss

위 예에서 Price는 서버 빌드에만 들어갑니다. 기본 인덱스 필드는 모든 행을 식별하는 키이므로 항상 포함되며, cs가 아니면 오류입니다.

그리고 recipe의 각 출력 항목에 TargetSide를 지정하면 그쪽에 맞는 것만 출력됩니다.

"Targets": [
{ "Type": "csharp", "Path": "./server/generated", "TargetSide": "s" },
{ "Type": "csharp", "Path": "./client/generated", "TargetSide": "c" }
]

기본값이 cs(전체)이므로, TargetSide를 지정하지 않은 기존 recipe의 출력은 달라지지 않습니다.

실행 시점에 좁히기--target-side는 recipe를 고치지 않고 실행 전체를 한쪽으로 좁힙니다.

tabbit --recipe recipe.json --target-side server

두 가지가 함께 일어납니다.

recipe 항목의 TargetSide--target-side server 로 실행하면
s그대로 실행 (이미 그만큼 좁음)
c건너뜀 — 이 실행의 산출물이 아님
cs실행되지만 서버 컷만 출력

declared & requested입니다. 옵션을 주지 않으면 requestedcs이므로 각 항목이 선언한 그대로 빌드되고, 옵션이 없던 때와 동일하게 동작합니다.

CI에서 클라이언트 잡과 서버 잡이 같은 recipe를 공유하면서 각자 필요한 것만 만들 때 쓰는 용도입니다. 정적 검증도 좁혀진 쪽만 검사하므로, 서버 빌드가 만들지도 않는 클라이언트 쪽 문제로 실패하지 않습니다.

클라이언트 빌드에 남은 테이블이 서버 전용 테이블을 참조하면 변환 단계에서 오류로 보고됩니다. 그대로 두면 생성된 코드가 존재하지 않는 타입을 가리키게 되고, 그 문제는 게임 프로젝트의 컴파일러에서야 드러나기 때문입니다.

정적 검증

변환 과정에서 아래를 검사하고, 문제를 모두 모아 한 번에 보고합니다. 첫 오류에서 멈추면 시트를 고치는 일이 "하나 고치고 다시 돌리기"의 반복이 되기 때문입니다.

  • 인덱스 필드(기본 / 보조)의 값이 유니크한지
  • 참조 대상 테이블과 필드가 존재하는지
  • 참조하는 행이 실제로 존재하는지 (0은 "참조 없음"으로 취급)
  • 순환 참조
  • TargetSide 필터링으로 참조가 끊기지 않는지
  • 컬럼이 선언한 범위·허용값·필수 여부를 값이 지키는지 — 레이아웃이 그것을 읽어 왔을 때만 (설계)
The workbook did not pass validation. (5 problems)

Details:
[ 1] Field `Shipments.Warehouse` references table `NoSuchTable`, which does not exist.
at sheets/data.xlsx : Bad : M7
[ 2] Index field `Catalog.Index` repeats the value `1`, first used at sheets/data.xlsx : Bad : B9.
at sheets/data.xlsx : Bad : B10
...

빈 칸의 뜻 — 자리별 총정리

가장 자주 묻는 질문이 「여기 비워도 되나」입니다. 자리마다 다르므로 한 표로 정리합니다.

세 줄 요약.

  1. 빈 칸은 「값 없음」이 아닙니다. 값 없음은 -이고, ? 컬럼에서만 적을 수 있습니다.
  2. 비워도 되는 곳 — 문자열 · bool · 배열의 데이터 칸, 선택 헤더 행의 칸, 정본이 다른 칸에 있는 헤더 칸.
  3. 비우면 안 되는 곳 — 숫자 계열의 데이터 칸, 기본 인덱스, 연장 행의 스칼라 칸, 이름 없는 컬럼의 데이터 칸.

헤더 영역

자리빈 칸의 뜻
선언 셀의 오른쪽설명 없음. 허용
:field자리가 없는 컬럼. 그 아래 데이터가 있으면 오류
:type 셀 — 보통의 필드오류. 타입은 생략할 수 없습니다
:type 셀 — struct 그룹의 2번째 이후 · 원소 1 이후 · 기본이 아닌 변형비우는 것이 정본입니다
:desc · :target · :variant설명 없음 · 양쪽 · 기본 변형. 허용
:desc · :target · :variant 행 자체전부 위의 기본값. 허용
메모 컬럼(#)의 모든 칸자유 공간

데이터 영역

자리빈 칸의 뜻
마커 열보통의 데이터 행
기본 인덱스 칸오류 — 그 행을 가리킬 것이 없습니다. 예외는 멀티 로우 표이고, 거기서는 연장 행의 신호입니다
string · bool · T[]값입니다"" · false · 빈 배열
숫자 · bitset · datetime · timespan · uuid · enum 칸오류(기본). 소스의 OnBlankCell이 완화합니다
참조(foreign) 칸오류. 키를 적거나, 옵셔널이면 -
옵셔널(?) 칸위와 똑같습니다. ?가 바꾸는 것은 「-를 적을 수 있다」뿐입니다
연장 행의 [] 아닌 칸비어 있어야 합니다. 값이 있으면 그 셀을 가리켜 오류
완전히 빈 행엔티티의 종료
엔티티 밖의 셀읽지 않습니다 — 자유

헷갈리는 자리

논리적으로는 정합하지만 처음 보면 걸리는 자리들입니다.

#헷갈리는 것안내
1[]의 두 자리이름의 []는 행, 타입의 []는 셀 안입니다
2원소 번호가 0부터엑셀 행 번호는 1부터입니다. [1]로 시작하면 「[0]이 없습니다」로 걸립니다
3인덱스 빈 칸의 뜻이 표에 따라 다름[] 컬럼이 있으면 연장 신호, 없으면 오류입니다. 갈림길은 []의 존재입니다
4text(Common) 옛 습관(부터가 메타이므로 「모르는 키」가 됩니다. string (text=Common)입니다
5빈 행이 표를 끝냄여백은 마커 열 #나 메모 컬럼으로
6*가 멀티 로우가 아님*는 보조 인덱스이고 멀티 로우는 []입니다. [] 컬럼에 *를 붙이면 둘을 함께 안내합니다
7타입 칸을 비우는 것그룹의 정본은 첫 멤버 컬럼입니다. 반복 기재도 되고, 그때는 일치를 검사합니다
8멀티 로우 그룹 2개가 나란히같은 행의 원소끼리 짝이 아닙니다. 짝이 필요하면 한 struct의 멤버로
9-와 빈 칸의 구분-가 값 없음이고 빈 칸은 그 타입이 읽는 값입니다
10#의 세 자리뜻은 하나이고 위치가 대상을 정합니다
11이름의 숫자Text1·Text2는 필드 둘입니다. 배열은 대괄호로만 만들어집니다
12:variant행 세트:variant한 필드의 값 컬럼이 여러 벌, 행 세트는 행의 집합이 여러 벌입니다

다른 규칙으로 쓰인 시트

지금까지 설명한 것이 tabbit 레이아웃이고 기본값입니다.

이미 다른 규칙으로 작성된 시트 한 벌이 있다면 — 마커가 없고 시트 탭 하나가 곧 테이블 하나인 형태 — 시트를 고치지 않고 그대로 읽는 sheet-per-table 레이아웃이 따로 있습니다. 레이아웃은 소스 항목마다 지정하므로 한 recipe에서 섞어 읽어도 됩니다.

"Xlsx": [
{ "Path": "./sheets", "Layout": "tabbit" },
{ "Path": "./other-sheets", "Layout": "sheet-per-table" }
]

레이아웃 규칙과 실제 적용 기록은 sprout 샘플에 따로 있습니다. 기존 시트를 가져올 일이 없다면 읽지 않아도 됩니다.