ソラマメブログ

2008年02月08日

別プリムにあるスクリプト間で定数を素直に共有できないか?

別なプリムにあるスクリプトで同じ定数を使いたい場合に、定数を変更するときのミスを減らしたい。
つまり、
スクリプトファイル外にある定数を素直に共有できないか?
つまり、
要求1:同じ意味の定数を変える場合は、変更するところは一箇所だけにしたい
要求2:タイプミスによるバグを減らしたい

例:オブジェクトAとBがチャンネルチャットで通信する場合には、
AでSayするチャンネルをBがlistenする必要がある。(同じチャンネル番号を使う必要がある)
このケースで、チャンネルを変えたい場合にどうするか。

[オブジェクトA]--------(ch.3)-------->[オブジェクトB]


結論:方法が無い。んじゃないかなぁ。


方法が無い理由:
C言語と比べてみる。C言語で書かれたソースファイルを実行できるようにするためには、
おおまかには以下の2つの手順が必要である。
(1)ソースファイルをコンパイルして、コンパイル済みオブジェクトファイルを作る
(2)コンパイル済みオブジェクトファイルをリンクして、実行ファイルを作る
この時に、以下の便利なことができる。
(1)では#include文により他のソースファイルを取り込む、
(2)ではextern宣言で型だけ決めてあった外部変数と、実際の定義(記憶領域の割付)を結びつける。

LSLにはこのような仕組みが無い。
(1)は、llRemoteLoadScriptPin関数で同じプリム内に入れることはできても、同じスクリプトファイルには入れられない。
(2)は、宣言(型を決める) = 定義(記憶領域の割付)で、この2つを分離できない。
このため、ヘッダファイルをincludeしたり、別なスクリプトで代入した変数を使ったりできない。


代替案:
案A:マジックワードとして、両方のスクリプトに数字を書く。
…一番素直。一番面倒。
案B:定数として定義する。両方のスクリプトに定数定義をコピペする。
原始的だがタイプミスは減らせる
案C:llLinkMessageで定数を得るスクリプトを書く。
…llRemoteLoadScriptPinで
…#includeとは違う!
…一見よさそうだが、スクリプト内でllLinkMessageを呼ぶ関数を書かなければならない。
 (スクリプト外の関数は呼び出せない)
……引数がマジックワードになる。
………コピペと同じ。
案D:ノートカードから取得する
…定数名をじかにかかなければならない(コンパイルエラーにはできない)
…定数が見つからないときのエラー処理や、処理のタイミング(起動時?)に注意すればいけるかも。
案E:外部サーバを使う
…外部サーバを呼び出す関数や、何が欲しいかを決めておく必要がある。llLinkMessageと同じ。
案F:既にある定数を無理やり使う
…PIとかCONTROL_BACKとか
……もはや「変更は一箇所で」という目的からずれている
案G:別スクリプトで同じstateを書いたら共有できるのではないか?
…1プリムに入っていても、スクリプトが別ならメモリ空間は別なので、共有できない。
案H:stateを上手に遷移させ、DESCやテクスチャオフセットなどでやりとりすればいけるかも。
…未検証。
…タイプミスは防げていない。



というわけで、リーズナブルなのは定数はスクリプトの頭にまとめておいてコピペする、
頑張るならノートカードから取得するのがいいんじゃないでしょうか。
間違いの指摘やご意見を歓迎します。
  

Posted by march at 00:22Comments(5)TrackBack(0)LSL

2007年06月25日

1.17でllGetNotecardLineで日本語取出せず

notecardのパブリック・ビューアを作ろうとしたが、
llEscapeURLしても日本語がとりだせない。
1.17で何か方法ないものか。


あさっての1.18まで待つか。
>* Fixed SVC-52: UTF-8 characters read from notecards are lost
で(多分)なおるだろう。  

Posted by march at 22:54Comments(3)TrackBack(0)LSL

2007年06月07日

メモリ管理には謎がある

"エースプログラマの uki-uki 日記"
「Second Life そんなネタふりされたら・・・・(LSL最適化) 」
http://blog.g-up.com/hidenori_goto/?s=2&b=11030

イベント内で、llOwnerSay( "Hello Avatar!" ); のような処理をしている場合、
>元の文字列が関数のコードブロックに直接保存されていますが、
>実行時にこれとは別にメモリ領域を確保する必要があるため、
>実質文字列長の倍の領域のメモリを消費していると考えることができます。
だそうで、グローバル変数のほうがメモリを節約できる。という記事。


なるべくローカル変数を使うようにしていた私には驚くような記事でした。
Stack-Heap Collision で悩んでいて、llGetFreeMemory() でいくつか実験して
よく分からなかったので別な手段で解決したのですが、
バイトコードやメモリの内容を調べる方法はあるんでしょうか^^?
  

Posted by march at 22:50Comments(0)TrackBack(0)LSL

2007年05月22日

複数スクリプト

複数スクリプトはlink_messageで連動できると教えてもらった。
1オブジェクト内なら受け渡しはどうにかなりそう。
今度試してみよう。
教えてくれたりおしゃべりにつきあってくれたりする人がいるのは嬉しいし有り難い。
  

Posted by march at 01:25Comments(0)TrackBack(0)LSL

2007年05月16日

llRegionSay()はどこでも届くのか不明

1.16.0(1)で入るllRegionSay()はオブジェクト間でregion-wideな通信ができるらしい。
どういうことなのかよく分からない。
オブジェクト編集で数値入力する欄に日本語で0を入れると落ちる場合があるのはどうにかしてもらいたい。  

Posted by march at 22:07Comments(0)TrackBack(0)LSL

2007年05月12日

「Limit 5 コンテスト」表彰式

「Limit 5 コンテスト」表彰式

22時まで投票受け付けで、その後に表彰式があった。
1,2位のMoranさんは1人としてカウントしたため、2位がManjiさんで
3位がmarch、4位がLeosoさんだった。



Moranさんのラーメンはとてもリアルで湯気まであがっていた。扇風機もなびいてるひもがいい雰囲気をだしていた。


Manjiさんのマイクスタンドはマイクの高さやポーズを変えられるなど親切な作りなうえ、説明看板も分かりやすかった。


私の掲示板は、もう少し小さめのほうが字がにじまなくてよかったかな?


Leosoさんの水と一緒に回れる噴水は座ってみるとゆったりとした気分になれてよかった。


個人的にはSheltさんのロボヘッドがカッコよかったと思う。



参加者の皆さんおつかれさまでした。  

Posted by march at 22:51Comments(0)TrackBack(0)LSL

2007年05月12日

ひとこと掲示板を漢字対応

漢字がちゃんと出るように直して、簡単なチェックをして、会場に置きなおした。
ASUKAグループに招待してもらったので、グループも指定した。

listは初期化時に72個しかアイテムを持てないのは知っていたので、区切って256個のキー追加。
すると、実行時にStack-Heap Collisionが出て動かない。
この辺を見ていくつか試す。
http://lslwiki.net/lslwiki/wakka.php?wakka=memory
デバッグチャンネルで言ってくれればいいのに、オブジェクトの発言として出るから最初は見逃してしまった。
結局リストの要素は16個のキーにしてif文を使ってだらだらと書くことにした。

  

Posted by march at 00:31Comments(0)TrackBack(0)LSL

2007年05月10日

「Limit 5 コンテスト」に作品を出した

「Limit 5 コンテスト」に作品を出した。
前から作っていた掲示板である。
漢字も対応だ!と意気込んだ。
さざなみフォントで16*16文字で256枚の画像を作って、
使いそうなところをuploadした所で力尽きた。
英数字と一部の漢字・記号しか表示できない状態である。需要があったらちゃんと漢字対応しよう。
自分のデザインセンスのなさには驚きと困惑をおぼえる。
 

台形プリムを使って3フェース表示させる方法はcheyさんに教えてもらった。
最初に思いついた人はアイデア賞モノだと思う。  

Posted by march at 22:10Comments(3)TrackBack(0)LSL

2007年05月07日

llRemoteLoadScriptPinで別スクリプト呼出

llRemoteLoadScriptPinで別スクリプト呼出

複数のスクリプトの扱いについて、情報が散逸しているので自分用にまとめる。
情報源は、http://wiki.secondlife.com/wiki/http://www.lslwiki.net/lslwiki/wakka.php
LSLGuide.pdf。
(間違いがあったら教えてください~)

・オブジェクト内には、スクリプト名のABC順に並べ変えられて格納される。
 大文字小文字は関係ない。
・一番上に格納されているスクリプトが実行される
・同じオブジェクトに入っているスクリプトを呼び出す際は、PINを指定しておかなくてOK。
 KEYもNULL_KEYでOK。
・別なオブジェクトに入っているスクリプトを呼ぶ場合は、呼び先がRezされている必要がある
 (インベントリに入っているだけではダメ)
・呼び出すタイミング(イベント)によって、動作が変わるので注意。下記の例参照。
 state_entry()で別スクリプトを呼び出すと、touch_start()の処理はinvokerが終わってからchild
 touch_start()で別スクリプトを呼び出すと、
 ・・・だと思ったが、いったんTakeしてからでないと、最後にオブジェクトに入れたスクリプト
 を最初に実行しているように見える。不明。
・PIN(Personal Identification Number)はinteger
・スクリプトをまたがって変数を受け渡す方法はなさそう。
 llRemoteLoadScriptPin関数の最後の引数を使えば、llGetStartParameter関数でintegerを受け取れる
 ID設定に使うなら、オブジェクトの属性としてllSetAlpha関数/llGetAlpha関数とかで受け渡したほうがいいかも。
・llRemoteLoadScriptPin関数の先頭の引数の「key target」に何を指定すればいいのかは不明。



//00Invoker-1 呼び出す側のスクリプトその1
default
{
state_entry()
{
llOwnerSay("rez " + llGetObjectName() + "with " + llGetScriptName());
llRemoteLoadScriptPin(NULL_KEY, "child-script", 3, FALSE, 0);
}

touch_start(integer total_number)
{
llOwnerSay("Touch start at " + llGetScriptName());
llOwnerSay("Touch end at " + llGetScriptName());
}
}


//00Invoker-2 呼び出す側のスクリプトその2
default
{
state_entry()
{
llOwnerSay("rez " + llGetObjectName() + "with " + llGetScriptName());
}

touch_start(integer total_number)
{
llOwnerSay("Touch start at " + llGetScriptName());
llRemoteLoadScriptPin(NULL_KEY, "child-script", 3, FALSE, 0);
llOwnerSay("Touch end at " + llGetScriptName());
}
}


//child-script 呼び出される側のスクリプト
default
{
state_entry()
{
llOwnerSay("rez " + llGetObjectName() + "with " + llGetScriptName());
}

touch_start(integer total_number)
{
llOwnerSay("Touch start at " + llGetScriptName());
llOwnerSay("Touch end at " + llGetScriptName());
}
}
  
続きを読む

Posted by march at 19:12Comments(0)TrackBack(0)LSL

2007年05月05日

文字の変わる箱

「/3 A」とかやると文字の変わる箱を作った。
余計なコードやデバッグ用のコードが残っているが、自分メモとして。
大半はパクリ。
フォントは東雲なんでとりあえず安心。




 



 


string texture;
float x;
float y;
float u;
float v;
integer xmax = 16;
integer ymax = 16;


integer LHandle;
integer CHANNEL = 3;
//--------
//see  http : // wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation
//--------
//Function: ord
//Returns the index of an ASCII character
integer ord(string chr)
{
    string ASCII = "                                 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    if(llStringLength(chr) != 1) return -1;
    if(chr == " ") return 32;
    return llSubStringIndex(ASCII, chr);
}


//Function:  DWord2Hex
//Converts a dword containted in a LSL integer to hexadecimal format.       
string DWord2Hex(integer m){
   
    string result;
    integer i = 0;
    integer index = 0;
   
    //Define character string [0-F] for use in building the hex.
    string characters = "0123456789ABCDEF";  
   
    //Step through 8 times, for a total of 32 bits, 8 nibbles, and 8 hexadecimal digits.
    for (i = 0; i < 8; i++){
        //Get a nibble by right-shifting and masking off 4 bits.
        index  = (m >> (i * 4)) & 0xF;
        //Grab character from the characters string at index position and add it to the result string.
        result = llInsertString(result, 0, llGetSubString(characters,index,index));
    }
   
    return result;
}


integer initialize()
{
    LHandle = llListen(CHANNEL, "", NULL_KEY, "");
    llListenControl(LHandle, TRUE);
    llSleep(0.5);
    llOwnerSay("listen start. ch=" + (string)CHANNEL);
    return 0;
}
vector ascii2pos(integer code)
{
    integer x;
    integer y;
    vector pos;
    //
    x = code % xmax;
    if(x > xmax || x < 0)
    {
        x = 0;
    }
    pos.x = (1.0 / xmax) * ((xmax / 2) - x - 0.5);
    pos.x *= (-1);
    //
    y = code / xmax;    //xmax is. NOT ymax.
    if(y > ymax || y < 0)
    {
        y = 0;
    }
    pos.y = (1.0 / ymax) * ((ymax / 2) - y - 0.5);
    //pos.y *= (-1);
    //
    return pos;
}


vector setAsciiTexture(integer code)
{
    vector pos = ascii2pos(code);
    llOffsetTexture(pos.x, pos.y, ALL_SIDES);
    llOwnerSay("setAsciiTexture " + (string)pos);
    //
    u = 1.0 / xmax;
    v = 1.0 / ymax;
    llScaleTexture(u, v, ALL_SIDES);      // kakudai
    return pos;
}


default
{
    state_entry()
    {
        //x = (1.0 / xmax) * -3.5;
        //y = (1.0 / ymax) * 6.5;
        //u = 1.0 / xmax;
        //v = 1.0 / ymax;
        //llOffsetTexture(x, y, ALL_SIDES);
        //llScaleTexture(u, v, ALL_SIDES);      // kakudai
        //llOwnerSay("x=" + (string)x + ",y=" + (string)y + ",u=" + (string)u + ",v=" + (string)v);
        //
        initialize();
    }
    listen(integer channel, string name, key id, string message)
    {
        string oneStr = llGetSubString(message, 0, 0);
        llOwnerSay("[" + oneStr + "] is " + (string)ord(oneStr) + ". 0x" + DWord2Hex(ord(oneStr)) + ".");
        llOwnerSay("[" + oneStr + "] is " + (string)ord(oneStr) + ". 0x" + DWord2Hex(ord(oneStr)) + ".");
        integer a = ord(oneStr);
        integer pos_x = a % 16;
        integer pos_y = a / 16;
        llOwnerSay((string)a + "=(" + (string)pos_x + "," + (string)pos_y +")");
        //
        llOwnerSay((string)ascii2pos(a));
        setAsciiTexture(a);
    }
}

  

Posted by march at 02:26Comments(0)TrackBack(0)LSL

2007年05月04日

コードの貼り付け

コードを貼ってみる。
キーワードを色付けとかはプラグインがいるのかな。

default
{
state_entry()
{
llSay(0, "Hello, Avatar!");
}

touch_start(integer total_number)
{
llSay(0, "Touched.");
}
}
  

Posted by march at 10:02Comments(0)TrackBack(0)LSL