Difference between revisions of "LlLinksetDataWrite/ja"

From Second Life Wiki
Jump to navigation Jump to search
m
m
 
Line 2: Line 2:
|default={{{default|}}}
|default={{{default|}}}
|inject-2=
|inject-2=
|summary=The '''llLinksetDataWrite''' and '''llLinksetDataWriteProtected''' functions create or update a '''name:value''' pair in the linkset datastore. The linkset datastore is a semi-permanent key-value store that is retained as a prim property regardless of whether the script is deleted or reset (via manual reset, [[llResetScript]], [[llResetOtherScript]], or cloning the object). If {{LSLP|value}} is an empty string, the pair is deleted.
|summary= '''llLinksetDataWrite''' および '''llLinksetDataWriteProtected''' 関数は、linkset データストア内の '''name:value''' ペアを作成または更新します。linkset データストアは、スクリプトが削除またはリセットされても(手動リセット、[[llResetScript]][[llResetOtherScript]]、またはオブジェクトのクローンを介して)、プリムのプロパティとして保持される半永久的なキー値ストアです。{{LSLP|value}} が空の文字列の場合、ペアは削除されます。


This function returns 0 on success or an error code on failure.
この関数は成功時には0を、失敗時にはエラーコードを返します。


When these functions are called, the [[linkset_data]] event is triggered in all scripts running in the linkset with an action of [[Template:LSL_Constants_Linkset_Data|LINKSETDATA_UPDATE]], or [[Template:LSL_Constants_Linkset_Data|LINKSETDATA_DELETE]] if the pair is deleted.
これらの関数が呼び出されると、[[linkset_data]] イベントが linkset 内で実行されているすべてのスクリプトで [[Template:LSL_Constants_Linkset_Data|LINKSETDATA_UPDATE]] アクションでトリガーされ、ペアが削除される場合は [[Template:LSL_Constants_Linkset_Data|LINKSETDATA_DELETE]] アクションでトリガーされます。


The linkset datastore can contain up to 131072 bytes (128 KiB) of data and has no impact on script memory usage aside from the functions and events used to interact with it.  Every pair written to the datastore consumes a number of bytes in the datastore equal to the length of {{LSLP|name}} plus the length of {{LSLP|value}}, plus an additional 32 bytes if written using '''llLinksetDataWriteProtected'''.
linkset データストアには最大で131072バイト(128 KiB)のデータを格納でき、関数とそれとやり取りするためのイベント以外のスクリプトメモリ使用量には影響しません。データストアに書き込まれる各ペアは、{{LSLP|name}} の長さと {{LSLP|value}} の長さに加えて、'''llLinksetDataWriteProtected''' を使用して書き込まれる場合は追加で32バイト消費します。


|constants={{LSL Constants Linkset_Data Returns}}
|constants={{LSL Constants Linkset_Data Returns}}
Line 17: Line 17:
|func=llLinksetDataWrite
|func=llLinksetDataWrite
|return_type=integer
|return_type=integer
|return_text=success or failure code.
|return_text=成功時は0、失敗時はエラーコード。
|p1_type=string|p1_name=name|p1_desc=The key of the '''name:value''' pair in the datastore to be updated or created.
|p1_type=string|p1_name=name|p1_desc=データストア内の '''name:value''' ペアのキー、更新または作成するもの。
|p2_type=string|p2_name=value|p2_desc=The '''value''' of the '''name:value''' pair.
|p2_type=string|p2_name=value|p2_desc= '''name:value''' ペアの '''value'''
|func_desc=Creates or updates an unprotected '''name:value''' pair from the linkset's datastore.
|func_desc=データストアから保護されていない '''name:value''' ペアを作成または更新します。
}}{{LSL_Function/Head
}}{{LSL_Function/Head
|func_sleep=0.0|func_energy=10.0
|func_sleep=0.0|func_energy=10.0
Line 26: Line 26:
|p1_type=string|p1_name=name|p1_desc=
|p1_type=string|p1_name=name|p1_desc=
|p2_type=string|p2_name=value|p2_desc=
|p2_type=string|p2_name=value|p2_desc=
|p3_type=string|p3_name=pass|p3_desc=A pass phrase used to protect the '''name:value''' pair.
|p3_type=string|p3_name=pass|p3_desc='''name:value''' ペアを保護するために使用されるパスフレーズ。
|return_type=integer
|return_type=integer
|return_text=success or failure code.
|return_text=成功時は0、失敗時はエラーコード。
|func_footnote
|func_footnote
|func_desc=Creates or updates a protected '''name:value''' pair from the linkset's datastore. Further attempts to read, write or update the '''name:value''' pair must use the protected versions of those functions and must supply the same string that was used in {{LSLP|pass}}.
|func_desc=データストアから保護された '''name:value''' ペアを作成または更新します。データストアから '''name:value''' ペアを読み取る、書き込む、または更新する場合は、これらの関数の保護バージョンを使用し、{{LSLP|pass}} で指定された文字列を同じものとする必要があります。
|func_footnote
|func_footnote
|caveats=
|caveats=
* Protecting a '''name:value''' pair adds an additional 32 bytes to its size in the datastore regardless of the length of {{LSLP|pass}}. The length of {{LSLP|pass}} itself is not counted against the data storage limit.
* '''name:value''' ペアを保護すると、そのサイズが {{LSLP|pass}} の長さにかかわらず追加で32バイト増加します。 {{LSLP|pass}} の長さ自体はデータストアの制限に含まれません。
* When writing a protected name, the [[linkset_data]] event fires as normal, however the value parameter will be an empty string.
* 保護された名前を書き込むと、[[linkset_data]] イベントは通常通りトリガーされますが、value パラメータは空の文字列になります。
}}
}}
|caveats=
|caveats=
* Events are only fired if the linkset's datastore is changed.
* イベントは linkset データストアが変更された場合のみトリガーされます。
** Rewriting an existing value to a '''name:value''' pair returns LINKSETDATA_NOUPDATE.
** 既存の値を '''name:value''' ペアに書き換えると LINKSETDATA_NOUPDATE が返されます。
** Writing an empty string to a nonexistent name in the datastore returns LINKSETDATA_NOTFOUND.
** データストアに存在しない名前に空の文字列を書き込むと LINKSETDATA_NOTFOUND が返されます。
* There is currently no way to write to or read from a linkset datastore from another linkset.
* 現在、別の linkset から linkset データストアに書き込みまたは読み込む方法はありません。
* The datastore is accessible from the entire linkset but acts as a property of the root prim alone. Therefore, linking and unlinking prims produces the following results:
* データストアは linkset 全体からアクセスできますが、単独で root prim のプロパティとして機能します。したがって、プリムのリンクおよびアンリンクを行うと次の結果が生じます。
** When linking one linkset to another linkset, the combined linkset datastore includes all pairs from both datastores.
** linkset を別の linkset にリンクする場合、結合された linkset データストアには両方のデータストアのすべてのペアが含まれます。
*** If any pairs have conflicting {{LSLP|name}}s, the combined linkset datastore will keep the pair from the original linkset and will silently drop conflicting pairs from newly added prim(s).
*** いくつかのペアで {{LSLP|name}} が競合する場合、結合された linkset データストアは元の linkset からのペアを保持し、新しく追加されたプリムの競合するペアは無言で破棄されます。
*** If the combined linkset datastore would exceed 131072 bytes, pairs from the newly linked prim(s) will be added to the combined linkset datastore up to the limit. It is not currently clear in what order pairs are added, so there is no way to predict which will be dropped.
*** 結合された linkset データストアが131072バイトを超える場合、新しく追加されたプリムからのペアが限界まで結合された linkset データストアに追加されます。現在のところ、どの順序でペアが追加されるかは不明なため、削除されるペアを予測する方法はありません。
** When unlinking a child prim from a linkset, the datastore remains in the original linkset and the child prim (now its own root prim) has an empty datastore.
** linkset から子プリムをアンリンクすると、データストアは元の linkset に残り、子プリム(現在は独自の root prim)は空のデータストアを持ちます。
*** If the datastore is too large to cache in a script to be rewritten after unlinking, you may need to devise a custom method of porting the datastore from the original linkset to the child prim, if necessary.
*** データストアがアンリンク後に書き換えるためにスクリプトにキャッシュするには、データストアが元の linkset から子プリムに移動するためのカスタムメソッドを考案する必要があるかもしれません。
** When unlinking a root prim from a linkset, the datastore remains in the newly-unlinked root prim and the remaining prims in the original linkset have an empty datastore.
** linkset から root prim をアンリンクすると、データストアは新しくアンリンクされた root prim に残り、元の linkset の残りのプリムは空のデータストアを持ちます。
* There is no limit on the size of {{LSLP|value}} aside from the total datastore limit, so care should be taken when writing very large values that could crash other scripts in the linkset via [[linkset_data]].
* {{LSLP|value}} のサイズにはデータストアの合計制限以外の制限はありませんので、非常に大きな値を書き込むと他のスクリプトを [[linkset_data]] 経由でクラッシュさせる可能性があるため注意が必要です。
** If a script does not define a [[linkset_data]] event, it will not load any event parameters into its memory when the datastore is written to, so the script should not crash from another script in the linkset writing to the datastore.
** スクリプトが [[linkset_data]] イベントを定義していない場合、データストアが書き込まれたときにメモリにイベントパラメータをロードしないため、スクリプトは他のスクリプトからのデータストアへの書き込みからクラッシュするべきではありません。
** If this is a possible risk, consider using '''llLinksetDataWriteProtected''', which does not send {{LSLP|value}} in [[linkset_data]], with a static {{LSLP|pass}}.
** これが可能なリスクである場合は、静的な {{LSLP|pass}} を使用した '''llLinksetDataWriteProtected''' を考慮してください。
* It is possible for data to be rolled back to a previous state if the datastore is stored in an object that is restored via a simulator rollback, or in an attachment that is not properly saved back to the server on logout.
* シミュレータのロールバックを介して復元されるオブジェクト、またはログアウト時に正しくサーバーに保存されないアタッチメント内のデータストアにデータがロールバックされる可能性があります。
** Viewer crashes can cause attachment states to not be saved, so care should be taken when using these functions in attachments, because datastore rollbacks are likely to occur on occasion for attachments.
** ビューアのクラッシュによりアタッチメントの状態が保存されないことがありますので、アタッチメントでこれらの関数を使用する場合はデータストアのロールバックが発生する可能性があります。
|examples=
|examples=
<syntaxhighlight lang="lsl2">
<syntaxhighlight lang="lsl2">
Line 271: Line 271:
|also_articles
|also_articles
|notes=
|notes=
* Linkset datastore operations are synchronous and are usually processed within one server frame. Therefore, it is possible to synchronize variables between multiple scripts using the datastore alone without resorting to [[llMessageLinked]], or to use the datastore directly as extended memory for specific workloads that need to work with extremely large datasets.
* Linkset データストアの操作は同期的であり、通常は1つのサーバーフレーム内で処理されます。したがって、[[llMessageLinked]] を使わずにデータストアだけを使用して複数のスクリプト間で変数を同期させることが可能であり、また、非常に大きなデータセットで作業する必要がある特定のワークロードに対してデータストアを直接拡張メモリとして使用することもできます。
|cat1=Script
|cat1=Script
|cat2=LinksetData
|cat2=LinksetData

Latest revision as of 12:54, 22 November 2023

Summary

Summary: llLinksetDataWrite, llLinksetDataWriteProtected

llLinksetDataWrite および llLinksetDataWriteProtected 関数は、linkset データストア内の name:value ペアを作成または更新します。linkset データストアは、スクリプトが削除またはリセットされても(手動リセット、llResetScriptllResetOtherScript、またはオブジェクトのクローンを介して)、プリムのプロパティとして保持される半永久的なキー値ストアです。value が空の文字列の場合、ペアは削除されます。

この関数は成功時には0を、失敗時にはエラーコードを返します。

これらの関数が呼び出されると、linkset_data イベントが linkset 内で実行されているすべてのスクリプトで LINKSETDATA_UPDATE アクションでトリガーされ、ペアが削除される場合は LINKSETDATA_DELETE アクションでトリガーされます。

linkset データストアには最大で131072バイト(128 KiB)のデータを格納でき、関数とそれとやり取りするためのイベント以外のスクリプトメモリ使用量には影響しません。データストアに書き込まれる各ペアは、name の長さと value の長さに加えて、llLinksetDataWriteProtected を使用して書き込まれる場合は追加で32バイト消費します。

llLinksetDataWrite

Function: integer llLinksetDataWrite( string name, string value );

データストアから保護されていない name:value ペアを作成または更新します。
Returns an integer 成功時は0、失敗時はエラーコード。

• string name データストア内の name:value ペアのキー、更新または作成するもの。
• string value name:value ペアの value
All Issues ~ Search JIRA for related Bugs

llLinksetDataWriteProtected

Function: integer llLinksetDataWriteProtected( string name, string value, string pass );

データストアから保護された name:value ペアを作成または更新します。データストアから name:value ペアを読み取る、書き込む、または更新する場合は、これらの関数の保護バージョンを使用し、pass で指定された文字列を同じものとする必要があります。
Returns an integer 成功時は0、失敗時はエラーコード。

• string name データストア内の name:value ペアのキー、更新または作成するもの。
• string value name:value ペアの value
• string pass name:value ペアを保護するために使用されるパスフレーズ。
Caveats
  • name:value ペアを保護すると、そのサイズが pass の長さにかかわらず追加で32バイト増加します。 pass の長さ自体はデータストアの制限に含まれません。
  • 保護された名前を書き込むと、linkset_data イベントは通常通りトリガーされますが、value パラメータは空の文字列になります。
All Issues ~ Search JIRA for related Bugs

Constant Description
LINKSETDATA_OK 0 The name:value pair was written to the datastore.
LINKSETDATA_EMEMORY 1 A name:value pair was too large to write to the linkset datastore.
LINKSETDATA_ENOKEY 2 The name supplied to llLinksetDataWrite was empty.
LINKSETDATA_EPROTECTED 3 The name:value pair has been protected from overwrite in the linkset's datastore.
LINKSETDATA_NOTFOUND 4 The named key could not be found in the linkset's datastore when attempting to delete it.
LINKSETDATA_NOUPDATE 5 The name:value stored in the linkset was not changed by the write operation because the value stored matches the value written.

Caveats

  • イベントは linkset データストアが変更された場合のみトリガーされます。
    • 既存の値を name:value ペアに書き換えると LINKSETDATA_NOUPDATE が返されます。
    • データストアに存在しない名前に空の文字列を書き込むと LINKSETDATA_NOTFOUND が返されます。
  • 現在、別の linkset から linkset データストアに書き込みまたは読み込む方法はありません。
  • データストアは linkset 全体からアクセスできますが、単独で root prim のプロパティとして機能します。したがって、プリムのリンクおよびアンリンクを行うと次の結果が生じます。
    • linkset を別の linkset にリンクする場合、結合された linkset データストアには両方のデータストアのすべてのペアが含まれます。
      • いくつかのペアで name が競合する場合、結合された linkset データストアは元の linkset からのペアを保持し、新しく追加されたプリムの競合するペアは無言で破棄されます。
      • 結合された linkset データストアが131072バイトを超える場合、新しく追加されたプリムからのペアが限界まで結合された linkset データストアに追加されます。現在のところ、どの順序でペアが追加されるかは不明なため、削除されるペアを予測する方法はありません。
    • linkset から子プリムをアンリンクすると、データストアは元の linkset に残り、子プリム(現在は独自の root prim)は空のデータストアを持ちます。
      • データストアがアンリンク後に書き換えるためにスクリプトにキャッシュするには、データストアが元の linkset から子プリムに移動するためのカスタムメソッドを考案する必要があるかもしれません。
    • linkset から root prim をアンリンクすると、データストアは新しくアンリンクされた root prim に残り、元の linkset の残りのプリムは空のデータストアを持ちます。
  • value のサイズにはデータストアの合計制限以外の制限はありませんので、非常に大きな値を書き込むと他のスクリプトを linkset_data 経由でクラッシュさせる可能性があるため注意が必要です。
    • スクリプトが linkset_data イベントを定義していない場合、データストアが書き込まれたときにメモリにイベントパラメータをロードしないため、スクリプトは他のスクリプトからのデータストアへの書き込みからクラッシュするべきではありません。
    • これが可能なリスクである場合は、静的な pass を使用した llLinksetDataWriteProtected を考慮してください。
  • シミュレータのロールバックを介して復元されるオブジェクト、またはログアウト時に正しくサーバーに保存されないアタッチメント内のデータストアにデータがロールバックされる可能性があります。
    • ビューアのクラッシュによりアタッチメントの状態が保存されないことがありますので、アタッチメントでこれらの関数を使用する場合はデータストアのロールバックが発生する可能性があります。
All Issues ~ Search JIRA for related Bugs

Examples

default
{
    touch_start(integer num_detected)
    {
        llLinksetDataWrite("test-name", "See you on the other side!");
        llResetScript();
    }
    state_entry()
    {
        llOwnerSay(llLinksetDataRead("test-name")); // Should print "See you on the other side!" to the owner
    }
}

Useful Snippets

Securing Against Tampering

// While there is no "standard" for names, it's a good idea to take some steps to prevent against other scripts accidentally overwriting your data.
// Since the datastore is shared among the entire linkset, one way to avoid name conflicts is to include the prim's UUID in the data pair's name.
// This example also monitors for llLinksetDataReset/unlinks and refreshes the datastore in response, which is usually good practice if you want to keep your data!

key this_uuid;
string lsd_data;

default
{
    state_entry()
    {
        this_uuid = llGetKey(); // Save the current key into this_uuid for checking later
        lsd_data = "bar"; // Store the data locally so it can be rewritten if the datastore gets erased for whatever reason
        llLinksetDataWrite((string)llGetKey() + "-foo", lsd_data); // Write the data
    }
    on_rez(integer start_param)
    {
        if (llGetKey() != this_uuid)
        {
            // Prim UUID has changed!
            // This should always be the case when on_rez is called, but is included here for clarity.
            llLinksetDataWrite((string)llGetKey() + "-foo", llLinksetDataRead((string)this_uuid + "-foo")); // Read the data from the last prim UUID's pair and write it into this prim UUID's pair
            // Note that you could also just write the lsd_data string instead of calling llLinksetDataRead, but this method is theoretically a little more robust if you expect other scripts to manipulate the data.
            llLinksetDataDelete((string)this_uuid + "-foo"); // Erase the original data to free up memory
            this_uuid = llGetKey(); // Update the UUID variable to the new UUID
        }
    }
    linkset_data(integer action, string name, string value)
    {
        if (action == LINKSETDATA_UPDATE || action == LINKSETDATA_DELETE)
        {
            if (name == (string)llGetKey() + "-foo")
            {
                // Somebody else wrote to our pair - we'll just save it in case we need it later, but you could re-write the original data instead if desired.
                lsd_data = value; // Note that in the case of LINKSETDATA_DELETE, value will be an empty string (""), which may or may not be how you want to handle that case
            }
        }
        else if (action == LINKSETDATA_RESET) 
        {
            // Linkset datastore has been reset!
            llLinksetDataWrite((string)llGetKey() + "-foo", lsd_data); // Write the lsd_data string into this prim UUID's pair - in this case we can't use llLinksetDataRead because the datastore is empty
        }
    }
    changed(integer change)
    {
        if (change & CHANGED_LINK)
        {
            // Linkset has changed!
            // Generally, this can happen for a few reasons (see Caveats above), including when an avatar sits on the object. In certain circumstances, this resets the datastore.
            // However, since the linkset data functions are very quick, it is easier to just write the data on every change to be safe for this example whether or not the datastore was reset.
            llLinksetDataWrite((string)llGetKey() + "-foo", lsd_data); // Write the lsd_data string into this prim UUID's pair - in this case we can't use llLinksetDataRead because the datastore might be empty
        }
    }
}

Simple blacklist management

integer gDialogChannel;
integer gDialogHandle;
integer gManagingBlocks;

startDialog(key person)
{
    gManagingBlocks = 0;
    gDialogHandle = llListen(gDialogChannel, "", person, "");
    llDialog(person, "\nSelect action", ["List blocks", "Add block", "Remove block"], gDialogChannel);
    llSetTimerEvent(60);
}

stopDialog()
{
    llSetTimerEvent(0);
    llListenRemove(gDialogHandle);
}

default
{

    on_rez(integer sp)
    {
        llResetScript();
    }

    state_entry()
    {
        gDialogChannel = (integer)(llFrand(-10000000)-10000000);
        llListen(PUBLIC_CHANNEL, "", NULL_KEY, "");;
    }

    timer()
    {
        stopDialog();
    }

    touch_start(integer nd)
    {
        key toucherKey = llDetectedKey(0);
        if (toucherKey == llGetOwner())
        {
            startDialog(toucherKey);
        }
    }

    listen(integer channel, string name, key id, string message)
    {

        if (llGetAgentSize(id) == ZERO_VECTOR)
        {
            return;
        }

        if (channel == gDialogChannel)
        {
            stopDialog();
            if (gManagingBlocks)
            {
                message = llStringTrim(message, STRING_TRIM);
                if ((key)message)
                {
                    if (gManagingBlocks == 1)
                    {
                        llOwnerSay("Addition request has been sent to the blacklist storage");
                        llLinksetDataWrite("blocklist:" + message, "1");
                    }
                    else
                    {
                        llOwnerSay("Removal request has been sent to the blacklist storage.");
                        llLinksetDataDelete("blocklist:" + message);
                    }
                }
                else
                {
                    llOwnerSay("The UUID '" + message + "' appears to be invalid.");
                }
                startDialog(id);
            }
            else if (message == "List blocks")
            {
                list blocks = llLinksetDataFindKeys("^blocklist:", 0, 0);
                integer listLength = llGetListLength(blocks);
                llOwnerSay("Blacklist items: " + (string)listLength);
                integer i;
                while (i < listLength)
                {
                    string record = llGetSubString(llList2String(blocks, i), 10, -1);
                    llOwnerSay("- secondlife:///app/agent/" + record + "/about" + " - " + record);
                    ++i;
                }
                blocks = [];
                startDialog(id);
            }
            else if (message == "Add block" || message == "Remove block")
            {
                string label = "add to";
                gManagingBlocks = 1;
                if (message == "Remove block")
                {
                    gManagingBlocks = 2;
                    label = "remove from";
                }
                gDialogHandle = llListen(gDialogChannel, "", id, "");
                llTextBox(id, "\nPlease specify one single avatar UUID you'd like to " + label + " the blacklist storage.", gDialogChannel);
                llSetTimerEvent(60);
            }
            return;
        }

        if (llGetListLength(llLinksetDataFindKeys("blocklist:" + (string)id, 0, 1)) > 0)
        {
            llRegionSayTo(id, 0, "You're blacklisted.");
            return;
        }

        llRegionSayTo(id, 0, "Hello there, secondlife:///app/agent/" + (string)id + "/about - your message: " + message);

    }

    linkset_data(integer action, string name, string value)
    {
        if (action == LINKSETDATA_RESET || action == LINKSETDATA_DELETE || action == LINKSETDATA_UPDATE)
        {
            llOwnerSay("Blacklist storage modified.");
        }
    }

}

Notes

  • Linkset データストアの操作は同期的であり、通常は1つのサーバーフレーム内で処理されます。したがって、llMessageLinked を使わずにデータストアだけを使用して複数のスクリプト間で変数を同期させることが可能であり、また、非常に大きなデータセットで作業する必要がある特定のワークロードに対してデータストアを直接拡張メモリとして使用することもできます。

Deep Notes

Search JIRA for related Issues

Signature

function integer llLinksetDataWrite( string name, string value );
function integer llLinksetDataWriteProtected( string name, string value, string pass );