2007年12月18日
回転マンタ・スクリプトの総括(3)
さてさて回転マンタ・スクリプトの総括の続きです。
4.llCreateLink
リンク生成の関数です。先にマンタが最後に自分のUUIDをメッセージで飛ばしていたのは、このためでした。
llCreateLink(key target, integer parent)
key targetにリンクする相手のUUIDを指定する必要があります。
integer parentにはTHRUEかFALSEを指定します。THRUEなら自分をルートにし、FALSEなら相手をルートにします。
今回のケースでは、回転軸側で発行していますので、THRUEを指定しています。
ここで幾つか問題になった事がありました。
・リンクするオブジェクトに対して、オーナーは編集権限を持っていないといけない事。
・リンクが成功したか、失敗したかの判断方法。
・アバターがオブジェクトに座る行為もリンクと見なされる事。
まずはリンク結果の判断方法ですが、これも色々考えられます。
(1)Changeイベントで判断する
今回使っているのはこの方法です。リンクが成功すればChangeイベントが発生します。
実際には以下のような処理をしてます。
changed(integer change){
if (change & CHANGED_LINK) {
llSetTimerEvent(0);
status = 1;
llMessageLinked( LINK_SET, status, msg_sta, NULL_KEY);
state moving;
}
}
これはif文でリンクの状態が変わったかどうかを判断しています。今回の仕様では、リンク生成を発したオブジェクトは、その時点では単独オブジェクトですから、リンク状態が変わった=リンク成功と考えています。
ただ、Changeイベントだけでは、リンクが失敗した場合は判定ができません。
仮に先のif文でelseを指定した場合はどうなるか?それは、リンク以外での状態が変わった事を意味します。オーナーが変わったとか、大きさが変わったとか・・今回はリンクが変わった時のみを対象としてますから、elseの指定は無いです。
また、リンク生成を発生させた後、タイマー設定して、タイマーイベントが発生したら、リンクが失敗したと判定させています。
もしリンクが成功していれば、changeイベントが先に発生しますから、タイマーイベントは発生し無い事になりますので。
(2)リンクNumberで判断(llGetLinkNumber)
llGetLinkNumber()で自分のリンク番号を取得して判断する事もできます。
単独プリムの場合はllGetLinkNumber()=0になります。自分をルートとしてリンクに成功するとllGetLinkNumber()=1に変わります。
ただし、この場合もタイムラグ等もあるので、一定時間待って番号を取得した方が良いでしょう。1秒待って番号を取得して、番号が変わって居なければリンクは失敗したと判断するとかです。
(3)リンク失敗のシステムメッセージを取得できないか?
結論から言うと取得できないようです。この方式は断念しました。
参考までに書いておきますと、リンク失敗した場合には次のようなダイアログとシステムメッセージが出力されます。


このメッセージを取得できれば、確実にリンク失敗を検知できることになります。
この点に関しては、MizさんのBBSに投稿し、Mizさん自身からもご意見をいただきました。結論はデバッグチャネルにも通常チャネルにも出力されていないようで、lissenイベントでは取得できませんでした。うーん。。。残念。
今回(1)の方法を採用した理由は、単にchangeイベントを使ってみたかったからです。
まあ、最終的には(1)と(2)の両方を使って、確実にリンク状態を把握して対応する事になりましたが。
そして、もう一つの問題である、座られてもリンク状態が変わると言う点ですが、これは無視する事にしました。理由は「座れないから」です。
フリー・ムーブ・マンタで以前書きましたが、完全ファントム化すると座れないのです。座れないオブジェクトで有る以上、座られた時の状態変化を考慮する必要は無くなります。
さて、残る問題はオーナーに「編集権限」を与えなくてはならない事です。
実はこれも厄介なのです。
今回の仕様では、回転軸オブジェクトをSculptedで作って、見た目は小さく、実は10m四方の大きなオブジェクトにしています。これはマンタのリンク可能距離を最大化するためです。
ところが、編集可能な状態にしてしまったら、購入者が勝手に回転軸プリムを小さくできてしまう事になります。これでは、せっかく最大距離までリンク可能にして。その範囲チェックまでしていても意味が無くなってしまいます。
でも「編集権限」が無いとリンク生成ができません。。。と言う事で、姑息な手段をとりました。
スクリプト内で、強制的にスケールを10m四方にしてしまう事です。勿論マニュアルで変更できてしまうのですが、リンク生成する直前には、必ず最大サイズにスケール変更かけてリンク命令を出すようにしました。
これなら、確実にリンク距離が保障できますから。
しかし、リンク生成に関しては、更なる問題も発見しました。
それは、「対象オブジェクトは同じ権限(次のオーナーが実行できる操作)状態で無いとリンクできない!」と言う事でした。
具体的には、回転軸プリムは「編集可」「コピー不可」「再販可」に設定していました。そしてコンテンツ内のマンタは、「編集可」「コピー可」「再販不可」にしてあったのですが、この状態で他の人へ渡して使わせるとリンクエラーが出てしまいます。
エラーは「 Link failed -- cannot link no-copy with no-transfer」と言う物です。

どうも、回転軸プリムとマンタとで権限が違うためにエラーになったようです。
試しに両方とも「編集可」「コピー可」「再販不可」に揃えたらエラーは消えました。同様に、「編集可」「コピー不可」「再販可」に揃えてもエラーにはなりません。正常にリンクできました。
でも、「編集可」「コピー不可」「再販可」の設定では、on_rezで書いたとおり、1回Rezしたらマンタがコンテンツ内から消えてしまう事になってしまいます。結局は「編集可」「コピー可」「再販不可」に揃える以外には無いと言う事です。
5.llBreakAllLinks
前項がリンクの生成でしたが、今回はリンクの全解除です。
何のために使っているか?それは、回転しているマンタを再設定する場合に必要だからです。
今回の仕様では、ダイアログでサイズ、回転方向、回転半径の設定ができますが、これらの設定内容は、マンタをコンテンツ内からRezした時に反映するようになっています。
ですから、動いているマンタを止めて、再度ダイアログで設定する場合には、一旦マンタを消滅させないといけません。
そこで、一度リンクを全解除し、その後マンタの部分だけを消滅させると言う訳です。
この仕組みを書くと次のようになります。
(1)マンタ(又は透明ながら回転軸)にタッチ
(2)停止命令がリンクメッセージで発令
(3)停止命令にそって、回転軸スクリプトはリンク全解除を発令し、透明化を解除してダイアログを表示
(4)マンタ側の各パーツはリンクが解除されると、自分自身を消滅させる。
と言う具合です。
llBreakAllLinksもllCreateLinkと同様に、オーナーには対象オブジェクトに対する編集権限が必要になります。
又、今回は全解除してますが、リンク番号を指定した部分解除も可能です。その場合はllBreakLinkを使います。
6.llDie
プリムを消滅させる命令です。
先に書いたようにリンクを全解除して、それぞれのパーツ毎にllDieを記述して消滅させています。
勿論回転軸には書かれていません。
が、リンク解除命令発動後、即各パーツで実行すると、何故か回転軸も巻き込まれて消滅してしまいます。
リンク生成やリンク解除時には、若干のタイムラグがあるそうです。リンク生成時にも1秒程度のタイムラグがあるとlslWikiにも書いてありました。 解除時も同様のようです。
実際のスクリプトとしては、今回もchangeイベントを使用しています。
default
{
changed(integer change){
if (change & CHANGED_LINK) {
if(llGetLinkNumber()==0){
llSleep(0.5);
llDie();
}
}
}
}
てな感じですね。
念のためllGetLinkNumber()==0で自分が単独プリムになっている事まで確認しています。
そして、0.5秒待って消滅!と言う事です。
llDieはもう一箇所使ってます。
それは、リンク生成失敗時の処理です。リンク生成に失敗したと回転軸プリムが認識したら、「死ね!」とメッセージを叫びます。それをマンタは受け取り、「ご主人様の命じるままに。。。」と自ら消滅するのです。
なんとなく哀れな感じもしますけど、まあしょうがないですね。そのままでは動けないのですから。
と言う事で、これで新たに使ってみたスクリプト関係のお話は終わりです。
最初は簡単そうだから・・・と思って始めた回転型マンタでしたが、実際には非常に面倒でした。しかし、どうしてもサイズ調整やリンク距離の調整、回転方向等を設定で入るようにしたかったので、ここまで複雑になってしまったのです。
そして、何より厄介だったのは、マンタをバラさずに調整したいと言う事でした。
マンタを分解した状態で、先の調整を実現する方が遥かに厄介に感じていたのです。でも終わってみると、個々の位置関係を詳細に記録して、最初からリンクした状態で調整した方が簡単だったかな?などと思えてしまいます。
現時点でもこのスクリプト仕様で販売しようか?どうしようか?まだ迷っています。
それはまだ販売上は問題になりそうな部分が残っているからです。その辺は次回「番外編」で書きたいと思います。
4.llCreateLink
リンク生成の関数です。先にマンタが最後に自分のUUIDをメッセージで飛ばしていたのは、このためでした。
llCreateLink(key target, integer parent)
key targetにリンクする相手のUUIDを指定する必要があります。
integer parentにはTHRUEかFALSEを指定します。THRUEなら自分をルートにし、FALSEなら相手をルートにします。
今回のケースでは、回転軸側で発行していますので、THRUEを指定しています。
ここで幾つか問題になった事がありました。
・リンクするオブジェクトに対して、オーナーは編集権限を持っていないといけない事。
・リンクが成功したか、失敗したかの判断方法。
・アバターがオブジェクトに座る行為もリンクと見なされる事。
まずはリンク結果の判断方法ですが、これも色々考えられます。
(1)Changeイベントで判断する
今回使っているのはこの方法です。リンクが成功すればChangeイベントが発生します。
実際には以下のような処理をしてます。
changed(integer change){
if (change & CHANGED_LINK) {
llSetTimerEvent(0);
status = 1;
llMessageLinked( LINK_SET, status, msg_sta, NULL_KEY);
state moving;
}
}
これはif文でリンクの状態が変わったかどうかを判断しています。今回の仕様では、リンク生成を発したオブジェクトは、その時点では単独オブジェクトですから、リンク状態が変わった=リンク成功と考えています。
ただ、Changeイベントだけでは、リンクが失敗した場合は判定ができません。
仮に先のif文でelseを指定した場合はどうなるか?それは、リンク以外での状態が変わった事を意味します。オーナーが変わったとか、大きさが変わったとか・・今回はリンクが変わった時のみを対象としてますから、elseの指定は無いです。
また、リンク生成を発生させた後、タイマー設定して、タイマーイベントが発生したら、リンクが失敗したと判定させています。
もしリンクが成功していれば、changeイベントが先に発生しますから、タイマーイベントは発生し無い事になりますので。
(2)リンクNumberで判断(llGetLinkNumber)
llGetLinkNumber()で自分のリンク番号を取得して判断する事もできます。
単独プリムの場合はllGetLinkNumber()=0になります。自分をルートとしてリンクに成功するとllGetLinkNumber()=1に変わります。
ただし、この場合もタイムラグ等もあるので、一定時間待って番号を取得した方が良いでしょう。1秒待って番号を取得して、番号が変わって居なければリンクは失敗したと判断するとかです。
(3)リンク失敗のシステムメッセージを取得できないか?
結論から言うと取得できないようです。この方式は断念しました。
参考までに書いておきますと、リンク失敗した場合には次のようなダイアログとシステムメッセージが出力されます。


このメッセージを取得できれば、確実にリンク失敗を検知できることになります。
この点に関しては、MizさんのBBSに投稿し、Mizさん自身からもご意見をいただきました。結論はデバッグチャネルにも通常チャネルにも出力されていないようで、lissenイベントでは取得できませんでした。うーん。。。残念。
今回(1)の方法を採用した理由は、単にchangeイベントを使ってみたかったからです。
まあ、最終的には(1)と(2)の両方を使って、確実にリンク状態を把握して対応する事になりましたが。
そして、もう一つの問題である、座られてもリンク状態が変わると言う点ですが、これは無視する事にしました。理由は「座れないから」です。
フリー・ムーブ・マンタで以前書きましたが、完全ファントム化すると座れないのです。座れないオブジェクトで有る以上、座られた時の状態変化を考慮する必要は無くなります。
さて、残る問題はオーナーに「編集権限」を与えなくてはならない事です。
実はこれも厄介なのです。
今回の仕様では、回転軸オブジェクトをSculptedで作って、見た目は小さく、実は10m四方の大きなオブジェクトにしています。これはマンタのリンク可能距離を最大化するためです。
ところが、編集可能な状態にしてしまったら、購入者が勝手に回転軸プリムを小さくできてしまう事になります。これでは、せっかく最大距離までリンク可能にして。その範囲チェックまでしていても意味が無くなってしまいます。
でも「編集権限」が無いとリンク生成ができません。。。と言う事で、姑息な手段をとりました。
スクリプト内で、強制的にスケールを10m四方にしてしまう事です。勿論マニュアルで変更できてしまうのですが、リンク生成する直前には、必ず最大サイズにスケール変更かけてリンク命令を出すようにしました。
これなら、確実にリンク距離が保障できますから。
しかし、リンク生成に関しては、更なる問題も発見しました。
それは、「対象オブジェクトは同じ権限(次のオーナーが実行できる操作)状態で無いとリンクできない!」と言う事でした。
具体的には、回転軸プリムは「編集可」「コピー不可」「再販可」に設定していました。そしてコンテンツ内のマンタは、「編集可」「コピー可」「再販不可」にしてあったのですが、この状態で他の人へ渡して使わせるとリンクエラーが出てしまいます。
エラーは「 Link failed -- cannot link no-copy with no-transfer」と言う物です。

どうも、回転軸プリムとマンタとで権限が違うためにエラーになったようです。
試しに両方とも「編集可」「コピー可」「再販不可」に揃えたらエラーは消えました。同様に、「編集可」「コピー不可」「再販可」に揃えてもエラーにはなりません。正常にリンクできました。
でも、「編集可」「コピー不可」「再販可」の設定では、on_rezで書いたとおり、1回Rezしたらマンタがコンテンツ内から消えてしまう事になってしまいます。結局は「編集可」「コピー可」「再販不可」に揃える以外には無いと言う事です。
5.llBreakAllLinks
前項がリンクの生成でしたが、今回はリンクの全解除です。
何のために使っているか?それは、回転しているマンタを再設定する場合に必要だからです。
今回の仕様では、ダイアログでサイズ、回転方向、回転半径の設定ができますが、これらの設定内容は、マンタをコンテンツ内からRezした時に反映するようになっています。
ですから、動いているマンタを止めて、再度ダイアログで設定する場合には、一旦マンタを消滅させないといけません。
そこで、一度リンクを全解除し、その後マンタの部分だけを消滅させると言う訳です。
この仕組みを書くと次のようになります。
(1)マンタ(又は透明ながら回転軸)にタッチ
(2)停止命令がリンクメッセージで発令
(3)停止命令にそって、回転軸スクリプトはリンク全解除を発令し、透明化を解除してダイアログを表示
(4)マンタ側の各パーツはリンクが解除されると、自分自身を消滅させる。
と言う具合です。
llBreakAllLinksもllCreateLinkと同様に、オーナーには対象オブジェクトに対する編集権限が必要になります。
又、今回は全解除してますが、リンク番号を指定した部分解除も可能です。その場合はllBreakLinkを使います。
6.llDie
プリムを消滅させる命令です。
先に書いたようにリンクを全解除して、それぞれのパーツ毎にllDieを記述して消滅させています。
勿論回転軸には書かれていません。
が、リンク解除命令発動後、即各パーツで実行すると、何故か回転軸も巻き込まれて消滅してしまいます。
リンク生成やリンク解除時には、若干のタイムラグがあるそうです。リンク生成時にも1秒程度のタイムラグがあるとlslWikiにも書いてありました。 解除時も同様のようです。
実際のスクリプトとしては、今回もchangeイベントを使用しています。
default
{
changed(integer change){
if (change & CHANGED_LINK) {
if(llGetLinkNumber()==0){
llSleep(0.5);
llDie();
}
}
}
}
てな感じですね。
念のためllGetLinkNumber()==0で自分が単独プリムになっている事まで確認しています。
そして、0.5秒待って消滅!と言う事です。
llDieはもう一箇所使ってます。
それは、リンク生成失敗時の処理です。リンク生成に失敗したと回転軸プリムが認識したら、「死ね!」とメッセージを叫びます。それをマンタは受け取り、「ご主人様の命じるままに。。。」と自ら消滅するのです。
なんとなく哀れな感じもしますけど、まあしょうがないですね。そのままでは動けないのですから。
と言う事で、これで新たに使ってみたスクリプト関係のお話は終わりです。
最初は簡単そうだから・・・と思って始めた回転型マンタでしたが、実際には非常に面倒でした。しかし、どうしてもサイズ調整やリンク距離の調整、回転方向等を設定で入るようにしたかったので、ここまで複雑になってしまったのです。
そして、何より厄介だったのは、マンタをバラさずに調整したいと言う事でした。
マンタを分解した状態で、先の調整を実現する方が遥かに厄介に感じていたのです。でも終わってみると、個々の位置関係を詳細に記録して、最初からリンクした状態で調整した方が簡単だったかな?などと思えてしまいます。
現時点でもこのスクリプト仕様で販売しようか?どうしようか?まだ迷っています。
それはまだ販売上は問題になりそうな部分が残っているからです。その辺は次回「番外編」で書きたいと思います。
llDetectedTouchST
llAddToLandPassList
【注意】Bulk Permissions機能は使っては駄目!
HTTP-INを使ってみた。
オブジェクトへの指示
ペットを作るには(6)
llAddToLandPassList
【注意】Bulk Permissions機能は使っては駄目!
HTTP-INを使ってみた。
オブジェクトへの指示
ペットを作るには(6)
Posted by Gonbe Shan at 19:15│Comments(2)
│スクリプトのお勉強メモ
この記事へのコメント
Link failed -- cannot link no-copy with no-transfer
これで検索をかけてここに来ました。
今、これが原因で人に渡すとうまく動かないことがわかりました。
なんとなくそうかなと思ってはいましたが。
私の場合は、オブジェクト(親)に子となるプリムを入れておいて、それをREZさせてリンクするようにしてます。
それでパーミッションの設定は、
親プリム
編集可(リンクのため)
子プリム
編集可(リンクのため)
コピー(rezのため)
としてました。LSL wikiとかみたんですが、親子とも編集可で、オーナーが同じでないとリンクはできないと書いてはありましたが、パーミッションの設定が異なるとだめとは書いてなかったように思います。
なんだかこの辺りのパーミッションの設計思想・実装・説明ってよくわかんないですね。やってみないと。
リンクではエラーでるけどブレークリンクではでないとか。同類のものだと思うんですけどね。
それと、パーミッションを得たときは、イベントが発生するのですが、得れなかったときはないので同じように時間を計って判断してます。
しばらくユーザの操作にロックをかけてユーザの許可が時間内に降りなかったら、ユーザーの許可が降りても今度はスクリプトが拒否するとか変数を元に戻すとかもう何がなにやらw
どうもお邪魔しました。
これで検索をかけてここに来ました。
今、これが原因で人に渡すとうまく動かないことがわかりました。
なんとなくそうかなと思ってはいましたが。
私の場合は、オブジェクト(親)に子となるプリムを入れておいて、それをREZさせてリンクするようにしてます。
それでパーミッションの設定は、
親プリム
編集可(リンクのため)
子プリム
編集可(リンクのため)
コピー(rezのため)
としてました。LSL wikiとかみたんですが、親子とも編集可で、オーナーが同じでないとリンクはできないと書いてはありましたが、パーミッションの設定が異なるとだめとは書いてなかったように思います。
なんだかこの辺りのパーミッションの設計思想・実装・説明ってよくわかんないですね。やってみないと。
リンクではエラーでるけどブレークリンクではでないとか。同類のものだと思うんですけどね。
それと、パーミッションを得たときは、イベントが発生するのですが、得れなかったときはないので同じように時間を計って判断してます。
しばらくユーザの操作にロックをかけてユーザの許可が時間内に降りなかったら、ユーザーの許可が降りても今度はスクリプトが拒否するとか変数を元に戻すとかもう何がなにやらw
どうもお邪魔しました。
Posted by 田中明夫 at 2008年02月25日 02:24
わーお仲間さんが居たんですねー^ ^;
このタイプは、最初思っていたよりずーっと複雑で、完成はさせましたが販売は止めにしました。
これほど複雑でありながら、表面の機能的にはTargetOmegaで回転しているだけですからね。。。><
ただ、スクリプトのお勉強には大いになりました。
でも、本音で言うと、ここまで複雑な配慮をしても、根源たるリンデンの仕様がいい加減だったら、何時何が起こるか分からないなー・・
と言う気持ちです。
だから、複雑なスクリプト制御は極力しない範囲での製品にしようと思っています。
後のトラブルが怖いですし・・・orz
作っていて「面倒だなー」と思ったら、個人の範囲での遊び道具にしちゃいます。^ ^;
このタイプは、最初思っていたよりずーっと複雑で、完成はさせましたが販売は止めにしました。
これほど複雑でありながら、表面の機能的にはTargetOmegaで回転しているだけですからね。。。><
ただ、スクリプトのお勉強には大いになりました。
でも、本音で言うと、ここまで複雑な配慮をしても、根源たるリンデンの仕様がいい加減だったら、何時何が起こるか分からないなー・・
と言う気持ちです。
だから、複雑なスクリプト制御は極力しない範囲での製品にしようと思っています。
後のトラブルが怖いですし・・・orz
作っていて「面倒だなー」と思ったら、個人の範囲での遊び道具にしちゃいます。^ ^;
Posted by Gonbe Shan
at 2008年02月25日 11:20
