[UE4]Unreal.jsでJSのコードに型とフラグ情報を付与する

[Unreal.jsプラグイン](http://qiita.com/ConquestArrow/items/bb81ad5e63cf6bc4e549)でJavaScriptで作成したものをUE4の世界に認識させるには次の方法が必要になる。

 1. ES2015(ES6)の書き方でクラスを生成
 2. クラス・メソッド・プロパティに **型とフラグの情報を付与**
 3. `uclass.js`で型とフラグ情報を解析させてUE4側にクラスを認識させる

この「型とフラグの情報を付与」という部分が若干特殊なので説明。

# Unreal.jsでの型およびフラグ情報の独自表現

周知の通り、JavaScriptには型表現の方法が基本的にない。一方UE4のUnreal C++ & Blueprintには型がある。Unreal.jsではこの差を埋めるために、コメント中に埋め込まれた型とフラグ情報を解析した上でUE4側に渡す形になっている。

また、Unreal C++独自のマクロ（`UPROPERTY`など）での識別子指定もフラグ情報等として表現できる（ ~~メタデータ識別子~~ メタプロパティも一部対応しているようだ）。

以下が、それぞれのUnreal C++マクロに対応するJS側での書き方。

## UCLASS

```cpp:unreal_c++
UCLASS([specifier, specifier, ...], [meta(key=value, key=value, ...)])
class ClassName : public ParentName
{
    GENERATED_BODY()
}
```

```js
class ClassName /* ClassFlag+ClassFlag+... */ extends ParentClass {
   ctor() {
     // initialization
     // component setup
   }
   properties() {
     // property-declarations
   }
}
```

`class クラス名 /* フラグ情報1+フラグ情報2+... */ {}`の形で定義する。

注意点：

- ES5以前の疑似クラス定義には非対応
    - 文字列解析で処理されているため
- コンストラクタは`ctor()`
    - ES2015の`constructor()`はJS側のコンストラクタ、`ctor()`はUE4側のコンストラクタとして働く
- プロパティ(UPROPERTY)は`properties()`で定義
- `UClass`として扱うには最後にuclass.jsで解析する必要がある

```js
//transformed into corresponding USTRUCT and UCLASS
let cls = require('uclass')()(global, ClassName);
```

参考：[USTRUCT and UCLASS](https://github.com/ncsoft/Unreal.js/wiki/USTRUCT-and-UCLASS)

## UFUNCTION

```cpp:unreal_c++
UFUNCTION([specifier, specifier, ...], [meta(key=value, key=value, ...)])
ReturnType FunctionName([Parameter, Parameter, ...])
```

```js
class ClassName{
  //...
  FunctionName([
    Parameter /* PropertyFlag+ParamType */,
    Parameter /* PropertyFlag+ParamType */,
     ... 
  ]) /* specifier+ReturnType */
}
```

前提として`UCLASS`と同時に定義する必要がある（JS的には必ずクラスのメソッド）。

`関数名(引数名 /* UPROPERTYのフラグ+引数の型 */) /* UFUNCIONのフラグ+返り値の型 */`という形で定義する。「UFUNCIONのフラグ」は[関数指定子](https://docs.unrealengine.com/latest/JPN/Programming/UnrealArchitecture/Reference/Functions/Specifiers/index.html)ということで調べられるが、Unreal.jsのWikiには言及がないのですべて使えるかどうかは不明。

 - 参考：[関数指定子](https://docs.unrealengine.com/latest/JPN/Programming/UnrealArchitecture/Reference/Functions/Specifiers/index.html)
 - 参考：[USTRUCT and UCLASS](https://github.com/ncsoft/Unreal.js/wiki/USTRUCT-and-UCLASS)
 - 参考：[UPROPERTY](https://github.com/ncsoft/Unreal.js/wiki/UPROPERTY)

## UPROPERTY

```cpp:unreal_c++
UPROPERTY([specifier, specifier, ...], [meta(key=value, key=value, ...)])
Type VariableName;
```

```js:Unreal.js
class MyClassName{
  //...
  properties(){
    this.VariableName /* specifier+specifier+...+Type */;
  }
}
```

前提として`USTRUCT`か`UCLASS`と同時に定義する必要がある。

`UPROPERTY`マクロは変数プロパティをエディタ上やBlueprint上から扱えるように設定するため設定する頻度が高い。JSで同様にするためには`properties()`メソッドの中で次のように定義する。`properties()`メソッド以外では定義できないので注意。

`this.プロパティ名 /* フラグ1+フラグ2+...+型 */;`

 * 参考：[UPROPERTY](https://github.com/ncsoft/Unreal.js/wiki/UPROPERTY)
 * 参考２：[UE4 よく使うUPROPERTYメモ](http://qiita.com/bigengelt/items/b17545fffe7b8d69e5e8)

なお、ドキュメントには明記されていないが`EditCondition`などの[メタプロパティ](https://wiki.unrealengine.com/UPROPERTY#Valid_Meta_Properties)も次のような書き方で有効になった。

```js:metaの書き方
properties() {
  //bEditConditionが有効ならエディタ上で編集可能に
  this.EditConditionVariable /* EditAnywhere+Category:condition+EditCondition:bEditCondition+int32*/
  //エディタ上で普段は隠しておく
  this.bEditCondition /* EditAnywhere+Category:condition+AdvancedDisplay+bool */;  
}
```

![MetaEditCondition1.png](https://qiita-image-store.s3.amazonaws.com/0/54764/be1e6418-6e22-c053-d0f0-b489a5f771cd.png)
↓
![MetaEditCondition2.png](https://qiita-image-store.s3.amazonaws.com/0/54764/32505979-2ea2-8d68-b1a6-2c0750507cbe.png)


## USTRUCT

```cpp:unreal_c++

USTRUCT([Specifier, Specifier, ...])
struct StructName
{
    GENERATED_USTRUCT_BODY()
};
```

 * [公式doc](https://docs.unrealengine.com/latest/JPN/Programming/UnrealArchitecture/Reference/Structs/index.html)

```js
class StructName /* Struct+Specifier+Specifier+... */{
   properties() {
     //property-declarations
   }
}
```

`UStruct`はJSのクラスを作成したうえで、`Struct`とコメントの最初に記述する。

参考：[USTRUCT and UCLASS](https://github.com/ncsoft/Unreal.js/wiki/USTRUCT-and-UCLASS)

# 補足情報

* uclass.jsの中では正規表現で文字列解析して変換している
 * `Function.toString()`でソース文字列を引っ張って解析（コメントも取得できる）
 * なのでここのコードを書き換えるか同様の処理を別のJSでやれば別の記法で型とフラグ情報を付与できる
* `UINTERFACE`マクロに相当するものはないっぽい？