CALL :NORMALIZEPATH "..\..\..\foo\bar.txt"
SET BLAH=%RETVAL%

ECHO "%BLAH%"

:: ========== FUNCTIONS ==========
EXIT /B

:NORMALIZEPATH
  SET RETVAL=%~dpfn1
  EXIT /B

출처 : https://stackoverflow.com/questions/1645843/resolve-absolute-path-from-relative-path-and-or-file-name

UE4 : BootstrapPackagedGame

해본 것/팁과 정보 2017.11.08 00:00 posted by 이밋

언리얼로 패키징하면 최상위 폴더에 게임 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 를 실행한다.

실행 중인 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

디버그 모드에서는 링크 문제가 없는데 릴리즈 모드에서 링크 에러가 발생했다. 해당 라이브러리를 쓰는 다른 프로젝트는 문제가 없어서 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

이펙트 파티클을 일정 기간 생성된 상태로 초기화하고 싶을 때 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개에 육박한 것을 볼 수 있었다. :(

언리얼에서 스크린샷이나 다른 이유로 랙이 걸릴 때 마다 다른 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 을 충분히 큰 값으로 올려주고 그 값을 넘어가는 오차가 발생하면 자르거나 재동기화하는 식으로 구현하는게 좋을 것 같다.

UE4 : 실행 파일명 변경

해본 것/팁과 정보 2017.07.19 00:00 posted by 이밋

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 라고 프로젝트 명을 지으면 패키징에서 오류가 발생한다. ;

TinyXML-2

해본 것/팁과 정보 2017.04.19 00:00 posted by 이밋
언리얼 기본 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/


Git : export

해본 것/팁과 정보 2017.02.25 00:00 posted by 이밋

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

윈도우 명령줄(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