이전 참고글: 나 방금 프로그래밍의 신을 목격함 - 사회 채널 (arca.live)




마크도 그렇고 모든 광대한 오픈월드를 가진 게임은 맵 파일들을 그때그때 필요할때 디스크에서 읽어서 씀

수만,수십만,수백만개가 되는 맵파일을 한번에 로딩 하면 로딩도 오래걸리고 그걸 램에 다 올리다가 튕겨서 꺼지거나 프레임이 ㅆ창나기 때문임

그래서 마크에서 맵 빠르게 이동하면 불러올때마다 화면 드드득 하면서 렉나는거임 파일 읽느라



이 글은 가로 546 세로 366 총 199,836 개의 맵파일을 한번에 메모리에 로드 시키고 읽고/쓰면서 렉 안나는 방법에 대해 들은걸 적어봄 

솔직히 나도 100% 이해한건 아니라 이해한대로 쓸거고 프로그래밍이라 영어로 용어 섞어서 쓸거



1)  199,836개의 json 맵 파일들을 하나의 문자열string 으로 모두 합쳐서 보관하고 저장해둠 용량은 1.2~1.98gb정도 나온다 함. 이때 맵과 맵들은 \x1e 로 구분자를 둠 ","로 안하는건 이미 json내부에서 써서 못쓴다 함


2) 파일을 읽어들인 후 \x1e를 제외한 맵 데이터들을 압축알고리즘으로 줄이면 게임 맵이란게 반복되는 요소가 많아서 90% 이상의 압축률이 나온다고 함, 20만개의 맵파일이 \x1e로 구분이 되는 단일 70~80mb정도의 문자열 변수로 바뀜, 이걸 map 변수에 저장함


3) 게임이 맵을 이 문자열에서 불러오려고 한다고 해보자, 예를들어 x:100 y:100 번째 맵임. 그럼 모듈로 연산을 거꾸로 해서 (100*546)+100 번째 맵을 찾으면 됌, 즉 \x1e로 구분해놓은 맵 문자열에서 에서 인덱스로 56500번째 맵을 찾으면 되는거임


4) 그런데 매번 저 긴 문자열에서 \x1e로 56500번째 문자열의 집합들이 어디에 있는지 찾을순 없음, 매번 70mb짜리 텍스트를 이잡듯이 뒤지면 낭비가 심하니 어디를 봐야 파일을 찾는지 주소록 같은 "index lookup table"을 따로 만들어야 함


5) map_index 배열 변수를 만들고 366개의 비어있는 배열을 넣어서 세로줄을 구현함

그리고 각 배열마다 가로줄 546개의 맵 파일들이 문자열 몇번째 글자에서 몇번째 글자 인지를 저장함 "0,52" 이런식이면  map 문자열변수의 map[0:53] 이게 첫번째 맵파일의 문자열 형태를 나타내는 거임

이것들의 546개 또한 \x1e로 구분해서 하나의 문자열로 저장해둠

이렇게 했을때 200,100의 맵파일의 look up 인덱스주소를 찾는법은 map_index[100]를 불러와서 \x1e로 파싱 한다음 200-1번째 인덱스의 값을 가져와서 ,의 앞뒤값을 따서 index의 x,y값으로 쓰면 됌

이걸로 199,836개 맵파일의 인덱스를 546개의 문자열을 넣은 하나의 배열 변수에서 관리할수 있게 되서 가벼워짐


6) 이제 index x,y값을 가져다가 (편의상 ix iy라고 함)   map[ix:iy]를 호출하면 20만개의 맵에서 원하는 번호의 맵 파일의 압축된 문자열을 가져오게 됨, 이걸 가져다가 압축을 풀고 json을 key/value 테이블로 변환함


7) 가져온 변환이 완료된 맵 파일을 map_cache 테이블에 lifetime과 함께 넣어놓고 쓰다가 만료가 되면 다시 문자열로 바꾸고 압축한 다음에 위의 쓴 내용을 순서로 반대로 진행해서 다시 map 문자열에 쑤셔넣고 map_index를 갱신해준다


8) 이렇게 하면 2기가에 육박하고 199,836개의 개별 맵파일을 70메가 정도의 단일 문자열로 취급해서 램에 로드시켜놓고 쓸수있어서 청크로딩에 렉/딜레이가 전혀 발생하지 않고 디스크에 저장/불러오기 할때도 렉이 하나도 없다고 함

CPU/RAM이 문자열과 배열에선 효율이 높다는걸 이용해 램디스크처럼 쓰는 트릭임




####내용추가