svn : shelve

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

svn 1.10 에 shelve 가 추가되었다.

shelve 는 WC 에 작업중인 코드가 있는데 특정 버그를 수정해야할 때 새로 체크아웃받지 않고 작업할 때 유용한 것 같다.

: 로컬에 작업중이던 코드를 shelve 를 통해 올려놓고 WC 를 rollback 한다.
: 버그를 수정한다.
: 수정된 코드를 커밋한다.
: unshelve 를 통해 작업중이던 코드를 다시 적용한다.

svn 1.11 에는 checkpoint 라는 기능이 작업 중인데 얘는 git 의 local commit 비슷한 동작을 지원하는 것 같다.

이제 파일 개수와 버전이 올라감에 따라 느려지는 속도만 Perforce 수준으로 빨라졌으면 한다.

출처 : https://cwiki.apache.org/confluence/display/SVN/Shelving+and+Checkpointing+Dev

Goodbye DPI

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

사이트 차단 때문에 말이 많았는데 vpn 도 있고 해서 실효성이 있나 모르겠다. 그 때 Goodbye DPI 라는 프로그램을 알게되었는데 사용하기도 편하고 무료라 PC 에서 사용하기에는 최고인 것 같다.

GoodbyeDPI 사이트에서 0.1.5 버전을 다운 받은 후 압축을 풀고 64비트 OS 의 경우 x86_64 폴더에 있는 goodbyedpi.exe 를 실행하기만 하면 된다.

다운로드 : https://github.com/ValdikSS/GoodbyeDPI/releases

참고 : https://www.clien.net/service/board/park/13153189

이번 기회에 성인 대상 야동 유통 합법화나 논의 되었으면 좋겠지만 기독 유교 탈레반 국가에서 논의가 시작될 수나 있을지 모르겠다.

C3859 계속 PCH에 대한 가상 메모리를 만들지 못했습니다.

가끔 프로젝트나 엔진 코드를 빌드하다 보면 C3859 오류가 발생할 때가 있다. -Zm146 옵션을 추가하라는 컴파일러 안내가 있었다. 하지만 언리얼은 VCToolChain 에서 /Zm850 이 기본으로 훨씬 많은 양을 추가하고 있는 상태였다.

코드에는 있지만 정말 /Zm850 옵션이 적용되는지 의심스러워서 확인해보았다. IncrediBuild 를 사용하고 있어서 엔진 설치 경로에서 Intermediate/Build/XGETasks.xml 을 확인했다.

Tools > Tool Element 에 Params 로 실제 cl 에 넘어가는 파일 경로를 확인할 수 있다. '파일명.cpp.obj.response' 형식이다. 파일을 열어서 확인해 보니 /Zm850 옵션이 적용되어 있었다.

혹시 실패가 특정 PC 에서 발생하고 있는지 확인해보니 특정 PC 에서 발생하고 있었다. IncrediBuild Coordinator 로 column 에 Environment > Virtual Memory 를 확인해보니 Avail 용량이 800MB 정도 밖에 안되는 PC 였다. 실제 가상 메모리가 부족한 상황이었다. -ㅁ-

몇 일간 빌드 옵션 문제 인가 싶어서 옵션을 바꿔가며 삽질했는데 현실은 환경 문제였다. :(

변수가 특정 문자열을 포함하고 있는지에 따라 분기처리를 해야할 경우가 있다. find 나 findstr 의 errorlevel 을 이용해서 처리하면 된다.

set TestStr=imit@imitursa

echo %TestStr% | find "@imitursa" >nul

if errorlevel 1 (echo notfound) else (echo found)


출처 : https://stackoverflow.com/questions/34077831/how-to-see-if-a-string-contains-a-substring-using-batch/34077870#34077870

OnlineSystemNull 을 데디 서버에서 사용하는 경우 OnlineAsyncTaskThreadNull 이 돌고 있는데 코드에서 사용하는 곳이 없었다. 엔진 코드를 뜯어 고쳐서 Thread 가 생성되지 않게 할 수도 있지만 설정만으로 cpu 를 덜 사용하게 할 수는 있다.

// FOnlineAsyncTaskManager::Run

do 
{
// Wait for a trigger event to start work
WorkEvent->Wait(PollingInterval);
if (!bRequestingExit)
{
Tick();
}
}

OnlineAsyncTaskThreadNull 은 PollingInterval 마다 sleep 하는 구조다. PollingInterval 의 기본값은 50ms 인데 -1(INFINITI) 값을 주면 Queue 에 작업을 줄 때 까지 Sleep 시킬 수 있다.

// FOnlineAsyncTaskManager::Init

if (GConfig->GetInt(TEXT("OnlineSubsystem"), TEXT("PollingIntervalInMs"), PollingConfig, GEngineIni))
{
PollingInterval = (uint32)PollingConfig;
}

초기화 코드를 보면 Engine.ini 에서 설정 가능하다.

[OnlineSubsystem]
PollingIntervalMs=-1

위와 같은 섹션을 추가 혹은 수정하면 된다. PollingIntervalMs 는 int 로 읽어서 unsigned int 로 변환된다.

bash : if

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

학교 졸업하고는 linux 를 써본 적이 없으니 얼마만에 써보는 지 모르겠다. if 문에서 계속 오류가 발생해서 뭔가 싶었는데 공백 문제였다. 

if [ conditions ]

if 다음에 공백 있고 '[', ']' 와 조건 사이에도 공백이 반드시 있어야 하네 -ㅁ-

출처 : https://stackoverflow.com/questions/16034749/if-elif-else-statement-issues-in-bash

UE4 에서 RPC가 구현된 class 는 Actor 와 ActorComponent 로 보입니다. Actor 의 멤버로 UObject 를 상속받은 class 는 RPC 함수들이 있어도 동작하지 않습니다. 

UObject 를 상속받은 클래스에는 IsSupportedForNetworking, IsNameStableForNetworking, CallRemoteFunction, GetFunctionCallspace 구현이 필요합니다.

cf. Outer class 가 APlayerController 라고 가정합니다. 통신이 가능한 Actor 면 상관없습니다.

class UMyObject : public UObject
{

virtual bool IsSupportedForNetworking() const override
{
return true;
}

virtual bool IsNameStableForNetworking() const override
{
return true;
}

virtual bool CallRemoteFunction(UFunction* Function, void* Parameters, FOutParmRec* OutParms, FFrame* Stack) override
{

if (auto MyOwner = GetOuterAPlayerController())
{
UNetDriver* NetDriver = MyOwner->GetNetDriver();
if (NetDriver)
{
NetDriver->ProcessRemoteFunction(MyOwner, Function, Parameters, OutParms, Stack, this);
return true;
}
}
return false;
}

virtual int32 GetFunctionCallspace(UFunction* Function, void* Parameters, FFrame* Stack) override
{
auto MyOwner = GetOuterAPlayerController();
return (MyOwner ? MyOwner->GetFunctionCallspace(Function, Parameters, Stack) : FunctionCallspace::Local);
}

} // UMyObject

추가로 Actor 의 Subobject 는 1단계만 허용되는 것 같습니다.

참고 : https://answers.unrealengine.com/questions/435733/rpc-doesnt-work-on-repicated-uobject.html


git 을 오랜만에 사용하는데 아래와 같은 오류 메시지가 발생했다.

remote: HTTP Basic: Access denied
fatal: Authentication failed for 'https://gitlab.com/myname/myproject'

전에 git 명령어로 설정한 데이터가 있는데 문제를 일으키는 상황같아 보였다. TortoiseGit 에서 Authentication data 를 Clear 해서는 초기화되지 않았다.

인증 관련 데이터를 초기화하기 위해서는 아래와 같이 처리하면 된다.

  • 관리자 권한으로 명령창을 연다.
  • 'git config --system --unset credential.helper' 를 실행한다.
  • global 영역 설정이 문제를 일으킬 수 있으니 'git config --global --unset credential.helper' 를 실행한다. 

출처 : https://stackoverflow.com/questions/47860772/gitlab-remote-http-basic-access-denied-and-fatal-authentication

소프트웨어 kvm 인 Input Director 를 사용하고 있는데 윈도우즈 10 설치 후 slave pc 가 로그인 전에 인식이 안되는 문제가 있었다. 빠른 부팅 모드가 문제를 일으키나 보다.

참고 : https://groups.google.com/forum/#!msg/input-director/Vazvfi1hryg/fYSWqJWVFAAJ

  • '제어판 > 하드웨어 및 소리 > 전원 옵션'에서 '전원 단추 작동 설정' 을 클릭
  • '현재 사용할 수 없는 설정 변경' 클릭
  • '빠른 시작 켜기' 를 체크 해제하니 잘 동작했다.
출처 : https://www.howtogeek.com/243901/the-pros-and-cons-of-windows-10s-fast-startup-mode/


언리얼 기본 옵션은 1파일로 데이터와 설정 파일이 패킹된다. 프로젝트가 커지면 수십 GB가 되기도 한다. 원활한 패치/배포를 위해 파일을 적당히 분리할 필요가 있다.

UE4는 Chunk 를 이용해 패킹 데이터를 분리할 수 있다. 특정 폴더만 분리하고 싶다면 먼저 특정 폴더에 PrimaryAssetLabel 클래스의 데이터 애셋을 생성한다.

애셋 이름은 다른 PrimaryAssetLabel 애셋과 겹치지 않아야 한다.

Chunk ID 를 겹치지 않게 1 이상의 값으로 설정하고 Label Assets in My Directory를 체크한다. Label Assets in My Directory 를 체크하면 애셋이 위치한 폴더 아래 폴더까지 한 Chunk 로 묶인다. 특정 애셋이나 특정 블루프린트 기준으로 묶을 수도 있다.

그리고 패키지 세팅에서 Packaging > Generate Chunks 를 체크한다.

패키징을 하면 해당 폴더의 데이터가 chunk0 pak 파일로 분리된 것을 확인할 수 있다. 설정하지 않은 나머지 파일은 0 파일로 패킹된다.

현재 프로젝트의 chunk 설정을 확인하고 싶으면 개발자 툴 > 애셋 검토 창을 이용하면 된다.

프라이머리 애셋 타입 추가 버튼을 누르면 목록이 아래에 나타난다.

Chunk 는 쿠킹 전에는 보이지 않는다. Windows 용 콘텐츠 쿠킹을 하거나 실제 패키징을 하면 청크 추가 버튼을 눌러 Chunk 목록을 대략적으로 확인할 수 있다. 

만약 갱신되지 않으면 에디터를 재시작하면 제대로 보이기도 한다. 

엔진 : 4.20.3

참고 : http://api.unrealengine.com/KOR/Engine/Basics/AssetsAndPackages/AssetManagement/CookingAndChunking/index.html