본문으로 건너뛰기

와일드링 — 데이터 설계

기획서가 요구하는 것을 테이블과 컬럼으로 옮깁니다. 이 문서가 정하는 것은 셋입니다.

무엇어디
무엇을 어떻게 적는가 — 테이블 · 컬럼 · 타입 · 제약3 · 4
어느 워크북 어느 탭에 두는가5
어느 기능이 어디에서 쓰이는가6

표기는 주 레이아웃(tabbit)의 확정본을 따릅니다. 근거는 주 레이아웃다형과 참조 배열이고, 이 문서는 그 표기를 쓰는 쪽입니다. 표기를 새로 정하지 않습니다.


1. 설계 원칙

#원칙근거
1시트 하나에 엔티티 하나. 탭 이름이 엔티티 이름입니다엑셀의 정렬 · 필터가 표 하나에만 걸립니다. 헤더가 데이터 사이로 흩어지는 사고가 줄어듭니다
2필드만 snake, 나머지는 전부 pascal시트에서 「타입과 이름의 자리」와 「값이 들어가는 자리」가 눈으로 구분됩니다. Naming.OnViolationerror로 두어 검사로 강제합니다
3반복되는 값 묶음은 .tbs에 선언같은 멤버 조합을 테이블마다 다시 적지 않습니다
4형태가 행마다 다른 것은 다형 레코드참조는 컬럼당 대상 하나이므로, 「아이템이거나 재화이거나 와일드링」을 참조로 표현할 수 없습니다
5밸런스 값은 .tsv에, 시트는 저작기가 생성숫자 조정이 diff로 읽힙니다. 워크북은 .tsv + 레이아웃 선언의 산출물입니다

1.1 예외 2곳 — 원칙 1을 지키지 않는 자리

경계 판정과 다중 엔티티 배치는 그 배치를 실제로 하지 않으면 검증되지 않습니다. 억지 시트를 만들지 않고 자연스러운 자리 2곳에 둡니다.

배치
Const_Battle상수셋 BattleConst와 그것만 쓰는 작은 표 ElementAffinityColumn을 나란히
Const_Growth상수셋 GrowthConst 아래에 빈 행 하나를 두고 AwakeningConst

2. 키와 참조

2.1 키 타입

문자열 키를 씁니다. sprout_deer_1처럼 읽을 수 있는 id여야 시트에서 참조를 눈으로 검증할 수 있고, 밸런스 .tsv의 diff도 읽힙니다. 수치 id는 Stage.index처럼 순번이 뜻을 갖는 자리에만 씁니다.

2.2 키 선언

테이블key 메타무엇을 확인하는가
Monster(생략)첫 필드 컬럼이 기본 인덱스인 기본 동작
Itemkey=item_id첫 컬럼이 아닌 컬럼을 기본 인덱스로 지정하는 것. Item의 첫 컬럼은 category입니다
Stagekey="stage_id; region_id,index"첫 키는 단일(참조 대상이 되므로), 둘째가 복합 보조 키
RegionYieldkey="region_id,hour_band"복합 기본 인덱스. 조회가 다인자가 되고, 이 테이블은 foreign의 대상이 될 수 없습니다
Monster*display_code컬럼 자리의 보조 키. 운영 도구가 쓰는 짧은 코드입니다

RegionYield가 복합 기본 인덱스인 것은 의도한 배치입니다 — 복합 키 테이블이 참조 대상이 될 수 없다는 규칙이 이 데이터에서 실제로 걸리는지 확인하는 자리이고, 그래서 이 테이블을 가리키는 컬럼을 두지 않았습니다.

2.3 참조 · 검사 · 다형의 구분

데이터의 성질적는 법이 데이터에서
대상이 테이블 하나foreign XMonsterSkill.skill_id foreign Skill
같은 테이블의 키 목록foreign X[]Stage.wave_monster_ids foreign Monster[]
값이 어느 테이블의 id이기만 하면 됨int (refs=A;B)Mission.target_id
형태가 행마다 다르고 id를 줄 가치가 없음다형 레코드 $typeRewardEntry.reward
개수도 형태도 행마다 다름다형 레코드 + 멀티 로우Boss.effects[]

Mission.target_id가 검사인 이유는 행에 닿을 필요가 없기 때문입니다. 의뢰 조건은 「sprout_deer_1을 3회 발견」이고, 클라이언트는 그 id를 표시에만 쓰므로 대상 행을 조회하지 않습니다. 참조로 두면 대상 목록을 컬럼 하나에 담을 수 없으므로 컬럼을 3개로 나누어야 하고, 그것은 이 자리에 맞지 않습니다.


3. .tbs 선언

samples/wildling/schemas/ 아래에 3개 파일로 나눕니다. recipe의 Schemas가 그 디렉터리를 가리킵니다.

파일담는 것
common.tbsStatBlock · Cost · EncounterEntry
reward.tbsReward와 변종 4개, Requirement와 변종 4개
battle.tbsEffect와 변종 4개, enum 4개

3.1 common.tbs

/// 와일드링과 수호자가 공유하는 능력치 묶음.
struct StatBlock
/// 체력.
field hp int (min=1)
/// 공격.
field attack int (min=1)
/// 방어.
field defense int (min=0)
/// 행동 순서. 같으면 배치 순서가 정합니다.
field speed int (min=1)
/// 치명타 확률. 만분율.
field crit_rate int (min=0, max=10000)
/// 치명타 배수. 만분율. 10000이 1배입니다.
field crit_power int (min=10000)

/// 재화 하나를 얼마나 소모하는가. 셀 하나에 `gold,4400`으로 적습니다.
struct Cost (sep=",")
/// 어느 재화인가.
field currency_id foreign Currency
/// 수량.
field amount int (min=1)

/// 출현 목록의 한 항목.
struct EncounterEntry
/// 어느 단계가 나오는가.
field monster_id foreign Monster
/// 가중치. 등급 기본값에 지역 계수를 적용한 값입니다.
field weight int (min=1)
/// 어느 슬롯에서 나오는가.
field encounter_slot EncounterSlot

Costsep을 두는 것이 이 파일의 요점입니다 — 같은 타입을 셀 하나로 적는 벌멤버를 컬럼으로 펼친 벌이 둘 다 있고, 와이어가 같습니다 (6.3).

3.2 reward.tbs

/// 무엇을 얼마나 주는가. 변종이 대상 카탈로그를 정합니다.
abstract struct Reward
/// 수량. 모든 변종이 갖습니다.
field amount int (min=1)

/// 아이템을 준다.
struct ItemReward extends Reward @1
field item_id foreign Item

/// 재화를 준다.
struct CurrencyReward extends Reward @2
field currency_id foreign Currency

/// 와일드링을 준다. 수호자 격파 보상이 이것입니다.
struct MonsterReward extends Reward @3
field monster_id foreign Monster

/// 울림 조각을 준다. 대상 종의 조각입니다.
struct ShardReward extends Reward @4
field monster_id foreign Monster

/// 무엇이 충족되어야 하는가.
abstract struct Requirement

/// 그 개체의 레벨.
struct LevelRequirement extends Requirement @1
field level int (min=1, max=70)

/// 기록부의 상태.
struct CodexRequirement extends Requirement @2
field codex_state CodexState

/// 아이템 보유.
struct ItemRequirement extends Requirement @3
field item_id foreign Item
field amount int (min=1)

/// 스테이지 클리어.
struct StageRequirement extends Requirement @4
field stage_id foreign Stage

/// 기록부 완성률. 주어가 없습니다.
struct CodexCompletionRequirement extends Requirement @5
field percent int (min=1, max=100)
  • CodexRequirementCodexCompletionRequirement가 나뉘어 있습니다. 앞은 「그 개체의 기록 상태」이고 뒤는 「기록부 전체의 비율」입니다 — 주어가 있고 없고가 다르므로 변종도 다릅니다. 뒤엣것이 없어서 지역 해금이 평가되지 않던 것이 게임 보고 §1입니다.
  • Rewardamount가 기반에 있습니다. 와이어에서 컬럼 하나이고 모든 행에 값이 있습니다. 변종마다 복제하면 컬럼이 4개가 되고 그중 하나만 채워집니다.
  • MonsterRewardShardRewardmonster_id를 공유합니다. 같은 이름 · 같은 타입이므로 컬럼 하나입니다. 이름을 shard_monster_id로 달리 두면 컬럼이 2개가 되고, 시트가 넓어집니다.
  • Requirement는 기반에 필드가 없습니다. 그 형태도 지원되는지 확인하는 자리입니다.
  • 판별자 @N을 전부 명시합니다. 선언 순서에 묶이면 변종을 재배열할 때 배포된 리더가 다른 변종으로 읽습니다.

3.3 battle.tbs

/// 스킬 하나가 일으키는 것.
abstract struct Effect
/// 발동 확률. 만분율. 10000이 항상입니다.
field chance int (min=1, max=10000)

/// 피해.
struct DamageEffect extends Effect @1
/// 공격력에 적용하는 배수. 만분율.
field power int (min=1)

/// 회복.
struct HealEffect extends Effect @2
/// 회복량에 적용하는 배수. 만분율.
field power int (min=1)

/// 상태 부여.
struct StatusEffect extends Effect @3
field status StatusKind
/// 지속 턴.
field duration int (min=1, max=9)

/// 능력치 변동.
struct BuffEffect extends Effect @4
field stat StatKind
/// 변동률. 만분율. 음수는 하락입니다.
field ratio int
field duration int (min=1, max=9)

/// 속성.
enum Element
/// 잎새에 강하고 물결에 약합니다.
value Flame = 1
value Tide = 2
value Leaf = 3
/// 물결과 잎새에 강하고 그늘에 약합니다.
value Arc = 4
/// 번개에 강하고 약한 상대가 없습니다.
value Umbra = 5

/// 희소성. 종의 성질이고 변하지 않습니다.
enum Grade
value Common = 1
value Rare = 2
value Epic = 3
value Legendary = 4
value Mythic = 5

/// 기록부의 상태.
enum CodexState
value Unknown = 0
value Sighted = 1
value Recorded = 2
value Studied = 3

/// 능력치의 종류. `BuffEffect`가 가리킵니다.
enum StatKind
value Attack = 1
value Defense = 2
value Speed = 3
value CritRate = 4

enum을 .tbs와 시트에 반씩 둡니다. .tbs에 두는 것은 Effect · Requirement 변종이 멤버 타입으로 쓰는 것들입니다 — 선언이 같은 파일에 있어야 읽는 사람이 한 번에 봅니다. 나머지(Role · EncounterSlot · StatusKind · RegionState · MissionCycle · ItemCategory)는 시트 탭에 둡니다. 양쪽이 다 있어야 두 표기가 다 검증됩니다.


4. 테이블 설계

컬럼 표기는 :field / :type의 쌍으로 적습니다. :desc:target은 생략해 적었고, 실제 시트에는 전부 있습니다.

4.1 와일드링

Monster — 종의 한 단계

:field:type비고
monster_idstring기본 인덱스
*display_codestring (regex="^[a-z]{2}[0-9]{3}$")보조 키. 운영 도구용
species_idstring같은 종을 묶습니다
stageint (min=1, max=3)
namestring (text=Monster)번역 수집
descriptionstring (text=Monster, namespace=Codex)기록부 설명
elementElement.tbs 선언
gradeGrade.tbs 선언
roleRole시트 enum
base.hpbase.crit_powerStatBlock첫 멤버 컬럼에만 타입 기재
habitatbitset서식 지역 플래그. 0b10011
max_stageint (min=1, max=3)
iconstring (asset=icon):target c
model_offsetvec3f?:target c. 연출 보정
tagsstring[]셀 배열. 검색 태그
#old_grade@7묘비. 등급을 종 단위로 옮기기 전의 컬럼
#메모 컬럼
  • habitatbitset으로 두는 것은 지역이 5개이고 한 종이 여러 지역에 나타나기 때문입니다. foreign Region[]으로도 적을 수 있지만, 기록부 화면이 「이 종이 나오는 지역」을 플래그 비교로만 쓰므로 참조가 필요하지 않습니다.
  • model_offset이 옵셔널인 것은 대부분의 종이 보정을 쓰지 않기 때문입니다.

MonsterSkill — 단계별 사용 가능 스킬

:field:type
monster_idforeign Monster
skill_idforeign Skill
slot_kindSlotKind
unlock_stageint (min=1, max=3)

기본 인덱스가 monster_id이고 같은 값이 여러 행에 나타나므로, key="monster_id,skill_id" 복합 기본 인덱스로 둡니다. 이 테이블은 참조 대상이 아니므로 복합 키 제약에 걸리지 않습니다.

MonsterAwakening — 각성 관계

:field:type비고
from_monster_idforeign Monster기본 인덱스
to_monster_idforeign Monster같은 테이블을 가리킵니다
gain.hpgain.crit_powerStatBlock
requirements[].$typeRequirement멀티 로우 다형 배열
requirements[].level합집합 컬럼
requirements[].codex_state
requirements[].item_id
requirements[].amount
requirements[].stage_id
costs[]Cost셀 하나에 shard,30

requirements가 이 데이터에서 다형 배열의 정본입니다. 조건 개수가 종마다 2~4개이고 형태가 갈립니다.

4.2 전투

Skill

:field:type비고
skill_idstring
namestring (text=Skill)
descriptionstring (text=Skill)
elementElement?무속성 스킬은 빈 칸
target_scopeTargetScope시트 enum
cooldownint (min=0, max=9)
iconstring (asset=icon):target c
effects[].$typeEffect멀티 로우 다형 배열
effects[].chance기반 필드
effects[].powerDamageEffect · HealEffect 공유
effects[].status
effects[].stat
effects[].ratio
effects[].durationStatusEffect · BuffEffect 공유

컬럼이 모든 변종의 합집합이고, 같은 이름 · 같은 타입인 powerduration이 컬럼을 공유합니다. 변종 4개의 멤버 합계는 8개인데 컬럼은 6개입니다.

SkillGrowth

:field:type
skill_idforeign Skill
levelint (min=1, max=10)
power_factorint (min=10000)
costs[0] costs[1]Cost

key="skill_id,level" 복합 기본 인덱스입니다. costs원소 번호 칸이므로 배열의 세 표기 중 두 번째입니다 — 타입은 원소 0에만 적습니다.

ElementAffinity — 매트릭스 표

:field:type
attackerElement
1 2 3 4 5int

컬럼 이름이 정수여야 매트릭스로 판독됩니다. 그래서 방어 속성 축은 이름이 아니라 Element enum의 값입니다. 값은 만분율 배수이고, 유리는 13500, 불리는 7500, 그 외는 10000입니다.

산출물은 배열 컬럼 하나와 컬럼 테이블 ElementAffinityColumn입니다. 두 테이블은 같이 배포해야 합니다 — at이 자리이지 id가 아니고, 컬럼이 중간에 추가되면 뒤가 밀립니다.

자르기를 걸 수 없는 자리입니다. 매트릭스에서 뒤를 자르면 행마다 배열 길이가 달라지고 value[at]이 성립하지 않습니다. TrimTrailingArrayElements를 이 소스에서 켜지 않는 이유이기도 합니다.

Boss

:field:type비고
boss_idstring
monster_idforeign Monster외형과 기본 능력치의 출처
stat_factor.hpStatBlock계수. 만분율
abilityBossAbility시트 enum
ability_pattern[0][0][2][2]int배열의 배열. 페이즈 3 × 행동 3
effects[].$typeEffect특수 능력의 효과
spawn_rotationquat?:target c
tintcolor32:target c

ability_pattern이 배열의 배열입니다 — 페이즈마다 행동 순서가 있고, 안쪽 레벨에는 이름이 없습니다. 소비자가 적을 낱말이 없으므로 번호로 가리키는 형태 그대로입니다.

4.3 세계

Region

:field:type비고
region_idstring
namestring (text=World)
orderint (min=1)
stateRegionState시트 enum
theme_elementElement
backgroundstring (asset=model):target c
fog_colorcolor:target c
unlocks[].$typeRequirement멀티 로우 다형 배열
unlocks[].level
unlocks[].codex_state
unlocks[].item_id
unlocks[].amount
unlocks[].stage_id

RegionYield

:field:type
region_idforeign Region
hour_bandint (min=0, max=7)
gold_per_hourint (min=0)
food_per_hourint (min=0)
drop_group_idforeign DropTable

key="region_id,hour_band". 시간대별로 산출이 다른 것은 방치 8시간이 균등하지 않게 하는 설계이고(기획서 §10.3), 그 결과로 복합 기본 인덱스가 필요해집니다.

Stage

:field:type비고
stage_idstring첫 키
region_idforeign Region복합 보조 키의 성분
indexint (min=1, max=18)같음
stage_kindStageKind시트 enum
wave_monster_idsforeign Monster[]셀 안의 참조 배열
wave_levelsint[] (size=1..5)셀 배열
reward_group_idforeign StageReward
boss_idforeign Boss?수호자 스테이지에만

key="stage_id; region_id,index" — 첫 키가 단일이므로 StageRequirement가 이 테이블을 가리킬 수 있고, 둘째 키가 복합이므로 (지역, 순번) 조회가 나옵니다.

wave_monster_idswave_levels짝을 이루는 두 배열입니다. 길이가 같아야 하는 것은 타입으로 표현되지 않으므로 검증 규칙이 봅니다 (7).

EncounterTable

:field:type비고
encounter_idstring
region_idforeign Region
entries[].monster_idEncounterEntry멀티 로우. 첫 멤버에만 타입 기재
entries[].weight
entries[].encounter_slot
gate[].$typeRequirement은둔 슬롯의 조건
gate[].codex_state
gate[].stage_id

:table EncounterTable(side=s)테이블 전체가 서버 대상입니다. 출현 확률은 클라이언트가 알 필요가 없고, 알면 조작 대상이 됩니다.

멀티 로우 그룹이 2개인 테이블입니다. entriesgate가 각자 독립적으로 쌓이고 길이가 다릅니다 — 같은 행에 있다고 짝이 되는 것이 아닙니다.

4.4 성장

GrowthCurve

:field:type
gradeGrade
levelint (min=1, max=70)
hp_factorint (min=10000)
attack_factorint (min=10000)
defense_factorint (min=10000)
bonus_factorint?
costs[0] costs[1]Cost

key="grade,level". 350행입니다 — 등급 5 × 레벨 70.

ResonanceRank

:field:type
gradeGrade
rankint (min=1, max=5)
stat_factorint (min=10000)
shard_costint (min=1)
unlock_notestring (text=Growth)?

4.5 보상과 조건 — 항목 테이블로의 분리

다형 레코드를 배열로 두지 않고 테이블 하나로 내립니다. 그러면 판별자가 스칼라 그룹이 되고, 멀티 로우와 판별자의 조합(8.1)을 기다리지 않습니다. 정규화로도 이쪽이 맞습니다 — 같은 보상 묶음을 여러 테이블이 가리키므로 묶음에 id가 필요합니다.

RewardGroup · RewardEntry

테이블:field:type
RewardGroupreward_group_idstring
notestring?
RewardEntryreward_group_idforeign RewardGroup
orderint (min=0, max=15)
reward.$typeReward
reward.amount
reward.item_id
reward.currency_id
reward.monster_id
rateint (min=1, max=10000)
server_weightint? · :target s

RewardEntrykey="reward_group_id,order"이므로 참조 대상이 되지 않습니다. 가리켜야 하는 것은 묶음이고, 그 자리가 RewardGroup입니다.

Reward를 쓰는 8곳이 컬럼 하나로 줄어듭니다reward_group_id foreign RewardGroup입니다. DropTable · StageReward · CodexReward · Mission · AdReward · PassBenefit · ShopSlot · Package가 그 컬럼을 갖고, 합집합 컬럼 5개는 RewardEntry 한 곳에만 있습니다. .tbs 선언의 효과가 사라진 것이 아니라 한 자리로 모인 것입니다.

RequirementGroup · RequirementEntry

같은 형태입니다. MonsterAwakening · Region · Mission · EncounterTablerequirement_group_id를 갖습니다.

테이블:field:type
RequirementEntryrequirement_group_idforeign RequirementGroup
orderint (min=0, max=7)
req.$typeRequirement
req.level
req.codex_state
req.item_id
req.amount
req.stage_id

Mission

:field:type비고
mission_idstring
cycleMissionCycle시트 enum
target_idstring (refs="Monster;Region;Item")검사. 참조가 아닙니다
goal_countint (min=1)
requirement_group_idforeign RequirementGroup
reward_group_idforeign RewardGroup

4.6 경제

Item

:field:type비고
categoryItemCategory첫 컬럼이지만 인덱스가 아닙니다
item_idstringkey=item_id
namestring (text=Item)
gradeGrade
iconstring (asset=icon):target c
stack_maxint (min=1, notDefault)

Currency · Shop · ShopSlot · Package · PassBenefit

테이블비고
Currencycurrency_id · 표시명 text · 아이콘 asset · 보유 상한
Shop상점 정의. 갱신 주기
ShopSlot행 벌 3개 — 상시 · _Season · _Package
Packageprice_display:variantkr · us · jp
PassBenefit월간 통행증의 일일 지급과 상시 효과

Package.price_display:variant의 자리입니다. 가격 표시 문자열만 국가별로 갈리고 나머지 필드는 공유되므로, 행을 3벌 두는 것보다 컬럼을 3벌 두는 것이 맞습니다.

4.7 문자열과 상수셋

엔티티비고
StringTabletext 수집의 대조본. 이 테이블 자체는 text 컬럼을 갖지 않습니다
BattleConst방어 계수 · 최대 턴 · 배속 단계
GrowthConst단계별 레벨 상한 · 스킬 상한 · 공명 상한
AwakeningConst슬롯 증가량
IdleConst누적 상한 · 진척도 계수 · 2배 대상 구분
PartyConst파티 인원 · 저장 슬롯 · 열별 배치 제약
CodexConst등급별 관측 상한 · 전투 누적 계수
CollectionConst미기록 보정 계수 · 조각 상한
MissionConst일일 · 주간 개수 · 초기화 시각

상수셋의 이름에는 경로와 원소 번호를 쓸 수 없습니다. PartyConst의 열별 배치 제약은 string[] 상수 5개입니다 — 처음에는 allowed_columns[0]으로 적었고, 상수 이름이 식별자여야 한다는 규칙에 걸렸습니다. 원소 번호 칸은 SkillGrowth.costs[0]GrowthCurve.costs[0]이 담당합니다.


5. 워크북과 시트 배치

워크북
Monster.xlsxMonster · MonsterSkill · MonsterAwakening
Battle.xlsxSkill · SkillGrowth · ElementAffinity · Boss
World.xlsxRegion · RegionYield · Stage · StageReward · EncounterTable
Growth.xlsxGrowthCurve · ResonanceRank · CodexReward · Mission
Economy.xlsxCurrency · Item · DropTable · Shop · ShopSlot · ShopSlot_Season · ShopSlot_Package · Package · PassBenefit · AdReward
Text.xlsxStringTable
Enums.xlsxRole · EncounterSlot · StatusKind · RegionState · MissionCycle · ItemCategory · SlotKind · StageKind · TargetScope · BossAbility
Const.xlsxConst_Battle · Const_Growth · Const_Idle · Const_Party · Const_Codex · Const_Mission

40개 탭입니다. Const_* 탭 2개가 1.1의 예외이고, 나머지는 탭 하나에 엔티티 하나입니다.

5.1 시트의 서식

자리
선언 행배경 #E3EDF8, 마커 글자 #1A5FA8 볼드
헤더 행 (:field · :type · :desc · :target · :variant)배경 #F1F6FB
메모 컬럼 · # 제외 행글자 #9AA1A8, ##C0392B
표 테두리격자 #D8DDE2, 외곽은 굵게

팔레트는 spec/layout/primary-layout-figures.py의 것을 그대로 씁니다 — 워크북이 문서의 그림과 같은 모습이 되고, 대조표에서 그림과 실물을 나란히 둘 수 있습니다.

틀 고정은 헤더 아래 · 인덱스 컬럼 오른쪽, 자동 필터는 :field 행에 걸고, 컬럼 폭은 값의 실측으로 정합니다.


6. 기능 배치표

이 표가 이 샘플의 목적입니다. 왼쪽이 기능이고 오른쪽이 그 기능이 실제로 쓰이는 자리입니다. 빈 칸이 없어야 「기능 전수」가 성립합니다.

6.1 시트 표현

기능어디
선언 셀 · 마커 열모든 탭
엔티티 설명 셀모든 탭
헤더 행 5종:variantPackage에만, 나머지는 모든 탭
한 시트에 엔티티 여럿Const_Battle · Const_Growth
완전히 빈 행의 경계Const_Growth
마커 열 # 행 제외Monster · Skill · Item
메모 컬럼 #Monster · GrowthCurve · DropTable
묘비 #이름@NMonster.#old_grade@7
와이어 태그 @NMonster · Skill · Item의 일부 컬럼
보조 인덱스 *Monster.*display_code
key= 단일 지정Item
key= 복합RegionYield · MonsterSkill · SkillGrowth · GrowthCurve
key= 여러 개Stage
side= 엔티티 대상EncounterTable(side=s)
:target 컬럼 대상Monster.icon(c) · DropTable.server_weight(s)
:variant 필드 변형Package.price_displaykr · us · jp
행 벌ShopSlot · ShopSlot_Season · ShopSlot_Package
인라인 레코드 그룹Boss.stat_factor는 struct이므로, 인라인은 Region의 좌표 그룹에서
DSL struct 그룹Monster.base · MonsterAwakening.gain
sep 한 셀 structMonsterAwakening.costs[] · SkillGrowth.costs[0]
원소 번호 칸 [n]SkillGrowth.costs · GrowthCurve.costs
셀 배열 T[]Monster.tags · Stage.wave_levels
멀티 로우 []EncounterTable.entries · MonsterAwakening.costs
배열의 배열Boss.ability_pattern[0][0]
중첩 — 멤버가 레코드Boss.stat_factor
foreign 단일모든 참조 컬럼
foreign X[] 참조 배열Stage.wave_monster_ids
refs= 검사Mission.target_id
다형 레코드 $type — 스칼라 그룹SkillEffect.effect · RewardEntry.reward · RequirementEntry.req
다형 레코드 + 멀티 로우Boss.effects[] 하나뿐입니다 (8.1)
매트릭스 표ElementAffinity
bitsetMonster.habitat
진법 리터럴Monster.habitat의 값을 0b
합성 값 타입Monster.model_offset(vec3f) · Boss.spawn_rotation(quat) · Region.fog_color(color) · Boss.tint(color32)
text 수집Monster · Skill · Item · Region · Growth 그룹
text 네임스페이스Monster.description
asset 종류icon · model
옵셔널 ?Skill.element · Monster.model_offset · Stage.boss_id · GrowthCurve.bonus_factor
컬럼 제약 min·max거의 모든 수치 컬럼
allowedItem.category의 일부 값 제한
regexMonster.*display_code
sizeStage.wave_levels
notDefaultItem.stack_max
enum — 시트Enums.xlsx의 10개
enum — .tbsElement · Grade · CodexState · StatKind
enum 별칭 aliasRole · RegionState
상수셋8개

6.2 실행과 산출

기능어디
Schemas.tbs 디렉터리recipe
TableRowSets 정규식recipe. ShopSlot의 벌 3개
Variants 선택recipe. 기본은 kr
Assets.Rootsicon · model 2종
Naming 검사필드 snake · 나머지 pascal · OnViolation: error
검증 규칙 4단계7
KnownProblems의도한 데이터 문제 2건
csharp 타깃유니티 프로젝트 안으로. 코드 생성은 이것 하나입니다
binary 타깃.bytes · 인코딩 보고서 · 스키마 기준선
업데이터csharpWriteUpdater
빌드 캐시두 번째 실행에서 확인
--validate-only검증만

6.3 같은 타입, 두 표기

Cost가 세 자리에 서로 다른 표기로 나타납니다. 와이어는 셋 다 같습니다.

자리표기셀에 적히는 것
MonsterAwakening.costs[]멀티 로우 + sepshard,30
SkillGrowth.costs[0] [1]원소 번호 칸 + sepgold,1200
GrowthCurve.costs[0].currency_id [0].amount원소 번호 칸 + 멤버 펼침gold / 4400

세 번째가 sep을 쓰지 않고 멤버를 컬럼으로 펼친 벌입니다. 같은 .tbs 선언을 두 방식으로 읽는 것이 확인되는 자리입니다.

6.4 이 데이터가 쓰지 않는 것

기능
구글 스프레드시트 소스자격증명이 필요해 저장소에 담을 수 없습니다. recipe에 주석으로 둡니다
데이터베이스 타깃 4종서버가 필요합니다. 회귀 스위트가 컨테이너로 확인합니다
히스토리 · --serve실행이 필요합니다
sheet-per-table · named-range 레이아웃sproutcanopy의 몫입니다
전 언어 타깃samples/sprout/out/이 이미 그 답입니다
json · text · html · summary 타깃최종 확인 지점이 유니티이므로 코드 생성은 csharp 하나입니다. 값을 눈으로 볼 자리는 유니티의 확인 씬이고, 나머지 타깃은 sprout이 이미 냅니다
set · map이름과 함께 거절됩니다. 거절 결과를 대조표에 싣습니다
변종의 묘비표기가 아직 없습니다
$key · $value아직 지원하지 않습니다
중첩 멀티 로우1차 거절 대상입니다
TrimTrailingArrayElementsElementAffinity가 있어 이 소스에서 켤 수 없습니다

7. 검증 규칙

시트로 표현할 수 없는 규칙입니다. samples/wildling/validation/rules/ 아래에 둡니다.

단계규칙무엇
preInputsRules.tsv 원본과 워크북의 행 수 일치
tablesMonsterRulesspecies_id + stage의 유일성. max_stage와 실제 각성 사슬의 일치
tablesMonsterAwakeningRules각성 후 능력치가 직전 단계 상한보다 높은지 (기획서 §7.3)
tablesStageRuleswave_monster_idswave_levels의 길이 일치
tablesEncounterTableRules지역마다 고유 종 4종 이상, 은둔 슬롯 1종
tablesDropTableRules확률 합이 10000을 넘지 않는지
tablesMissionRulestarget_idcycle에 맞는 카탈로그를 가리키는지
globalProgressionRules각성 재료가 2개 지역 이상에서 산출되는지 (기획서 §10.4)
globalConventionsRulestext 컬럼의 빈 값, 아이콘 이름 규약
runtime이 샘플에는 없습니다. 연결이 필요한 규칙이 없습니다

MonsterAwakeningRulesProgressionRules가 이 규칙 집합의 요점입니다 — 둘 다 기획서가 정한 것이고, 타입으로는 표현되지 않으며, 어긋나면 게임이 성립하지 않습니다.


8. 다음 단계

#무엇선행
3저작기와 .tsv 데이터없음
4recipe · 검증 규칙 · 애셋3
5변환하며 고치기4
6유니티 확인 씬5

8.1 멀티 로우와 판별자의 조합

멀티 로우 자체는 구현되어 있습니다 — 주 레이아웃 2단계이고, 같은 배열을 [n][]로 적은 .tcb가 바이트 동일함까지 확인되어 있습니다. 남은 것은 멀티 로우와 판별자의 조합이고 (다형과 참조 배열 §11의 5단계), 현재 픽스처는 Effect.$type 스칼라 그룹 하나입니다.

4.5가 그 조합을 요구하지 않도록 보상과 조건을 테이블로 내렸습니다. 그래서 이 데이터는 지금 표기로 전량 변환됩니다.

조합이 남는 자리를 하나만 둡니다 — Boss.effects[]입니다. 수호자의 특수 능력은 수호자 하나에만 종속되고 공유되지 않으므로 묶음 id를 줄 가치가 없고, 그래서 그 표기가 요구되는 자리의 예로 정확합니다. 5단계가 들어올 때까지 이 컬럼은 거절되므로, recipe.jsonc에서 BossExcludeSheets로 빼고 5단계와 함께 되돌립니다.

8.2 조합이 아닌 멀티 로우의 자리

조합이 아닌 멀티 로우는 이 데이터에도 있습니다.

테이블컬럼
EncounterTableentries[].monster_idEncounterEntry struct 그룹
MonsterAwakeningcosts[]sep을 쓴 Cost

EncounterTable은 멀티 로우 그룹이 하나가 되었습니다 — 조건은 requirement_group_id로 옮겼습니다.


EOD