GUIアプリケーションというものは、Headlessモードを搭載しているモノが多くあります。
例えば、Google Chrome の Headlessモード。
ちょっとした自動化、CI/CD、テスト、デバッグなんかを実行するのに便利だし、
グラフィック処理がない分高速です。
ディスプレイのないサーバーでも動作させることができます。
OSSなゲームエンジン Godot もいくつかの操作をコマンドライン上で実行することができます。
特に、オンライン用のサーバーサイドを書くときに結構便利そうなので、使い方をメモっておきます。
↑に色々書いてあります!
Godot をコマンドとして実行できるようにする
※macOS + zsh です。別環境の人は適宜読み替えてください。
Macの/Applications
フォルダにGodotをインストールした人は、
Godot.app
を 右クリックして、「コンテンツを表示」とやるとこんな感じになってるはず。
/Applications/Godot.app/Contents/MacOS/Godot
これがGodotの実行ファイルパスです。
Finderからダブルクリックしてやると、Godotエディタが起動します。
これをターミナルのコマンドとして実行できるように、.zshrc
にalias
を定義してやります。
# Godot bin
alias godot="/Applications/Godot.app/Contents/MacOS/Godot"
これで準備OKです!
-e
ターミナルからGodot Editorを起動する。
-e
= --editor
ターミナルからGodotを始めたい人も結構いるはず。
Godotのプロジェクトファイル(project.godot
)があるディレクトリで、
godot -e
を実行すると、そのディレクトリ内のプロジェクトを開きます。
ただし、macの場合は、open
コマンドで開いた方が、バックグラウンド実行されて
ターミナルを占領されないのでそっちのがいいかもしれない。
cd path/to/project
godot -e
# macならこっちのがいいかも
open project.godot
-s
GDScriptを実行
-s
= --script
godot -s --headless file.gd
上のコマンドを実行すると、
以下の2つのどちらかのClassを継承した.gd
ファイルを、Headlessで実行できます。
MainLoop
SceneTree
MainLoop
は SceneTree
のスーパークラスなのですが、
全てのメソッドが仮想メソッドで、実処理が実装されていなくて使いづらいので、
Headlessで使う場合はSceneTree
の方がおすすめだと思います。
Hello Worldを書くとこんな感じです。
extends SceneTree
func _init():
print("Hello, world!")
quit()
スクリプトを実行する。
> godot -s hello.gd
# Hello, world!
ちょっとした計算機にするとか、pythonっぽい使い方ができそうです。
ちなみに、本番環境でスクリプトモード実行するのはやめときましょう。
ヘッドレスサーバー向けにバイナリをビルドできるので、そっちの方が高速です。
そのときは、--export
フラグを付けます
# プロジェクトフォルダ内で実行する
# godot --export <target> <out_path>
godot --export "Linux/X11" /var/builds/project
-d
シーンをデバッグ実行する
-d
= --debug
Godotエディタの右上についてるボタンと同じ挙動です。
メインシーンを実行したり、個別シーンを実行したりできます。
godot -d
# .tscnファイルを指定して実行
godot -d SubScene.tscn
# headless モードで実行
godot -d --headless SubScene.tscn
個人的に、ターミナルからGodotを使う一番の動機となります。
Godot Editorからのデバッグ実行では1つのシーンしか同時に起動できません
これは、マルチプレイゲームのServer/Clientシーンを同時に起動して
デバッグしたい場合に不便です。
しかし、ターミナルのタブを複数開いてCLIから実行すれば、
同時に複数のシーンを実行することができます。
おまけ : UDPサーバーデモ
godot -s
のスクリプト実行で、簡単なUDPサーバー/クライアントを
実行してみます。
extends SceneTree
func _init():
var done = false
# host=127.0.0.1, port=4242 でUDP通信を待受
var socket = PacketPeerUDP.new()
if(socket.listen(4242, "127.0.0.1") != OK):
print("server error")
done = true
else:
print("listening on port 4242 on localhost")
# utf8 で "quit" パケットが来たら終了
while (!done):
if(socket.get_available_packet_count() > 0):
var data = socket.get_packet().get_string_from_utf8()
if (data == "quit"):
done = true
else:
print("recieve data is {%s}" %data)
socket.close()
print("Exit App")
self.quit()
extends SceneTree
func _init():
# Serverに接続して、"Hello"を送る
var socket = PacketPeerUDP.new()
socket.set_dest_address("127.0.0.1", 4242)
socket.put_packet("Hello".to_utf8())
quit()
スクリプト実行
godot -s --headless Server.gd
# 別タブ
godot -s --headless Client.gd
# recieve data is {Hello}
ちなみに、UDPのテストはMac/Linuxであればnc
(netcat)コマンドでも簡単にできます。
# nc {host} {port}
# -u : UDPモード
nc -u 127.0.0.1 4242
Hello^D
quit^D
# -l : Listen = サーバーモード
nc -lu 127.0.0.1 4242
Macの場合、
Ctrl + D = EOF