ラベル LSL の投稿を表示しています。 すべての投稿を表示
ラベル LSL の投稿を表示しています。 すべての投稿を表示

2018年7月24日火曜日

L$ Exchange Rate Board V1.1.0

L$ Exchange Rate Boardなんですが、2週間前ぐらいから動作してないことに気が付きました。そのときは、サーバーが調子悪いんじゃないかな?って思って、きっと数日後にはケロッと直ってるはず!って期待してたんですよ。でも1週間過ぎても直らないので、もう流石に知らないふりはできないなって思い始めて、色々と調べてみると原因はllHTTPRequestに関わるバグで、もう1ヶ月か2ヶ月くらいバグ修正されてないみたいでした。#BUG-216320

簡単に書くと、現時点で下記みたいにllHTTPRequestからSLのライブデータフィードを取得しようとすると499エラーが出ます。
// 取得するライブデータフィードURL
string url="http://secondlife.com/httprequest/homepage.php";

default
{
    touch_start(integer total_number)
    {
        key id=llDetectedKey(0);  // タッチしたアバターのキー
        if (id == llGetOwner()) {  // それがオーナーなら
            llHTTPRequest(url, [], "");  // HTTPリクエスト実行
        }
    }

    http_response(key request_id, integer status, list metadata, string body)
    {  // HTTPレスポンス
        if (status == 200) {  // 正常(ステータスコードが200)なら
            llOwnerSay(body);  // データ内容を表示
        }
        else {  // エラーのときはエラー番号を表示
            llOwnerSay("エラー HTTP status "+(string)status);
        }
    }
}

SL公式のデータフィードがインワールド内からゲットできなくなるなんて想定外だったので、現バージョン(当装置にはバージョン表記ないですけど一応V1.0.0かな?)のL$ Exchange Rate Boardはエラーも出さなくて、全くうんともすんとも言わない有様です^^; ちなみにライブデータフィードは普通にウエブブラウザで開くとエラーもなく開けるんですよ。なので外部サーバーを経由させてデータを取得するように改造しました。。。わざわざ外部サーバー使うって、何かバカみたいなんですけどねw まあエラー出たときだけ外部サーバーに頼るって感じの改良です。

今までにL$ Exchange Rate Boardをお買い上げ頂いたお客様には既にV1.1.0をお送りました。もし受け取れなかったお客様は再送しますのでご連絡くださいね。

2018年7月1日日曜日

名前からアバターキーを取得するスクリプト

ずっと存在しなかったアバター名からアバターキーを得る関数が最近できてたので、今回はそれを使ったスクリプトを書いてみました。昔は名前からアバターキーを調べるために、外部サーバーを併用するなどしてSLの検索などからHTMLデータを取得してキーを切り出すっていう面倒な方法しかなかったので便利ですよね。んー、ただ私はこの関数、プライバシーとかの関係で実装されてないのかなって勝手に思ってたんですけど、今頃になって実装されたってことはそうでもなかったんでしょうかね?w

新しく実装された関数はllName2KeyllRequestUserKeyです。llName2KeyはllKey2Nameと同様データサーバーを通さないので、同一SIM内かその周囲数m以内に対象アバターがいないと値が得られないんだと思います。。。ってことは名前からキーを割り出すっていう場面では、この関数ってあまり使い道なくないですかね?www

そういうことでllRequestUserKeyの方を使って、早速アバターキーを取得するスクリプトを書いてみました。

// アバター名からアバターキーを取得

integer ch=5;  // チャット入力に使うチャンネル番号
integer listen_handle;  // リッスン関数を扱うための変数
key query;  // データ問い合わせ用変数

listen_end()
{  // チャット受信またはタイムアウト時の処理
    llListenRemove(listen_handle);  // リッスンを破棄
    llSetTimerEvent(0);  // タイマー停止
}

default
{
    touch_start(integer total_number)
    {
        key id=llDetectedKey(0);  // タッチしたアバターが
        if (id == llGetOwner()) {  // オーナーなら
            llOwnerSay("「/"+(string)ch+" アバター名」でキーを検索します。");
            llListenRemove(listen_handle);  // 一応リッスンを破棄して
            listen_handle=llListen(ch, "", NULL_KEY, "");  // リッスン開始
            llSetTimerEvent(60);  // タイマー60秒
        }
    }

    timer()
    {  // 指定時間が経過したら
        listen_end();  // listen_endへ
        llOwnerSay("時間切れです><");
    }

    listen(integer channel, string name, key id, string msg)
    {  // チャットを受信
        if (channel == ch) {  // 設定したチャンネル番号なら
            listen_end();  // listen_endを処理して
            query = llRequestUserKey(msg);  // アバターキー問い合わせ
        }
    }

    dataserver(key queryid, string data)
    {
        if (queryid == query) {  // 問い合わせたデータを取得したら
            llOwnerSay("アバターキー "+data);  // アバターキーを表示
        }
    }
}

オーナーがタッチして「/5 アバター名」をチャットで入力するとアバターキーを表示します。入力するアバター名はユーザーネームでもレガシーネームでもオッケーみたいです。

7月3日追記: リッスン開始の直前に念のためリッスン破棄するよう修正しました。

2017年12月12日火曜日

チップジャーに入れると分配できるスクリプト

えっと、今回は久しぶりに簡単なスクリプトです。まあ記事書くのも、すごく久しぶりでマジ放置状態になってたりするんですが。。。^^;

このスクリプトをチップジャーのコンテンツ内に入れると、チップが支払われる度に分配できます。基本的に支払いを行うオブジェクトなら何でも動作しますが、異なる金額で複数の商品を販売するベンダーなど返金機能がある装置には向いてません。

// チップジャー用分配スクリプト

key avatar="00000000-0000-0000-0000-000000000000";  // 分配を受けるアバターのキー
integer  percent=10; // 分配率(%)
integer debit=FALSE;  // 権限確認用変数

default
{
    state_entry()
    {
        // プリムにスクリプトを入れたときL$引き落とし権限をリクエスト
        llRequestPermissions(llGetOwner(),PERMISSION_DEBIT);
    }

    touch_start(integer total_number)
    {
        key id=llDetectedKey(0);  // タッチしたアバターのキー
        if (id == llGetOwner()) {  // オーナーだったら
            // 変数debitが偽(権限が未許可)のときは権限をリクエスト
            if (!debit) llRequestPermissions(id,PERMISSION_DEBIT);
        }
    }

    run_time_permissions(integer perm)
    {
        if (perm & PERMISSION_DEBIT) {  // 権限が許可されたら
            debit=TRUE;  // debitに真をセット
        }
    }

    money(key id, integer amount)
    {  // チップの支払いが発生したとき
        // 分配額を計算
        integer commission=llFloor((float)amount*(float)percent/100);
        // 分配額が1~チップ額以内の範囲なら
        if (commission >= 1 && commission <= amount) {
            llTransferLindenDollars(avatar,commission);  // 分配金を送金
        }
    }
}

分配を受け取るアバターのキーと分配率を記入して、スクリプトをチップジャーに入れたら、L$口座からお金を引き落としできる権限を要求するダイアログが出るので許可してください。拒否してしまったときは、タッチすると再びダイアログを出します。最初のダイアログで間違いなく許可するつもりだったら、タッチイベントの部分(touch_start以下8行分)は必要ないので省略してしまっても構いません。

送金する関数は今回llTransferLindenDollarsを使ってますが、戻り値は使用してないので、従来のllGiveMoneyを使ってもオッケーです。

ちなみにベータテストグリッド(プレビューグリッド、Aditi)で送金テストする場合、L$取引履歴はこのアドレスで見れます。

2012年5月10日木曜日

プリムのリンク番号をチェックするスクリプト

プリムのリンク番号はllDetectedLinkNumberっていう関数で知ることができるんですね。それで、その関数のページにもタッチでリンク番号を表示する簡単なスクリプトが載ってるんですが、何となくリンク番号を表示したプリムがグロー全開で光るようにスクリプトを書いてみました。これならタッチしにくい場所とかで手がすべって隣のプリムをタッチしてたりって感じの失敗がなくていいんじゃないかなって思いますw

// タッチでリンク番号を表示

default
{
    touch_start(integer total_number)
    {  // タッチされたとき
        key id=llDetectedKey(0);  // タッチしたアバターのキー
        if (id == llGetOwner()) {  // オーナーだったら
            integer num=llDetectedLinkNumber(0);  // タッチされたプリムのリンク番号
            list faces=[];  // グローデータ記録用リスト
            integer i;
            integer j=llGetLinkNumberOfSides(num);  // タッチされたプリムの全面数
            for (i=0; i < j; i++) {  // 面の数だけ繰り返し
                list glow=llGetLinkPrimitiveParams(num,[PRIM_GLOW,i]);  // 面ごとにグローを取得して
                faces+=[PRIM_GLOW,i]+glow;  // グロー設定で使える形式にしてリストに保存
            }
            llOwnerSay("Link no."+(string)num);  // タッチされたプリムのリンク番号を表示
            llSetLinkPrimitiveParams(num,[PRIM_GLOW,ALL_SIDES,1.0]);  // タッチされたプリム全面のグローを1.0にセット
            llSetLinkPrimitiveParamsFast(num,faces);  // グローを元に戻す
        }
    }
}

タッチしたプリムが持つ面の数をllGetLinkNumberOfSidesで調べて各面のグローを記憶させるので、元々グローを設定したプリムがあっても支障が出ません。あとllSetLinkPrimitiveParamsは、llSetLinkPrimitiveParamsFastにするとノーウェイトでグローが視認できなかったので使用してます。(llSleep入れて調整してもよかったんですが)

スクリプトをオブジェクトの親プリムに入れてください。オーナーがタッチしたときにタッチされたプリムがグローで光って、オーナーのチャットにリンク番号が表示されます。

2012年3月14日水曜日

新関数を使った長距離用高速テレポーターのスクリプト

昨日、何となく公式wikiのLSL関数一覧を見てたらllSetRegionPosっていう便利な関数が追加されてるってことに気がつきました。この新関数はllSetPosみたいな最大10mの移動制限がないので、SIM内長距離用のテレポーターとかを書くのが楽になりますね。。。ホント簡単にオブジェクトが一瞬で移動できます^^

昔書いた長距離用高速テレポーターのスクリプト にllSetRegionPosを使うよう書き換えてみたら、こんな感じでかなりシンプルになりました^^
// 長距離用高速テレポーター(新)
vector dest;  // 目的地の座標保存用
vector pos;  // 出発地の座標保存用

default
{
    state_entry()
    {
        llSitTarget(<0.2,0,0.55>, ZERO_ROTATION);  // 座る位置
        dest=llGetPos();  // 現在位置の座標を目的地に設定
        llOwnerSay("Destination = "+(string)dest);
    }

    changed(integer change)
    {
        if (change & CHANGED_LINK) {  // リンクが変わったとき
            key id=llAvatarOnSitTarget();  // 乗ってるアバターのキー
            if (id) {
                if (pos) return;  // 出発地座標が設定されてるとき(動作中)はリターン
                pos=llGetPos();  // 現在位置を出発地の座標に設定
                llSetRegionPos(dest);  // 目的地へテレポート
                llUnSit(id);  // 目的地でアバターを降ろす
                llSetRegionPos(pos);  // テレポーターを出発地に戻す
                pos=ZERO_VECTOR;  // 出発地の座標をクリア
            }
        }
    }
}

移動させる部分以外は変更してないので、使い方は古いのと全く同じです。目的地でスクリプトをリセットしてから出発地に置くだけで使えます。

2011年8月23日火曜日

スカルプを表示させる装置のスクリプト

今回は装置のコンテンツ内にスカルプトテクスチャを入れてスカルプテッドプリムを表示させる簡単なスカルプ表示装置を作ってみました。丁度スカルプのテクスチャをアップロードするときのウィンドウで形状を確認できるのと同じ程度のものなんですが^^;

まず装置のプリムを作成します。1.0x1.0x0.2ぐらいのボックスを作り、面番号1番の面(Y軸のマイナス側の面)に操作パネルのテクスチャ(「← →」みたいな)を作って貼り付けてください。。。まあこのアニメーションベンダーと同じ感じにしてもらったらOKです。

そして、0.5x0.5x0.5ぐらいのボックス(ボックス以外でもいいけど)を作って、先ほど作ったプリムの真上に少し空間を空けて浮かべて、これを子プリムとしてリンクさせてください。(2プリムのオブジェクトになります)

続いてスクリプトです。スカルプの縫い目の種類はシリンダーに打ち決めしてます。http://wiki.secondlife.com/wiki/PRIM_TYPE_SCULPT/ja
// Sculpt viewer
integer number;  // スカルプトテクスチャの数
integer cur;  // ポインタ用
integer sculpt=2;  // 子プリムのリンク番号
integer sculpt_type=PRIM_SCULPT_TYPE_CYLINDER;  // スカルプの縫い目の種類

set_sculpt()
{
    string texture=llGetInventoryName(INVENTORY_TEXTURE,cur);  // ポインタからテクスチャ名を取得
    if (number > 0) llSetText(texture+" ("+(string)(cur+1)+"/"+(string)number+")",<1,1,1>,1.0);  // テクスチャが入ってるときフローティングテキストを表示
    else llSetText("",<1,1,1>,1.0);  // 入ってないときはフローティングテキスト非表示
    llSetLinkPrimitiveParamsFast(sculpt,[PRIM_TYPE,PRIM_TYPE_SCULPT,texture,sculpt_type]);  // スカルプを表示
}

init()
{
    number=llGetInventoryNumber(INVENTORY_TEXTURE);  // コンテンツ内のテクスチャ数
    if (cur >= number) cur=0;  // ポインタを初期化
    set_sculpt();  // set_sculptへ
}

default
{
    state_entry()
    {
        init();  // 最初はinitへ
    }

    changed(integer change)
    {
        if (change & CHANGED_INVENTORY) init();  // コンテンツ内が変化したらinit
    }

    touch_start(integer total_number)
    {  // タッチ
        integer i=llDetectedTouchFace(0);  // タッチされた面番号
        if (i == 1) {  // 面番号が1だったら
            vector v=llDetectedTouchUV(0);  // タッチされた位置
            if (v.x > 0.5) {  // 中央よりも右だったら「→」
                cur++;
                if (cur >= number) cur=0;
            }
            else {  // そうでないときは「←」
                cur--;
                if (cur < 0) cur=number-1;
            }
            if (cur >= 0) set_sculpt();  // set_sculptへ
        }
        else if (i == -1) {  // 古いビューワーは非サポート
            llWhisper(0,"Your viewer is not support.");
        }
    }
}

スクリプトを装置の親プリムのコンテンツに入れて、スカルプのテクスチャ(スカルプトUVマップ)もそこに入れてください。テクスチャを複数入れたら「←」「→」で順次表示できます^^


縦、横、高さとも同じ長さなので、やっぱりスカルプの階段なんかはこんな感じになりますけどねwww

2011年7月10日日曜日

簡単にフローティングテキストを付けるスクリプト

今回はllTextBoxを使ってフローティングテキスト(ホバーリングテキスト)を付けられる簡単で便利なスクリプトです。llTextBox実装の関係でビューワー2.4以上でないと使えないみたいですけど^^;

スクリプトをインベントリ(持ち物)の中で作っておいて、フローティングテキストを付けたいプリムにドロップするとテキスト入力ダイアログが出るので、そこにテキストを入れて送信すればオッケーです。あとフローティングテキストが設定されるとスクリプトは消えるようにしました。また無視とか放置したりしたときのために5分後には自動的に消えるようにしました。

// フローティングテキスト簡単設定

integer ch;  // ダイアログのチャンネル用変数

default
{
    state_entry()
    {
        ch=llCeil(llFrand(2147483646));  // チャンネルをランダムに決める
        key id=llGetOwner();  // オーナーのキー
        llListen(ch,"",id,"");  // リッスン開始
        llTextBox(id,"5分以内にフローティングテキストを入力してください",ch);  // テキスト入力用のダイアログ
        llSetTimerEvent(300);  // タイマー5分
    }

    timer()
    {  // 5分後にスクリプト削除
        llOwnerSay("時間切れです。スクリプトを削除します!");
        llRemoveInventory(llGetScriptName());
    }

    listen(integer channel, string name, key id, string msg)
    {  // リッスンイベント
        if (channel == ch && id == llGetOwner()) {  // いらないけど一応
            llSetText(msg,<1,1,1>,1.0);  // 受信したメッセージをフローティングテキストに設定
            llOwnerSay("テキストを設定しました。スクリプトを削除します。");  // なお、このスクリプトは自動的に消滅する
            llRemoveInventory(llGetScriptName());  // スクリプト削除
        }
    }
}

繰り返しますが、このスクリプトは消えるようになってるので、オブジェクト内でスクリプトを作ったときは実行する前に持ち物にコピーしてくださいねw

2011年5月10日火曜日

グループ専用ベンダーのスクリプト

グループギフトってのはよくあると思うんですが、たまにグループメンバーだけしか商品買えないベンダーなんてのもありますよね。そこで今回は簡単なグループ専用ベンダーのスクリプトです^^

まあこのグループギフトスクリプトをPayイベントで商品を渡すようにした感じですが、商品オブジェクトのチェックは支払いが起きたときだけにしました。無料のグループギフトと違って、グループが一致しなかったら返金しないといけないので、単品を売る商品ベンダーですが口座からリンデンドル引落しの許可が必要になります。

// グループ専用ベンダー
integer price=10;  // 価格

set_pay(integer on)
{
    if (on) {  // 支払いダイアログに価格を設定する
        llSetPayPrice(PAY_HIDE,[price,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
        llSetClickAction(CLICK_ACTION_PAY);  // クリックで支払い
    }
    else {  // 支払いダイアログを無効にする
        llSetPayPrice(PAY_HIDE,[PAY_HIDE,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
        llSetClickAction(CLICK_ACTION_TOUCH);  // クリックでタッチ
    }
}

default
{
    state_entry()
    {
        set_pay(FALSE);  // 支払いダイアログを無効に
        llRequestPermissions(llGetOwner(),PERMISSION_DEBIT);  // 口座引落しリクエスト
    }

    touch_start(integer total_number)
    {
        key id=llDetectedKey(0);  // タッチしたアバターのキー
        if (id == llGetOwner()) {  // オーナーだったら
            // 口座引落しが許可されてなかったら再リクエスト
            if (!(llGetPermissions() & PERMISSION_DEBIT)) llRequestPermissions(id,PERMISSION_DEBIT);
        }
    }

    run_time_permissions(integer perm)
    {
        if (perm & PERMISSION_DEBIT)
        {  // 口座引落し許可されたら
            set_pay(TRUE);  // 支払いダイアログ設定
        }
    }

    money(key id, integer amount)
    {  // 支払いが発生したら
        string item=llGetInventoryName(INVENTORY_OBJECT,0);  // コンテンツ内の最初のオブジェクト
        if (llList2Key(llGetObjectDetails(llGetKey(),[OBJECT_GROUP]),0) == NULL_KEY) {  // グループ設定されてなかったら
            llGiveMoney(id,amount);  // 返金
            llWhisper(0,"Error - owner must set a group.");  // グループ未設定エラー
        }
        else if (llGetInventoryType(item) == INVENTORY_NONE) {  // オブジェクトが入ってなかったら
            llGiveMoney(id,amount);  // 返金
            llWhisper(0,"Error - object not found.");  // オブジェクトが見つからないエラー
        }
        else if (amount != price) {  // 支払い額が価格と一致しないとき
            llGiveMoney(id,amount);  // 返金
            llWhisper(0,"Error - illegal amount.");  // 不正な金額ですエラー
        }
        else {  // エラーじゃないとき
            if (llSameGroup(id)) {  // グループが同じだったら
                llGiveInventory(id,item);  // 商品を渡す
                llInstantMessage(id,"Thank you!!");  // サンキュー^^
            }
            else {  // グループが同じじゃない
                llGiveMoney(id,amount);  // 返金
                llInstantMessage(id,"Sorry, group member only.");  // グループ専用です
            }
        }
    }
}

スクリプトの価格のところだけ設定して、コンテンツ内に商品のオブジェクトを1個入れてください。オブジェクトが複数のときやオブジェクト以外のアイテムのときは箱詰めしてくださいね。そして忘れないようベンダーにグループをセットしてご使用ください。

他のグループ限定スクリプト同様、設置場所が自分名義の土地でない場合は使えないことが多いです。(異なるグループは自動返却される土地設定が多いので)

5月14日追記: 不正な額の支払いが起きたときのエラーを追加しました。

2011年4月20日水曜日

/* ←こんなコメント→ */

最近LSL Wiki : commentを何となく見て知ったんですが、LSLもCとかでよくある /* と */ で括るコメントが使えるんですね。

たくさんの行をまとめてコメントアウトするときとか便利なのに今まで知らなかった。。。っていうか、LSL始めて間もないころ試そうとしたことがあったんですが、書いても//みたいに色が変わらないので使えないんだと思ってたんですよ^^;

2011年2月4日金曜日

Rezzer HUDのスクリプト

空中で辺りに足場も何もない場所にオブジェクトをrezしたいときってありますよね? 今回はそんなときにちょっと便利なRezzer HUDのスクリプトです^^

HUDをタッチで自分の前1mくらいの位置にオブジェクトがrezされます。

// Rezzer HUD
vector offset=<1,0,0>;  // Rezする位置(自分の位置を基準にして相対的な値)

default
{
    touch_start(integer total_number)
    {  // タッチされたら
        key id=llDetectedKey(0);  // アバターのキー取得
        if (id == llGetOwner()) {  // オーナーだったら
            string obj=llGetInventoryName(INVENTORY_OBJECT,0);  // コンテンツ内の最初のオブジェクト名
            if (obj) {
                vector pos=llGetPos();  // 現在位置取得
                rotation rot=llList2Rot(llGetObjectDetails(id,[OBJECT_ROT]),0);  // 向き(回転)を取得
                llRezObject(obj,pos+offset*rot,ZERO_VECTOR,ZERO_ROTATION,0);  // オフセット値を加えてrez
            }
            else {  // オブジェクトが入ってなかったら
              llOwnerSay("Error オブジェクトが入ってないです");
            }
        }
    }
}

ローテーションを含めた位置計算が何かあまり理解できてないんですけど(いつも試行錯誤しながらやってますw)、まあそれ以外はめっちゃ簡単ですね^^;

コンテンツ内にrezしたいオブジェクトを入れてご使用ください。土地のチェックとかはしてないので、オブジェクト作成不能な場所ではスクリプトエラーが出ます。

ところでずっと思ってたんですけど、rezって発音は「レズ」でいいんですよね? でも仮名で書いちゃうとSL知らない人が見たら、誤解とかもあるんじゃないかなって気もしますね?www