본문으로 건너뛰기
문서
이 페이지의 내용

레벨 형식

레벨은 폴더입니다: 내용은 level.json 또는 level.blob, 메타데이터는 metadata.json 또는 metadata.blob, 그리고 커버와 미디어 파일. 백업, 기록, 플레이어 설정은 기기에 남습니다

레벨 폴더

레벨 폴더의 모든 파일 이름은 FileNames에 고정되어 있습니다:

파일모델내용
level.json 또는 level.blobLevel내용: 설정, 오브젝트와 이벤트, 오디오, 리소스, 힌트
metadata.json 또는 metadata.blobLevelMeta제목, 설명, 제작자, 라이선스, 리소스마다 하나씩의 기록, 커버 참조
logo.png 또는 logo.jpg-커버
트랙, 이미지, 폰트-레벨이 참조하는 미디어 파일

확장자가 곧 형식입니다. 형식은 파일 안 어디에도 기록되지 않습니다. 읽는 쪽은 어떤 파일이 있는지 봅니다: level.json인지 level.blob인지

레벨과 메타데이터는 각자 형식을 따로 고릅니다. 예를 들어 내장 레벨 new-zero-demo에는 level.blob 옆에 metadata.json 파일이 있습니다

metadata.json 파일은 일부러 분리되어 있습니다. 카탈로그는 작은 메타데이터 파일 천 개로 레벨 천 개를 보여 줍니다. 그러기 위해 레벨을 하나도 열지 않습니다

리소스

리소스는 uri, uri_type(ResourceUriType) 한 쌍으로 지정됩니다:

값타입파일 위치
1LevelPath레벨 폴더 안. 이 타입만 레벨을 이동 가능하게 만듭니다
2AbsolutePath이 기기의 다른 곳
3DirectUrl네트워크에서 다운로드
4StreamingAssets레벨이 아니라 게임과 함께 배포됨

AbsolutePath 타입은 곡을 중심으로 레벨을 만들 때 생깁니다. 아카이브로 내보내면 그런 파일은 안으로 복사됩니다. 자세히 - 아카이브와 보호

커버는 다른 리소스와 마찬가지로 LevelMeta.LevelLogo에서 얻을 수 있습니다. logo.png인지 logo.jpg인지는 원본 이미지의 이름이 아니라 파일 자체의 바이트로 결정됩니다

커버의 저작권 기록은 resource_type 9(LevelLogo)인 ResourceMeta입니다. 여기에는 resource_id도 resource_guid도 채워지지 않습니다: 레벨의 커버는 하나뿐이므로 타입만으로 주소가 됩니다

AI 사용 선언

LevelMeta 및 모든 ResourceMeta에는 AiGeneration 타입의 ai_generated 필드가 있습니다:

값이름의미
0NotSpecified선언 없음, 알 수 없음. 기본값이며, 키가 없으면 이 값으로 읽힙니다
1NoAI 생성 없이 만들었다고 선언됨
2YesAI로 생성했다고 선언됨

LevelMeta에서 이 값은 레벨 자체의 내용만 다룹니다. 각 리소스와 커버는 자기 기록에서 따로 선언합니다. 레벨에 AI 콘텐츠가 있는지는 저장되지 않습니다: 그 답은 LevelMeta.ContainsAiContent()에서 나오며, Yes 값만 계산에 들어갑니다

레벨과 함께 이동하지 않는 것

다음 파일은 레벨 폴더 안이 아니라 levels 폴더 옆에 있습니다. 레벨을 아카이브로 만들거나, 보내거나, 삭제해도 영향을 받지 않습니다:

폴더 또는 파일내용남는 이유
backups/에디터 자동 저장, 레벨 ID마다 폴더 하나, backup_level_<time>.<extension>보호 대상 폴더 안의 사본은 그 폴더와 함께 삭제됩니다
stats/LevelId별 기록과 진행 상황, statistics.json그렇지 않으면 누군가 보낸 레벨이 이미 클리어된 상태로 도착합니다
settings.jsonUserSettings, 기기 전체에 대한 플레이어 설정레벨이 아니라 플레이어의 것입니다
resources/themes, effects, shapes, prefabs기기의 공유 라이브러리기기의 모든 레벨이 함께 씁니다
reports/진단 보고서-

JSON 키

JSON은 항상 들여쓰기 없이 압축된 형태로 기록됩니다. 눈으로 읽으려면 텍스트 에디터에서 서식을 정리합니다

키의 길이는 레벨 안에서 그 키가 몇 번 나오는지에 따라 정해집니다:

  • 파일당 한 번 나오는 키는 snake_case의 온전한 단어로 씁니다: level_id, min_generation
  • 수천 번 반복되는 키는 몇 글자로 줄입니다: objs, f, e, v

키는 레벨 파일 바이트의 52%를 차지하므로, 이것은 취향이 아니라 규칙입니다. 모든 키는 Names.cs에 선언되어 있습니다

다형 값은 [tag, data] 형태로 기록됩니다. 일반 문자열은 [0,{"v":"Author"}], 현지화 문자열은 [1,{"strs":[...]}]

ObjectId 같은 식별자 래퍼는 숫자나 문자열 그대로 기록됩니다

식별자

정수 식별자의 부호에는 의미가 있습니다. 0 값은 항상 "설정되지 않음"을 뜻합니다:

식별자JSON 키양수음수
ObjectIdid, 부모는 pid레벨 오브젝트게임 오브젝트: -1 카메라, -2 로컬 플레이어, -3 프리팹 템플릿의 루트
리소스 식별자txid, fnid, auid, byid, ttid게임과 함께 배포되는 리소스레벨 자체 리소스
오디오 트랙의 AudioIdaid이 레벨의 트랙사용하지 않음

pid 값이 0인 오브젝트에는 부모가 없습니다. -3보다 작은 수는 게임 실행 중에만 존재하며 파일에 기록되지 않습니다

Marker, Checkpoint, BeatSegment에는 식별자가 없습니다. 이들의 주소는 시간 위의 위치입니다: 마커와 체크포인트는 프레임 f, 비트 세그먼트는 구간 sp의 첫 프레임입니다(세그먼트는 겹치지 않습니다). 이런 오브젝트를 옮기면 주소가 바뀝니다

프리팹 오버라이드는 필드를 JSON 키가 아니라 번호로 지정합니다. 배치는 오버라이드를 mod 목록에 보관합니다. 각 오버라이드의 key에는 숫자 세 개가 들어갑니다:

  • id - 템플릿 안의 오브젝트이며, 레벨에 있는 그 사본이 아닙니다
  • f - 필드의 영구 번호
  • i - 목록 필드의 요소, 필드 전체라면 -1

번호는 필드에 영구히 묶입니다. 그 필드의 JSON 키 이름을 바꿔도 레벨에 이미 저장된 오버라이드는 깨지지 않습니다

바깥쪽 "g"

모든 직렬화 루트는 키 두 개짜리 엔벨로프로 감싸집니다:

{"g":2,"v":{"level_id":"18df5f61-3aa4-4812-bf69-d357f2201bc3","vrs":"1.0", ... }}

g - 모델 세대(Names.Generation), v - 데이터

엔벨로프는 중첩됩니다. Level 안에서 LevelSettings, GameLevel, AudioLevel, LevelResources, LevelHints에 각각 자기 엔벨로프가 있습니다. 세대의 작동 방식 - 버전 관리와 마이그레이션

주의

g, vrs 두 값은 서로 다른 수입니다. vrs - 제작자가 정한 레벨 버전(LevelMeta.LevelVersion)이며 형식과는 관계가 없습니다. g 값을 직접 바꾸지 마십시오: 빌드가 아는 것보다 높은 g 값을 가진 파일은 아예 읽히지 않습니다