유니티로 게임을 만지다 보면 데이터를 직접 압축할 일이 종종 생긴다.
특히 서버와 큰 데이터를 주고받거나 서버에서 굳이 열어보지 않을 데이터를 수집하는 등의 작업에서 압축을 하면 효과를 볼 때가 있다.
아래는 문자열을 압축하는 간단한 코드이다. 유니티서 사용할 경우 동기 버전으로 변형하거나 Task 대신 UniTask 등으로 변형해서 사용할 수 있다.
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Threading.Tasks;
public static class Compression
{
public static async Task<byte[]> Compress(string source)
{
var bytes = Encoding.UTF8.GetBytes(source);
await using var input = new MemoryStream(bytes);
await using var output = new MemoryStream();
await using var brotliStream = new BrotliStream(output, CompressionLevel.Fastest);
await input.CopyToAsync(brotliStream);
await brotliStream.FlushAsync();
return output.ToArray();
}
public static async Task<string> Decompress(byte[] compressed)
{
await using var input = new MemoryStream(compressed);
await using var brotliStream = new BrotliStream(input, CompressionMode.Decompress);
await using var output = new MemoryStream();
await brotliStream.CopyToAsync(output);
await brotliStream.FlushAsync();
return Encoding.UTF8.GetString(output.ToArray());
}
}
기타 압축에 대한 사소한 정보들
- brotli는 구글에서 개발한 압축 알고리즘으로, 특히 텍스트 데이터에 일반적으로 gzip보다 빠르고 압축률이 좋다.
- C#의 ZLibStream, GZipStream은 각각 zlib(RFC-1950), gzip(RFC-1952) 형식을 구현한다. zlib 및 gzip은 압축에 사용하는 알고리즘을 선택할 수 있도록 되어 있는데, 일반적으로, 그리고 C#의 구현에서도 deflate를 사용한다
- DeflateStream은 deflate 알고리즘(RFC-1951) 을 구현한다.
- 위의 코드는 비동기 버전으로 작성되어 있지만, 일반적으로 몇KB 정도는 게임 도중 아무때나, 몇백KB까지도 적당한 UI와 함께라면 동기식으로 실행해도 거의 끊김이나 어색함을 느낄 수 없다.
- brotli는 압축 해제는 매우 빠르지만, CompressionLevel.Optimal 옵션으로 압축을 할 경우 매우 느리다. 클라이언트에서 압축을 해야 하는 경우 CompressionLevel.Fastest를 사용하는 편이 좋다.
- 주의: 유니티에서 실행할 경우, BrotliStream은 비동기 버전으로 실행해도 동기식처럼 작동한다. 기본 SynchronizationContext가 제공하는 병렬처리 기능에 의존하기 때문이다. DeflateStream는 그렇지 않기 때문에 비동기+병렬로 작동한다.
'Unity > 코드' 카테고리의 다른 글
코루틴 여러개가 모두 완료될때까지 대기하는 코드 (0) | 2024.02.20 |
---|