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

Blob 형식

.blob 파일에는 .json 파일과 같은 데이터가 바이너리 형태로 들어 있습니다: 24바이트 헤더 뒤에 데이터가 옵니다. 캐시가 아니라 동등한 레벨 형식입니다

레벨을 .blob 형식으로만 저장할 수도 있습니다

레벨 volcano, 오브젝트 19,341개크기
level.json15.7 MB
level.blob5.1 MB, 읽기 203 ms

.blob 형식은 가독성을 약속하지 않습니다. 눈으로 읽을 수도, diff로 비교할 수도 없으므로 어디에서도 기본값이 아닙니다

모든 모델의 코덱은 Roslyn 생성기가 만듭니다

헤더

오프셋크기필드값
04매직uint 0x4F424842, 바이트 42 48 42 4F (BHBO)
42코덱 세대ushort, BlobFormat.Generation = 1
62플래그ushort, 비트 0 FlagHashed = 해시 있음. 나머지 비트는 예약되어 있으며 0 값을 유지해야 합니다
88데이터 길이long
168해시ulong, 코덱 세대를 시드로 한 데이터의 xxHash64

헤더 길이 BlobFormat.HeaderLength 값은 24바이트이며, 그 뒤에 데이터가 옵니다

검사 순서

BlobFormat.ReadHeader 메서드는 정해진 순서대로 헤더를 검사합니다. 헤더가 통과하기 전에는 아무것도 할당하지 않습니다:

  1. 매직
  2. 코덱 세대가 1임
  3. 알 수 없는 플래그가 없음
  4. 선언된 길이가 실제 길이와 같음
  5. FlagHashed 플래그가 설정되어 있다면 해시가 일치함

실패는 모두 고유한 메시지를 가진 BlobFormatException 예외입니다. "파일이 손상됨"과 "더 새로운 빌드의 파일"은 플레이어에게 서로 다른 행동을 요구하므로 하나의 오류로 합치지 않습니다

해시는 의도적으로 암호학적이지 않습니다. 해시는 손상을 잡아내고, 변조는 OpenPGP 계층이 막습니다. 자세히 - 아카이브와 보호

인코딩

  • 리틀 엔디언, 고정 폭 숫자, varint 없음
  • 문자열은 바이트 수 int 뒤에 UTF-8 데이터
  • null 값은 길이 -1입니다. 그래서 빈 목록과 없는 목록이 왕복 변환 후에도 구별됩니다
  • 다형 값은 1바이트 태그로 시작하며, 0xFF 값은 null용으로 예약되어 있습니다. 태그는 모델의 GetModelType() 값이며, JSON에서 [tag, data] 안에 기록되는 것과 같은 표식입니다
  • 파일에서 읽은 개수는 그것을 위해 무언가를 할당하기 전에 BlobReader.ReadCount에서 검사됩니다

엔벨로프와 두 가지 세대

[ModelGeneration] 특성이 붙은 모든 루트는 자기 엔벨로프를 기록합니다: 문자열로 된 도메인, int 타입의 모델 세대, 내용의 길이, 그리고 내용 자체. 도구는 이렇게 파일의 세대를 읽습니다:

var bytes = File.ReadAllBytes(path);
var reader = new BlobReader(bytes, BlobFormat.HeaderLength, bytes.Length - BlobFormat.HeaderLength);
var domain = reader.ReadString();
var generation = reader.ReadInt();

여기에는 서로 다른 세대가 두 가지 있습니다:

  • 코덱 세대는 헤더에 있으며 바이트 배치를 나타냅니다. 이것이 바뀌면 기존의 모든 .blob 파일을 통째로 읽을 수 없게 됩니다: 대신 쓸 것이 없습니다
  • 모델 세대는 각 엔벨로프에 있으며 도메인 하나의 형태를 나타냅니다. 오래된 세대는 마이그레이션되고, 새로운 세대는 NewerGenerationException 예외로 거부됩니다. 자세히 - 버전 관리와 마이그레이션

두 값을 하나의 수로 합칠 수는 없습니다. 모델 세대는 엔벨로프 안에 있고, 엔벨로프는 바이트 배치를 이미 아는 쪽만 찾을 수 있습니다. 모델이 바뀌어도 코덱 세대는 절대 바뀌지 않습니다

헤더 확장

헤더에는 여유 바이트도, 자기 길이를 담은 필드도 없습니다. 헤더는 두 가지 방법으로 확장됩니다:

  • 플래그. 15비트가 비어 있습니다. 오래된 리더는 모르는 플래그가 있는 파일을 잘못 읽는 대신 거부합니다
  • 새 코덱 세대. 새 배치에서는 헤더 길이를 포함해 무엇이든 바꿀 수 있습니다. 더 새로운 리더는 새 세대와 함께 오래된 세대도 읽을 수 있습니다

데이터 뒤에는 아무것도 덧붙일 수 없습니다. 선언된 길이가 실제 길이와 일치해야 하므로, 남는 꼬리는 모두 거부됩니다. 새 레벨 데이터는 모델 세대를 통해 데이터 안에 들어갑니다

참고

선언된 길이에서 정확히 끝나지 않는 내용은 어느 쪽으로 어긋나든 손상으로 간주됩니다. 루트가 헤더 검사를 모두 통과하고도 파싱되지 않는 경우가 있습니다. 그러면 그 루트는 길이만큼 건너뛰어지고 기본값을 유지합니다. 건너뛴 사실은 조용히 넘어가지 않고 반드시 SerializationReport에 기록됩니다