Unity에서 JavaScript Plugin 만들기 #3 - JS Websocket 시행착오

FGPRJS·2022년 5월 17일
0

Unity JavaScript Plugin

목록 보기
4/4

현재 Unity 사양

Unity 2021.3.2f1


Native plugin 제거하기

Native Plugin이란?

Unity는 C, C++, Objective-C 등으로 작성할 수 있는 네이티브 코드의 라이브러리인 네이티브 플러그인을 지원합니다. 플러그인은 C#으로 작성한 코드가 이러한 라이브러리에서 함수를 호출하게 해줍니다. 이는 Unity를 미들웨어 라이브러리나 기존의 C/C++ 코드와 통합시키는 기능입니다.
(Native Code : .Net 기반하에서 사용자 마음대로 메모리를 조작할 수 있는 C, C++같은 언어.
Managed Code : CLR 하에 있는 언어. C#)

JavaScript 플러그인 (.jslib)을 포함한 Native Plugin은 상당히 민감하며, 불편하고 조심스럽게 다루어야 한다.
Native Plugin은 한번 설치되면 프로젝트에 계속 남아있으며, 단순히 프로젝트에서 삭제한다고 사라지지 않는다.

올바른 방법은 아니지만, 완전히 해소하는 방법으로는 다음 링크를 참조하여

  1. Unity를 종료
  2. Asset 폴더와 ProjectSetting 폴더를 제외한 모든 폴더를 삭제
  3. Plugin도 삭제
  4. 다시 Project를 로드하면 Unity측에서 남은 자료를 가지고 새롭게 필요한 파일들을 복구한다.

하는 방법이 있기는 하다.

다음 링크에서는 Native Plugin이 왜 다루기 까다로운지에 대해 설명하고 있다.

Plugins can be unloaded, but not safely.
Unloading a native library could cause a crash or memory corruption if any native code holds pointers to types or functions in that library.
플러그인은 Unload 할 수 있지만, 안전하지는 않다.
Native 라이브러리를 언로딩했을 때, Native 코드가 그 라이브러리의 함수나 타입들을 가리키고 있는 포인터를 가지고 있다면 Crash나 메모리 깨짐현상의 원인이 된다.

위 방법은 번거로우므로 Native Plugin은 조심해서 사용하도록 하자.


JavaScript Object 유지하기

기본 Unity 문서에서는 기재되지 않았지만, JavaScript의 Object를 유지해야 할 상황이 있다.
이전 문서에서 언급한 것과 같이, autoAddDeps함수를 사용하여 싱글톤한 객체를 유지할 수 있다.

보통 객체를 $ 표시를 사용한 식별자로 유지한다.

JavaScript에서 달러 기호는 일반적으로 변수 정의 및 함수 호출에 나타납니다. 달러 기호는 변수(또는 식별자) 이름일 뿐이므로 신비한 것은 없습니다.

Unity 커뮤니티에서 질의응답된 문서를 참고한 예제를 보아도 $표시가 있는 식별자를 사용함을 알 수 있다.

var LibraryMyPlugin = {
   $MyData: {
       myVar: 123,
   },
 
   Setvar: function (val) {
       MyData.myVar = val;
   },
   Getvar: function () {
       return MyData.myVar;
   },
};
 
autoAddDeps(LibraryMyPlugin, '$MyData');
mergeInto(LibraryManager.library, LibraryMyPlugin);

의존성을 갖는 개체들이 사용할 때에는 $ 표시를 뺀다.

위의 예시를 참고하면 알 수 있듯이, Object를 선언할 때는 $MyData로 선언하지만, 실제로 내부 함수가 사용할 때에는 $표시가 빠진다.

$ 표시를 빼버리면 오류가 난다.

그렇다고 그냥 $ 표시를 빼면 오류가 발생한다.

다음 링크에서 주석으로 아주 짧게 쓰여진 바로는

a communicator object inside the global object, the dollar sign must be before the name.
전역 Object 안에 있는 통신 Object는 앞에 $표시가 붙어야만 한다.

왜 그래야 하는지는 파악되지 않았다. 아마 Rule인듯.
JQuery등에서도 $가 많이 사용된다고 하니 이것과 비슷한 맥락으로 이해하고 넘어간다.


string에 UTF8ToString처리하기

다음과 같은 오류가 발생한다면, string에 UTF8ToString을 하지 않은 것이다.

위는 어떤 string값을 주며 Connect를 시도하였으나, 그 string의 값이 아닌 숫자만 나와있는 상황이다. 이는 UTF8의 어떤 값을 준것에 대한 pointer 주소를 string으로 받아서 출력해버린 것이므로, 다음과 같이 처리하여 오류를 제거하자.

 Connect: function(url){
        var newWebSocket = new WebSocket(UTF8ToString(url));
 //... 후략
 }

Runtime is not defined

사용하던 함수인 Runtime이 defined되지 않았다는 오류이다.

다음 링크에서는 현재 2021 버전의 유니티에는 Runtime이라는 Variable이 존재하지 않아서 다른 방식을 사용해야 한다고 기재되어 있다.

in unity 2021.2 variable Runtime doesn't exist and can be replaced with Module['dynCall_*'].
In webSocket.jslib change all Runtime.dynCall('1', 2, [3, 4]) for Module['dynCall_*1'](2, 3, *4)

Runtime.dynCall(
  'vi', 
  webSocketState.onOpen, 
  [ instanceId ]
);

위와 같은 코드를 다음과 같이 변경하여야 한다.

Module['dynCall_vi'](webSocketState.onOpen, instanceId);

jslib -> Unity로 데이터 전송하기

Unity에서 받은 데이터(함수 인자)는 UTF8ToString함수로 처리되지만, 반대는 안된다.

buffer를 만들고, 그것을 stringToUTF8로 처리해주는 과정이 필요하다.
(jslib에서 Unity로 string을 전송해봤자 UTF8 규격을 원하는 Unity는 아무것도 받아내지 못한다.)

다음과 같은 코드는 동작한다.

function(event) {
  var rawdata = event.data;

  var bufferSize = lengthBytesUTF8(rawdata) + 1;
  //Allocate memory space
  var buffer = _malloc(bufferSize);
  //Copy old data to the new one then return it
  stringToUTF8(rawdata, buffer, bufferSize);

  Module['dynCall_vi'](callback, buffer);
}	

malloc(Memory Allocation)은 C용 메모리 할당 함수로 JavaScript는 사용할 수 없는 함수이다.

emscripten에서 사용할 수 있게 해 주는 것.

하는 역할은 원래의 malloc과 동일하다. 힙 영역에 메모리를 할당해주고 그 주소를 리턴하는 것.

profile
FGPRJS

0개의 댓글