Linden Scripting Language(LSL)はリンデン・ラボが運営している仮想世界Second Lifeでユーザが使用できるプログラミング言語である。LSLによってSecond Life内のオブジェクトの挙動をコントロールすることができ、また電子メール、XML-RPC、HTTPリクエスト送信によって外部インターネットとの通信も行なえる。
LSLはC言語に近い文法構造を持ち、非常に強い型付けの言語である。有限状態マシン(有限オートマトン)をモデルにした「状態(State)-イベント駆動型スクリプト言語」といえる。
LSLの構造
スクリプトは変数、関数定義、1個以上の状態(ステート)、から構成される。各ステートには、そのステートにある場合に起こったイベントにどう反応するかが記述される。
基本データ型は整数型、浮動小数点実数型、文字列、キー(UUID)、ベクトル(3次元位置、およびRGB色表現)、ローテーション(クォターニオン)がある。また、配列型や構造体に相当するものとして基本データ型を要素とするリスト型がある。組み込み関数は2015年11月時点で430個あり、ユーザーは必要に応じてユーザー定義関数を定義することもできる。
実行環境
スクリプトは Second Life の仮想世界内に配置された椅子や壁といったオブジェクトの中に配置され、実行される。その点でスクリプトはオブジェクトと非常に密接に結び付けられる。システムはスクリプトにイベント(タイマー・移動・アバターとのチャット・電子メール・他のオブジェクトとの衝突など)を送信し、その結果スクリプトはステート遷移を起こしたり、他のオブジェクトやアバターとコミュニケーションを行うことになる。
スクリプトはオブジェクトに追加され次第開始される。そのオブジェクトが仮想世界内に配置されている限り、所有者がログインしていない状態でも実行は継続する。所有者がオブジェクトを撤去して自分のインベントリに移し、さらにオブジェクトを仮想世界内に再配置した場合でも、スクリプトの状態は保持されている。ファイルやデータベースといった永続的なデータ記憶機構は用意されていないが、例えばHTTPリクエスト通信を利用して Second Life 外にデータを保存することはできる。
オブジェクトには複数のスクリプトを含めることができ、それらを並行して実行できる。単体のスクリプトで使用できるメモリ領域は64キロバイト以下に制限される。各スクリプトはバイトコードの実行形式にコンパイルされ、リンデン・ラボのサーバ上の Mono を用いた仮想機械で実行される。
いくつかの組み込み関数ではその負荷に応じて0.2秒~20秒の「遅延」が設定されており、高負荷となる関数の連続実行が制限される。さらに実行時間が掛かる処理はすべてイベントハンドラを使った非同期処理となる。これは一つの仮想世界シミュレーターのなかで、数千から数十万個のスクリプトが同時稼働するため、スクリプト実行者がシステム資源に過大な負担をかけないようにするためである。
基本となるLSLスクリプト
以下は定型で用意される基本となるスクリプト(一種のHello world)である。default というステートの中に state_entry、touch_start という2つのイベントが記述されている。各イベント発生時、「Hello, Avatar!」「Touched.」とオブジェクトが発言する。
default
{
state_entry()
{
llSay(0, "Hello, Avatar!");
}
touch_start(integer total_number)
{
llSay(0, "Touched.");
}
}
非同期処理のサンプル
キーボード入力や、ファイル読み出しは、非同期処理で行う。指定したテキストファイル(ノートカード)の内容表示を行うサンプルを示す。
integer lsn;
string filename;
integer line;
key read;
default
{
touch_start(integer total_number)
{
llOwnerSay("Enter note name:");
lsn = llListen(0,"",llGetOwner(),"");
}
listen(integer channel, string name, key id, string message)
{
if(channel==0 && id==llGetOwner()){
llListenRemove(lsn);
filename = message;
state read_file;
}
}
}
state read_file
{
state_entry()
{
if(llGetInventoryKey(filename)==NULL_KEY){
llOwnerSay("ERROR: note is missing.");
state default;
}
line = 0;
read = llGetNotecardLine(filename,line);
}
dataserver(key requested, string data)
{
if(requested==read){
if(data==EOF){
filename = "";
state default;
}
llOwnerSay(data);
line++;
read = llGetNotecardLine(filename,line);
}
}
}
関連項目
外部リンク