ActionScriptのThreadライブラリ（そうめん）をHaxe/OpenFLに移植した際にやったこと

# はじめに

ActionScript Thread Library 1.0 (そうめん)をHaxe/OpenFLに移植しました。

**[HxThread](https://github.com/utibenkei/hxthread) (https://github.com/utibenkei/hxthread)**

この記事ではAS3のライブラリをHaxeへ移植した際に行った作業を手順を追って説明したいと思います。

### ActionScript Thread Library(そうめん)とは
[yossy](http://beinteractive.jp/)氏が開発された、非常に便利なライブラリです。

> ActionScript Thread Library 1.0 (そうめん) は、タスクシステムと Java のスレッドモデルをベースとした疑似スレッドライブラリです。 複雑で冗長になりがちな、イベント処理や非同期処理、リアルタイム処理を、分かりやすくスマートに記述することを可能にします。 もちろん、割り込みやキャンセル、例外処理もバッチリです。スレッドを使って、イベントリスナー地獄から抜け出しましょう。

具体的な使い方はここを見てもらえればわかると思います。

- [ActionScript Thread Library 1.0 (そうめん) で非同期処理をスマートに](http://www.adobe.com/jp/devnet/flex/articles/as_thread_library.html)
- [ActionScript Thread Library 1.0 (そうめん) ドキュメント](http://www.libspark.org/htdocs/as3/thread-files/document/)

### 開発環境

この移植作業の動作検証は全て、以下の環境で行いました。

- Windows8.1
- FlashDevlop
- Haxe(3.1.3)
- OpenFL(2.1.7)
- [munit](http://github.com/massiveinteractive/MassiveUnit)(2.1.0)
- [async-tests](https://github.com/ProG4mr/asynctests)(1.0.0)

# AS3とHaxeの文法の違いを確認する

まずは移植作業の参考になるサイトを一通り眺めて、 AS3とHaxeの文法の違いを確認します。

- [AS3とHaxeの構文比較：図書塔](http://rsakane.net/memo/?p=56)
- [AS3 and Haxe Comparison：haxeflixel.com](http://haxeflixel.com/documentation/as3-and-haxe-comparison/)
- [AS3 和 Haxe 语法对比](http://r32.github.io/haxe/2014/03/29/as3-and-haxe-comparison.html)
- [as3tohaxe-cheatsheet](https://github.com/azrafe7/as3tohaxe-cheatsheet)
- [Tarwin's AS3 to Haxe conversion script](https://github.com/as3boyan/tarwins_as3_to_haxe_conversion_script_-_haxe_neko_-)
- [AS3 to Haxe Conversion Script](https://github.com/CloudKidStudio/AS3ToHaxehttp://)


# AS3 to Haxeコンバータで変換する

元となる[ActionScript Thread Library](http://www.libspark.org/wiki/Thread)のソースコードをSVN等から入手してください。

AS3 to Haxeのコンバータはいくつか存在しますが、今回は一番良さげな[as3hx](https://github.com/openfl/as3hx)というコンバータを利用します。

### 使い方

haxelibでインストールしてから

```
haxelib run as3hx Thread/ out/
```

で、出力フォルダに変換された.hxファイルが生成されます。

※ホームディレクトリに生成される".as3hx_config.xml"という設定ファイル編集することで、変換内容をカスタマイズすることができるようです。


# 手作業でコードを修正する

単純なコードならコンバータによる変換結果がそのままでHaxeで動くかもしれませんが、今回はいくつかの部分で手直しが必要でした。

### * リフレクション


```as3:as3
runHandler.apply(this, [error, errorThread]);
```


```haxe:haxe
Reflect.callMethod(this, runHandler, [error, errorThread]);
```

### * インスタンスオブジェクトからクラス名を得る


```as3:as3
getQualifiedClassName(error);
```

```haxe:haxe
Type.getClassName(Type.getClass(error));
```

### * パッケージを含まないクラス名を得る

```as3:as3
var names:Array = getQualifiedClassName(this).split(/::/);
return names.length == 2 ? names[1] : names[0];
```


```haxe:haxe
return Type.getClassName(Class).split('.').pop();
```


これらの手直しにより、Haxeのflash出力でコンパイルが通るようになりました。
flash出力ではオリジナルと同じ「as3unit」というswcのテストライブラリを利用したかったのですが、HaxeでAS3のnamespaceを指定する方法が（いくら調べても）判らなかったので、あきらめて「[munit](http://github.com/massiveinteractive/MassiveUnit)」というHaxeのユニットテストライブラリを利用しました。
ユニットテスト、サンプル共に無事にに動作しているようです。

# OpenFLでも動くようする

ここからはこの移植の本当の目的であるOpenFLでの動作を目指します。
もしかしたら、修正無しでクロスプラットフォームで動くかなぁと淡い期待をしていたのですが、世の中にそんな都合のよい話はありません。
以下の修正が必要でした。

### * native/html5ターゲットではaddChild()しないとEnterFlameイベントが発行されない

EventDispatcherをaddChildする

```haxe:EnterFrameThreadExecutor.hx
		#if (native || html5)
		// openflの native/html5 ターゲットではaddChild()しないとイベントが発行されない現象への対処
		openfl.Lib.current.addChild(_clip);
		#end
```

### * nativeターゲットでLoaderでローカルのファイルをロードすると同期的に完了イベントが発行される

(Loader/URLLoaderではnativeのみ、SoundLoaderではnativeとhtml5でもみられる現象)
イベントリスナーの適用を待ってからロード開始する

```haxe:LoaderThread.hx
	override private function run():Void
	{
        events();
		// 割り込みハンドラを設定
		Thread.interrupted(interruptedHandler);

		// ロード開始
		#if (native)
			// イベントリスナーの適用を待ってからロード開始する
			// openflの native ターゲットではローカル上の画像ファイルをロードした際に同期的に完了イベントが発行される？
			// (internalExecute()内のeventHandler.register()でリスナーが設定される前にロード完了イベントが発行されてしまうことへの対処)
			var funcThread = new FunctionThread(function() { load(); }, []);
			funcThread.start();
		#else
			load();
		#end
	}

```


これでやっとOpenfFLでも使えるようになりました。
OpenFLでも「[munit](http://github.com/massiveinteractive/MassiveUnit)」でユニットテストをしたかったのですが、なぜかnativeターゲットにおいて非同期テストを動作させることができなかったので今度は「[async-tests](https://github.com/ProG4mr/asynctests)」というテストライブラリを利用しました。

とりあえず今のところ、OpenFLの以下のターゲットでテストとサンプルが動作することを確認しています。

- flash
- native (neko / windows)
- html5


# おわりに
コンバータがあったので移植作業は思ったより楽でした。
なにより元のライブラリのコードにきめ細やかな日本語のコメントが付いていたので助かりました。
素晴らしいライブラリを開発していただいた[yossy](http://beinteractive.jp/)氏に改めて感謝と共にお礼申し上げます。

#追記
記事の投稿後に素晴らしいAS3ライブラリ移植のプロジェクトを見つけたので、ぜひ紹介させてください。

**[SiON](https://github.com/gunnbr/SiON) (https://github.com/gunnbr/SiON)**

SiONライブラリとは、こんなライブラリです。（[オリジナル版ページ](https://sites.google.com/site/sioncenterj/)より引用）

> SiON (“サイオン”) は，Flash Player 10 上で動作する ソフトウェア音源 です．
このライブラリによって mp3 データを用意しなくても様々な音を合成し，楽譜に合わせて演奏する事ができます．また，曲シーケンスと DisplayObject の連携や，動的な音楽生成が，シンプルに実装できます．もちろん mp3 データにも対応しており，Sound クラスを PCM 音源波形として取り込む事で，スライシング/ループ再生，ピッチ/エンベープ/モジュレーション/フィルタなどの操作やエフェクタによる加工，mp3 データ自体を音色として楽譜の演奏，などが可能です．
楽譜や音源の設定は Music Macro Language (MML) によって記述する事ができるため，非常に軽量なテキストデータによって音楽や効果音を表現できます．

コミットログもとても参考になります。
まだ移植途中のようですが、頑張っていただきたいです。