언리얼로 패키징하면 최상위 폴더에 게임 exe 파일을 실행해주는 exe 파일이 생성된다. 확인해보니 패키징 과정 중 WinPlatform.Automain.cs 에 있는 StageBootstrapExecutable 에 의해 생성되고 있었다. 

다음과 같은 과정을 거쳐 생성된다.

: Engine/Binaries/[Platform]/BootstrapPackagedGame-[Platform]-Shipping.exe 파일을 타겟 경로에 복사
: Build/Windows/Application.ico 파일을 101 리소스 갱신
: 201 리소스 아이디로 실행할 게임 exe 파일 상대 경로 문자열 갱신
: 301 리소스 아이디로 실행할 게임 기본 파라미터 문자열 갱신

BootstrapPackagedGame 은 2가지 기능은 한다.

: MSVCP140.DLL 과 XINPUT1_3.DLL 을 체크하여 Microsoft Visual C++ 2015 Runtime 이나 DirectX Runtime 이 설치되었는지 확인한다.
: 설치되어 있지 않다면 배포 버전에 포함된 UE4PrereqSetup_x64.exe 를 실행한다.
: 필요한 패키지들이 설치되어 있다면 리소스 경로를 참고하여 게임 exe 를 실행한다.

728x90

실행 중인 OS가 64 비트인지 확인하기 위해서는 IsWow64Process 를 이용하면 된다. 지원하지 않는 OS 도 있으니 GetProcAddress 를 이용해야한다. 64 비트 프로그램의 경우에는 그냥 TRUE 를 return 하면 된다.

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64()
{
#ifdef _WIN64
    return TRUE;
#else
    BOOL bIsWow64 = FALSE;

    //IsWow64Process is not available on all supported versions of Windows.
    //Use GetModuleHandle to get a handle to the DLL that contains the function
    //and GetProcAddress to get a pointer to the function if available.

    fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
    if (NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
        {
            //handle error
        }
    }
    return bIsWow64;
#endif
}

참고 : https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms684139(v=vs.85).aspx

728x90

디버그 모드에서는 링크 문제가 없는데 릴리즈 모드에서 링크 에러가 발생했다. 해당 라이브러리를 쓰는 다른 프로젝트는 문제가 없어서 lib 경로 문제인가 싶어서 이리저리 확인해 봤으나 원인을 찾을 수가 없었다. lib 에 정말 symbol 이 있는지 확인해 보고 싶어졌다. 

Visual Studio 에 포함된 dumpbin 을 이용하면 된다.

dumpbin /symbols [lib 파일명]

Visual Studio 에 포함된 libcmt.lib 를 까보면 이런 식으로 보인다.

dumpbin /symbols libcmt.lib


File Type: LIBRARY


COFF SYMBOL TABLE000 00C7A09E ABS    notype       Static       | @comp.id
001 00000011 ABS    notype       Static       | @feat.00
002 00000000 UNDEF  notype       External     | _strcat003 00000000 UNDEF  notype       WeakExternal | __mbscat

    Default index        2 Alias record

String Table Size = 0x0 bytes

COFF SYMBOL TABLE
000 00C7A09E ABS    notype       Static       | @comp.id
001 00000011 ABS    notype       Static       | @feat.00
002 00000000 UNDEF  notype       External     | _strcpy
003 00000000 UNDEF  notype       WeakExternal | __mbscpy

    Default index        2 Alias record

String Table Size = 0x0 bytes

COFF SYMBOL TABLE
000 00C7A09E ABS    notype       Static       | @comp.id
001 00000011 ABS    notype       Static       | @feat.00

...(생략)

0A4 00000000 SECT33 notype       External     | ??_C@_01EEMJAFIK@?6?$AA@ (`string')
0A5 00000000 SECT34 notype       Static       | .rdata    Section length    3, #relocs    0, #linenums    0, checksum BB71EC38, selection    2 (pick any)

0A7 00000000 SECT34 notype       External     | ??_C@_02LLMPMKNF@?$DO?5?$AA@ (`string')

0A8 00000000 SECT35 notype       Static       | .rdata

    Section length    9, #relocs    0, #linenums    0, checksum F5F13728, selection    2 (pick any)

0AA 00000000 SECT35 notype       External     | ??_C@_08OMAHNMHJ@?6Data?3?5?$DM?$AA@ (`string')

0AB 00000000 SECT36 notype       Static       | .rdata
    Section length   2A, #relocs    0, #linenums    0, checksum 21F15550, selection    2 (pick any)

0AD 00000000 SECT36 notype       External     | ??_C@_0CK@DKGBICFE@?6Allocation?5number?5within?5this?5f@ (`string')

0AE 00000000 SECT37 notype       Static       | .rdata

    Section length    8, #relocs    0, #linenums    0, checksum AFE40ACB, selection    2 (pick any)

0B0 00000000 SECT37 notype       External     | ??_C@_07DFDJCKFN@?6Size?3?5?$AA@ (`string')
0B1 00000000 SECT38 notype       Static       | .rdata

    Section length    D, #relocs    0, #linenums    0, checksum 37DE352B, selection    2 (pick any)
0B3 00000000 SECT38 notype       External     | ??_C@_0N@MHFFIMFG@?6Address?3?50x?$AA@ (`string')

0B4 00000000 SECT39 notype       Static       | .rdata
    Section length   48, #relocs    0, #linenums    0, checksum DB7219C5, selection    2 (pick any)

0B6 00000000 SECT39 notype       External     | ??_C@_0EI@CLEPFNGI@Stack?5area?5around?5_alloca?5memory@ (`string')
0B7 00000000 SECT3A notype       Static       | .rdata

    Section length   1A, #relocs    0, #linenums    0, checksum B3C0476C, selection    2 (pick any)
0B9 00000000 SECT3A notype       External     | ??_C@_0BK@ODNDAGKB@?$CFs?$CFs?$CFp?$CFs?$CFzd?$CFs?$CFd?$CFs?$CFs?$CFs?$CFs?$CFs?$AA@ (`string')

0BA 00000000 SECT3B notype       Static       | .rdata
    Section length   34, #relocs    0, #linenums    0, checksum D4450C50, selection    2 (pick any)
0BC 00000000 SECT3B notype       External     | ??_C@_0DE@OHJBPMBP@A?5variable?5is?5being?5used?5without@ (`string')

0BD 00000000 UNDEF  notype       External     | ___security_cookie
0BE 00000000 SECT3C notype       Static       | .sxdata


...(생략)


  Summary


           4 .00cfg
           4 .CRT$XCA
          10 .CRT$XCAA
           4 .CRT$XCZ
           4 .CRT$XDA
           4 .CRT$XDZ
           4 .CRT$XIA
          10 .CRT$XIAA
          10 .CRT$XIAC
           8 .CRT$XIC
           4 .CRT$XIZ
           4 .CRT$XLA
           4 .CRT$XLC
           4 .CRT$XLD
           4 .CRT$XLZ
           4 .CRT$XPA
           4 .CRT$XPZ
           4 .CRT$XTA
           4 .CRT$XTZ
         3A9 .bss
          38 .data
          77 .data$r
         1D0 .debug$F
       A7880 .debug$S
        3454 .debug$T
         5BF .drectve
          AC .gfids$y
        742E .rdata
          18 .rdata$T
         120 .rdata$r
           4 .rtc$IAA
           4 .rtc$IZZ
           4 .rtc$TAA
           4 .rtc$TZZ
          3C .sxdata
       1B0E8 .text$mn
           F .text$mn$00
          1B .text$x
           1 .tls
          8C .tls$
           1 .tls$ZZZ
         2E0 .xdata$x
       6C630 _RDATA


0BC 00000000 SECT3B notype       External     | ??_C@_0DE@OHJBPMBP@A?5variable?5is?5being?5used?5without@ (`string')

위와 같이 External 이 표기된 부분을 디버그와 릴리즈 모드를 비교해봤더니 릴리즈 모드에서 링크에러가 발생한 symbol을 찾을 수 없었다.

문제가 생긴 함수는 constructor 였는데 명시적으로 구현을 안해서 그런건지 릴리즈에서만 링크 에러가 발생한 것이었다. 다행히 명시적으로 cpp 파일에 구현해주니 링크 에러는 해결되었다.

참고 : https://stackoverflow.com/questions/305287/how-to-see-the-contents-of-windows-library-lib

728x90

이펙트 파티클을 일정 기간 생성된 상태로 초기화하고 싶을 때 Warmup Time 을 설정하게 된다.

UParticleSystemComponent::ActivateSystem 코드를 보면 어떻게 동작하는지 알 수 있는데  WarmupTime을 WarmupTickRate 나눈 수만큼 TickComponent 를 호출하는 식이다.

if (WarmupTime != 0.0f)
{
bool bSaveSkipUpdate = bSkipUpdateDynamicDataDuringTick;
bSkipUpdateDynamicDataDuringTick = true;
bWarmingUp = true;
ResetBurstLists();


float WarmupElapsed = 0.f;
float WarmupTimestep = 0.032f;

if (WarmupTickRate > 0)
{
WarmupTimestep = (WarmupTickRate <= WarmupTime) ? WarmupTickRate : WarmupTime;
}

while (WarmupElapsed < WarmupTime)
{
TickComponent(WarmupTimestep, LEVELTICK_All, NULL);
WarmupElapsed += WarmupTimestep;
}

bWarmingUp = false;
WarmupTime = 0.0f;
}

예를 들어 WarmupTime 을 100 WarmupTickRate 를 0 으로 설정한 경우 100 / 0.032(WarmupTickRate 기본값) = 3125 Tick 을 돌아서 이 이펙트가 스폰될 때 마다 i7 + Nvidia 970 + 32GB Mem 정도 사양에서도 버벅이는 것을 느낄 수 있다. 초당 0.7 정도의 8개 짜리 스프라이트 이펙트였는데 스프라이트 파티클 개수가 10000개에 육박한 것을 볼 수 있었다. :(

728x90

언리얼에서 스크린샷이나 다른 이유로 랙이 걸릴 때 마다 다른 PC 에 비해 World::TimeSeconds 가 느리게 가는 현상이 발견되었다.

확인해보니 AWorldSettings::FixupDeltaSeconds 에 의해 제한되고 있었다.

float AWorldSettings::FixupDeltaSeconds(float DeltaSeconds, float RealDeltaSeconds)

{

// DeltaSeconds is assumed to be fully dilated at this time, so we will dilate the clamp range as well

float const Dilation = GetEffectiveTimeDilation();

float const MinFrameTime = MinUndilatedFrameTime * Dilation;

float const MaxFrameTime = MaxUndilatedFrameTime * Dilation;


// clamp frame time according to desired limits

return FMath::Clamp(DeltaSeconds, MinFrameTime, MaxFrameTime);

}

WorldSettings 의 MinUndilatedFrameTime 과 MaxUndilatedFrameTime 에 설정할 수 있었다.


기본 값은 BaseGame.ini 에 설정되어 있다.

[/Script/Engine.WorldSettings]

MinUndilatedFrameTime=0.0005 ; 2000 fps

MaxUndilatedFrameTime=0.4 ; 2.5 fps

0.4초 이상은 버려지니 스크린샷으로 2~3초가 지났어도 World 는 0.4초 밖에 안 지난 것으로 취급되는 상황이었다.

P2P 마스터를 지원하는 상황에서는 DefaultGame.ini 에 MaxUndilatedFrameTime 을 충분히 큰 값으로 올려주고 그 값을 넘어가는 오차가 발생하면 자르거나 재동기화하는 식으로 구현하는게 좋을 것 같다.

728x90

UE4 에서 C++ Project 를 만들면 프로젝트 이름으로 실행파일명이 생성된다.

uproject 이름 변경하는 법

http://www.worldofleveldesign.com/categories/ue4/ue4-renaming-your-project.php

1. uproject 파일명을 바꾼다.
2. Config/DefaultEngine.ini 에 아래 섹션을 추가/수정한다.

[URL]
GameName=NewName

패키징을 해보니 GameName은 바뀌었으나 실행 파일명은 바뀌지 않았다.
그리고 에디터에서 컴파일하면 오류도 발생하고 svn commit 시에 ensure도 발생했다.

https://answers.unrealengine.com/questions/242407/renaming-a-c-project.html

제대로 바꾸려면 Target.cs, Build.cs 도 바꿔주고 Config 에서 추가 작업도 필요한 것 같다.

회사분이 에디터 컴파일 오류 수정하시다가 Rename.Target.cs 을 NameName.Target.cs 로 이름을 변경하셨다. 그런데 exe 이름도 같이 변경되었다. 실행 파일명은 메인 모듈의 TargetName 을 따라가도록 되어 있나 보다.

P.S. Test 라고 프로젝트 명을 지으면 패키징에서 오류가 발생한다. ;

728x90
언리얼 기본 XML Parser 가 제한 사항이 많아 불편했다.

: attribute 에 "(double quote)를 쓸 수 없다.
: attribute 선언 시에 공백을 쓸 수 없다.
: root element가 value와 child가 없는 element 일 수 없다.


기존에 사용 중인 xml 파일을 그대로 사용하려다 보니 파일마다 고치기 힘들어 다른 XMl Parser 를 가져다 붙였다. 전에는 MS XML Parser 를 썼었는데 언리얼에 붙이기에는 Platform 의존도가 너무 높아지는 것 같아서 TinyXML-2 를 가져다 붙였다.

TinyXML-1 이 메모리 사용이 비효율적이고 모바일 환경에 맞지 않는 것 같아서 TinyXML-2 를 만들었다고 한다.

TinyXML-1 과 TinyXML-2 장단점을 비교한 것도 있다.

Both parsers:

  1. Simple to use with similar APIs.
  2. DOM based parser.
  3. UTF-8 Unicode support. http://en.wikipedia.org/wiki/UTF-8

Advantages of TinyXML-2

  1. The focus of all future dev.
  2. Many fewer memory allocation (1/10th to 1/100th), uses less memory (about 40% of TinyXML-1), and faster (~5x on read).
  3. No STL requirement.
  4. More modern C++, including a proper namespace.
  5. Proper and useful handling of whitespace

Advantages of TinyXML-1

  1. Can report the location of parsing errors.
  2. Support for some C++ STL conventions: streams and strings
  3. Very mature and well debugged code base.

ReleaseDll 정적 라이브러리를 만들어서 언리얼에 붙였다.

붙이고 테스트 해보니 몇 가지 문제점이 있었다.

: utf-8 을 지원한다고는 하지만 LoadFile 은 fopen 을 사용하고 있는 관계로 ANSI 문자열만 지원한다. . 파일명이 다른 국가 문자열을 포함한다면 읽어들일 수 없었다.
: utf-16 을 지원하지 않는다.

그래서 다음과 같은 방식으로 wrap 해서 사용하고 있다.

: 언리얼은 다국어를 지원하는 관계로 FileHelper::LoadFileToString 을 이용하여 다국어 파일명의 파일을 읽어들인다.
: TinyXML2 로 보내기 위해 utf-8 으로 문자열을 변환한다.
: XmlDocument::Parse 를 통해 파싱 후 각 element 의 문자열 데이터를 UTF8_TO_TCHAR 를 이용하여 변환해서 사용한다.

공식 홈페이지 : http://www.grinninglizard.com/tinyxml2/


728x90

Git 저장소를 export 해서 전달해야할 때는 git archive 를 사용하면 된다.


현재 브랜치의 가장 최신 내용을 export 하는 경우


git archive --format=tar --prefix=junk/ HEAD



zip 으로 remote 브랜치를 export 하는 경우


git archive --format=zip branch.zip remotes/origin/branch





참고 : https://git-scm.com/docs/git-archive

728x90

윈도우 명령줄(cmd.exe) 에서 for 루프 내에서 문자열을 set 으로 붙이려고 했으나 동작하지 않고 %XX% 가 미리 처리되어 마지막 set 만 처리되었다.

 

[코드]

 

for /f %%a ('dir /a /b') do set XX=%XX% %%a 

 

[실제 동작]

 

for /f %%a ('dir /a /b') do set XX= %%a

 

검색해보니 Delayed Expansion 을 enable 해서 처리하거나 goto 문을 이용하는 방법이 있었다. Delayed Expansion 을 enable 하는 것이 더 깔끔한 것 같다.

 

@echo off
setlocal enabledelayedexpansion
set myvar=the list:
for /r %%i In (*.sql) DO set myvar=!myvar! %%i,
echo %myvar%

 

출처 : http://stackoverflow.com/questions/2027070/how-to-concatenate-strings-in-a-windows-batch-file

728x90

UE4 로 작업할 때 IncrediBuild 가 설치되어 있어도 쓰고 싶지 않은 경우가 있다. IncrediBuild agent 를 disable 하면 서버 접속할 수 없다는 오류가 뜬다. 


다음과 같이 BuildConfiguration.xml 을 설정하면 된다.

경로는 %appData%\Unreal Engine\UnrealBuildTool\BuildConfiguration.xml 이 최우선인 것 같다.


<?xml version="1.0" encoding="utf-8" ?><Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">

<BuildConfiguration>

<bAllowXGE>false</bAllowXGE>

</BuildConfiguration>

</Configuration>



출처 : https://answers.unrealengine.com/questions/488246/how-to-disable-incredibuild.html

728x90

+ Recent posts