BLOG ARTICLE MOD | 2 ARTICLE FOUND

  1. 2010.06.01 2010년 5월 10일 - 2010년 5월 31일 = ?
  2. 2007.08.02 R1Q2의 D-Day Normandy MOD 실행 문제 (2)

  • Garrys Mod 내부에서 이제 Lua의 비율은 어지간한 수준 이상으로 올라갔다. 단순히 랙돌 가지고 놀기서부터 Youtube 끌어와 게임 내에서 띄워 다른 사람과 보기. 아예 다른 게임을 만들기 까지… 하긴 Garrys Mod 자체가 매우 큰 샌드박스긴 하니…(개리모드 Garrys Mod 루아 Lua 근데 난 루아는 모른다 그냥 툴건만 씀) 2010-05-31 19:55:28
  • 우리는 인터넷 친구들 : 한국내의 희귀하고 해괴한 앨범들을 모으고 공유하는 블로그. 6월에 서울 갈때 권용만씨 찾아가서 문화사기단 앨범 몇개하고 제주도 내 인디밴드 데모앨범 몇개를 가져가서 올려볼 예정. 가지고 있어봤자 너무 아까운 앨범이 좀 있어서 말이죠…(우리는 인터넷 친구들 희귀하거나 해괴하거나 음악 인디) 2010-05-31 19:58:25

이 글은 PSG-01님의 2010년 5월 31일의 미투데이 내용입니다.

YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST


 
D-Day Normandy In R1Q2

D-Day Normandy In R1Q2



 R1Q2라는 R1CH (http://www.r1ch.net) 씨가 만든 퀘이크 2 클라이언트가 있다.

 퀘이크 2 클라이언트임에도 불구하고 zlib 라이브러리와 다이렉트 인풋, 사운드를 쓰는 프로그램인데 기존 퀘이크 2 클라이언트 보다 세부적으로 조정할수 있는 옵션도 많고 로딩 속도 또한 살인적으로 빠른 클라이언트라 D-Day Normandy를 즐기는 분들 중에서도 이 클라이언트를 쓰는 분이 많은데, 유독 KDDAY와 다른 D-Day Normandy가 맵 몇개만 실행하면 서버가 터지는 (Crashing) 그런 상황이 발생한다는 예기가 있었다.

 그래서 고쳐보자 한게 2007년 1월인데... 그때는 Z_FreeTagsGame에서 메모리 할당이 잘못돼 깨진다는거 말고는 별로 알고 있는게 없어서 원인도 제대로 못 알아본 채 포기 했었다.

 그리고 오늘 생각 난 김에 다시 이 문제를 잡아보고 삽을 프기 시작했다. 우선 어떤 조건에서 에러가 나는지 먼저 알아보니


 - 맵이 바뀔때, 특히 국가가 바뀌고 난 뒤에 맵을 몇번 바꾸면 Z_FreeTagsGame 에러가 난다.

 - 그리고 또 유달리, R1Q2에서만 이런 에러가 난다.

 
 (부연설명 : D-Day Normandy의 MOD 라이브러리 구조는 메인 게임 라이브러리 밑에 국가별 정보가 들어있는 라이브러리 파일들이 있는 시스템이다. 그러므로 메인 게임 라이브러리는 항상 상주해 있는 반면에 하위 라이브러리는 맵이 어떤 맵으로 바뀌냐에 따라 유동적으로 갈아끼워지는 시스템이다)

  이거 두개였다. 일단 처음에는 메인 게임 소스 (gamex86.dll) 을 디버깅 해보기로 했다. 역시 이부분이 문제였다.

 void ShutdownGame (void)
{
    gi.dprintf ("==== ShutdownGame ====\n");

    CleanUpCmds();
    ClearUserDLLs();

    gi.FreeTags (TAG_LEVEL); //  TAG_LEVEL의 경우에는 새로운 레벨 (맵) 을 로딩할때 클리어를 해주는 상수
    gi.FreeTags (TAG_GAME); // TAG_GAME의 경우에는 하위 라이브러리를 언로딩할때 클리어 해주는 함수라고 적혀 있었다.
}

 이 두개는 메인 라이브러리가 맵 한판이 끝났을때 하위 라이브러리와 맵의 관련된 엔티티쪽의 메모리를 해방시키는 역활을 하는 코드다. 이 곳에서 에러가 검출되었는데 gi의 경우에는 클라이언트에서 받아오는 정보인것 같은지라 일단 클라이언트의 소스를 찾아보는게 좋다해서 R1Q2와 icculus에서 만들었던 기존 퀘이크 2 클라이언트의 소스를 비교해 보기로 했다. 참고로 icculus에서 만든 클라이언트에서는 Z_FreeTagsGame 문제는 없었다.      

 우선 FreeTags가 각각 어떤 명령을 하는지 부터 알아보니 이클루스의 경우에는
 
    import.FreeTags = Z_FreeTags; 
 
 그리고 R1Q2의 경우에는

     import.FreeTags = Z_FreeTagsGame;

 이라 하여 문제의 에러가 나는 그 함수 부분이였다.

 Z_FreeTagsGame의 경우에는 소스코드가 다음과 같다.


void EXPORT Z_FreeTagsGame (int tag)
{
    zhead_t    *z, *next;

    z_memloc_t    *loc, *last;

    loc = last = &z_game_locations;

    while (loc->next)
    {
        loc = loc->next;

        if (*(int *)((byte *)loc->address + loc->size) != 0xFDFEFDFE)
        {
            Com_Printf ("Memory corruption detected within the Game DLL. Please contact the mod author and inform them that they are not managing dynamically allocated memory correctly.\n", LOG_GENERAL);
            Com_Error (ERR_DIE, "Z_FreeTagsGame: Game DLL corrupted a memory block of size %d at %p (allocated %u ms ago from code at %p)", loc->size, loc->address, curtime - loc->time, loc->allocationLocation);
        }
    }

    for (z=z_chain.next ; z != &z_chain ; z=next)
    {
        next = z->next;
        if (z->tag == tag)
            Z_FreeGame ((void *)(z+1));
    }

    Z_Verify (va("Z_FreeTags %d (GAME): END", tag));
}

 소스의 상태나 기존 Z_FreeTags가 남아서 여전히 쓰이고 있는걸로 봐서는 아무래도 기존 퀘이크2에만 최적화를 맞추다보니 상하부 라이브러리 구조로 이루어진 MOD에 대한 배려가 없는 메모리 할당때문에 벌어진 문제라고 생각을 했다. 참고로 Z_FreeTags의 경우에는 소스는 다음과 같다.

void Z_FreeTags (int tag)
{
    zhead_t    *z, *next;

    Z_Verify ("Z_FreeTags: START");

    for (z=z_chain.next ; z != &z_chain ; z=next)
    {
        next = z->next;
        if (z->tag == tag)
            Z_Free ((void *)(z+1));
    }

    Z_Verify ("Z_FreeTags: END");
}
 

 해결은 생각외로 간단하게 됐다. 앞서 말했던 FreeTags를 임포팅 해주는 함수를 Z_FreeTagsGame에서 기존 Z_FreeTags 로 바꿔주니 쉽게 문제가 해결되었다. 아무래도 Z_FreeTagsGame 에서 memloc을 할당해 주는데에서 뭔가 비밀이 있는것 같은데 이거는 나중에 struct까지 뜯어보고 알아보는게 좋겠다고 생각을 한다.

 다만 아직 남은 문제가 있는데

 - 비 효율적인 메모리 할당

 - DLL을 전부 언로딩 했다가 다시 맞춰서 불러오는 기존 맵 시스템을 R1Q2에서 쓸 경우 엄청난 양의 메모리 누수가 발생한다. (이 문제의 경우에는 gamemap 이라는 명령어를 이용하면 깔끔하게 해결된다.)

 - 게으른 R1CH가 이 문제를 전혀 손 댈려고 하지 않고 그저 sv_buggygame 함수를 써서 막아라 라고 하는 말만 하고 있다. -_-;



여담 :

 1. 전 처음에 저 문제가 DLL 내부의 메모리 셋팅 잘못인줄 알고 엄청나게 내부 소스만 헤집고 다녔습니다 -_-;
 
 2. R1Q2 컴파일 할때의 불친절한 R1CH 덕분에 별 이상한곳에서 삽질을 다했네요. 링커에 함수가 안 붙고, 라이브러리 찾아 다니고. 별 고생을 다해서 컴파일에 성공한걸로 기억합니다. (...)

 3. ...하여튼 퀘이크 2의 세계는 크고 넓고 광활하다. 앞으로 더 파볼 생각은 충분히 있음.

YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST
  1. BlogIcon nidev 2007.08.02 12:37  댓글주소  수정/삭제  댓글쓰기

    짱이네염;

    • BlogIcon PSG-01 2007.08.02 18:45 신고  댓글주소  수정/삭제

      사실 삽질 히스토리를 쭉 적어놔서 장황해 보인거지 실제 결과물은 글자 4개 지우고 컴파일 한겁니다. 그러니 급한대로 되긴 하더군요 -_-