summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRider Linden <rider@lindenlab.com>2026-03-04 15:08:11 -0800
committerGitHub <noreply@github.com>2026-03-04 15:08:11 -0800
commitccc10aeda7a3db0fd53cb249b24d22049bae1b94 (patch)
tree0e8c853be11efac8a3ab9f7155ba32238b3635fd
parent2d77fdc672f52f36e511af52ae5b1f678799171d (diff)
parent0c289bf27dcc40b9f41152b60408fa047ccf6f65 (diff)
Merge pull request #5383 from secondlife/rider/default_script
Rider/default script
-rw-r--r--indra/llinventory/llinventory.h8
-rw-r--r--indra/llinventory/llinventorydefines.h5
-rw-r--r--indra/llinventory/llinventorytype.h7
-rw-r--r--indra/newview/llpanelcontents.cpp107
-rw-r--r--indra/newview/llpreviewscript.h4
-rw-r--r--indra/newview/llsyntaxid.cpp11
-rw-r--r--indra/newview/lltooldraganddrop.cpp2
-rw-r--r--indra/newview/llviewerinventory.cpp64
-rw-r--r--indra/newview/llviewerinventory.h4
-rw-r--r--indra/newview/llviewerobject.cpp22
-rw-r--r--indra/newview/llviewerobject.h10
-rw-r--r--scripts/messages/message_template.msg4
-rw-r--r--scripts/messages/message_template.msg.sha12
13 files changed, 76 insertions, 174 deletions
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 181c46226c..58dea83617 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -24,11 +24,11 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLINVENTORY_H
-#define LL_LLINVENTORY_H
+#pragma once
#include "llfoldertype.h"
#include "llinventorytype.h"
+#include "llinventorydefines.h"
#include "llpermissions.h"
#include "llrefcount.h"
#include "llsaleinfo.h"
@@ -166,6 +166,7 @@ public:
virtual const std::string& getActualDescription() const; // Does not follow links
virtual const LLSaleInfo& getSaleInfo() const;
virtual LLInventoryType::EType getInventoryType() const;
+ virtual U8 getInventorySubType() const { return getFlags() & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK; }
virtual U32 getFlags() const;
virtual time_t getCreationDate() const;
virtual U32 getCRC32() const; // really more of a checksum.
@@ -182,6 +183,7 @@ public:
void setSaleInfo(const LLSaleInfo& sale_info);
void setPermissions(const LLPermissions& perm);
void setInventoryType(LLInventoryType::EType inv_type);
+ void setInventorySubType(U8 sub_type) { setFlags((getFlags() & ~LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK) | (sub_type & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK)); }
void setFlags(U32 flags);
void setCreator(const LLUUID& creator); // only used for calling cards
@@ -294,5 +296,3 @@ protected:
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat);
-
-#endif // LL_LLINVENTORY_H
diff --git a/indra/llinventory/llinventorydefines.h b/indra/llinventory/llinventorydefines.h
index 8e7bd87ac4..9088d172d9 100644
--- a/indra/llinventory/llinventorydefines.h
+++ b/indra/llinventory/llinventorydefines.h
@@ -24,8 +24,7 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLINVENTORYDEFINES_H
-#define LL_LLINVENTORYDEFINES_H
+#pragma once
// Consts for "key" field in the task inventory update message
extern const U8 TASK_INVENTORY_ITEM_KEY;
@@ -97,5 +96,3 @@ public:
// on a pre-existing inventory item (DEV-28098 and DEV-30997)
};
};
-
-#endif // LL_LLINVENTORYDEFINES_H
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index c90f8aa107..0627b8df3c 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -150,6 +150,13 @@ private:
~LLInventoryType( void );
};
+// Subtypes for scripts, (inventory type IT_LSL).
+enum ScriptSubtype_t
+{
+ SST_LSL = 0,
+ SST_LUA = 1
+};
+
// helper function that returns true if inventory type and asset type
// are potentially compatible. For example, an attachment must be an
// object, but a wearable can be a bodypart or clothing asset.
diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp
index bc99899c27..2e4dc88217 100644
--- a/indra/newview/llpanelcontents.cpp
+++ b/indra/newview/llpanelcontents.cpp
@@ -221,19 +221,6 @@ void LLPanelContents::clearContents()
// Static functions
//
-// See below comment in `onClickNewScript()` about this hack :(
-static const std::string DEFAULT_SLUA_SCRIPT = R"(
-function LLEvents.touch_start(detected)
- ll.Say(0, "Touched.")
-end
-
-local function main()
- print("Hello, Avatar!")
-end
-
-main()
-)";
-
// static
void LLPanelContents::onClickNewScript(void *userdata)
{
@@ -254,20 +241,9 @@ void LLPanelContents::onClickNewScript(void *userdata)
std::string desc;
LLViewerAssetType::generateDescriptionFor(LLAssetType::AT_LSL_TEXT, desc);
- // --------------------------------------------------------------------------------------------------
- // Begin hack
- //
- // The current state of the server doesn't allow specifying a default script template,
- // so we have to update its code immediately after creation instead.
- //
- // Moreover, _PREHASH_RezScript has more complex server-side logic than _PREHASH_CreateInventoryItem,
- // which changes the item's attributes, such as its name and UUID. The simplest way to mitigate this
- // is to create a temporary item in the user's inventory, modify it as in create_inventory_item()'s
- // callback, and then call _PREHASH_RezScript to move it into the object's inventory.
- //
- // This temporary workaround should be removed after a server-side fix.
- // See https://github.com/secondlife/viewer/issues/3731 for more information.
- //
+ U8 script_language = SST_LSL;
+ LLUUID template_id;
+
LLViewerRegion* region = object->getRegion();
if (region && region->simulatorFeaturesReceived())
{
@@ -275,78 +251,11 @@ void LLPanelContents::onClickNewScript(void *userdata)
region->getSimulatorFeatures(simulatorFeatures);
if (simulatorFeatures["LuaScriptsEnabled"].asBoolean())
{
- if (std::string::size_type pos = desc.find("lsl2"); pos != std::string::npos)
- {
- desc.replace(pos, 4, "SLua");
- }
-
- auto scriptCreationCallback = [object](const LLUUID& inv_item)
- {
- if (!inv_item.isNull())
- {
- LLViewerInventoryItem* item = gInventory.getItem(inv_item);
- if (item)
- {
- auto scriptUploadFinished = [object, item](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response)
- {
- LLPointer<LLViewerInventoryItem> new_script = new LLViewerInventoryItem(item);
- object->saveScript(new_script, true, true);
-
- // Delete the temporary item from the user's inventory after rezzing it in the object's inventory
- ms_sleep(50);
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RemoveInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
- gAgent.sendReliableMessage();
-
- gInventory.deleteObject(item->getUUID());
- gInventory.notifyObservers();
- };
-
- std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
- if (!url.empty())
- {
- LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLScriptAssetUpload>(
- item->getUUID(),
- "luau",
- DEFAULT_SLUA_SCRIPT,
- scriptUploadFinished,
- nullptr));
-
- LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
- }
- }
- }
- };
- LLPointer<LLBoostFuncInventoryCallback> cb = new LLBoostFuncInventoryCallback(scriptCreationCallback);
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_CreateInventoryItem);
- msg->nextBlock(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlock(_PREHASH_InventoryBlock);
- msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
- msg->addUUIDFast(_PREHASH_FolderID, gInventory.getRootFolderID());
- msg->addUUIDFast(_PREHASH_TransactionID, LLTransactionID::tnull);
- msg->addU32Fast(_PREHASH_NextOwnerMask, PERM_MOVE | PERM_TRANSFER);
- msg->addS8Fast(_PREHASH_Type, LLAssetType::AT_LSL_TEXT);
- msg->addS8Fast(_PREHASH_InvType, LLInventoryType::IT_LSL);
- msg->addU8Fast(_PREHASH_WearableType, NO_INV_SUBTYPE);
- msg->addStringFast(_PREHASH_Name, "New Script");
- msg->addStringFast(_PREHASH_Description, desc);
-
- gAgent.sendReliableMessage();
- return;
+ script_language = SST_LUA;
}
}
- //
- // End hack
- // --------------------------------------------------------------------------------------------------
+ // *TODO* Get a template ID and script_language based on user preferences. Template ID is the inventory item UUID of a script
+ // in the user's inventory that is used as a template for new scripts.
LLPointer<LLViewerInventoryItem> new_item =
new LLViewerInventoryItem(
@@ -359,9 +268,9 @@ void LLPanelContents::onClickNewScript(void *userdata)
"New Script",
desc,
LLSaleInfo::DEFAULT,
- LLInventoryItemFlags::II_FLAGS_NONE,
+ LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK & script_language,
time_corrected());
- object->saveScript(new_item, true, true);
+ object->saveScript(new_item, true, true, template_id);
std::string name = new_item->getName();
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index a85837065e..909e2183c2 100644
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -24,8 +24,7 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLPREVIEWSCRIPT_H
-#define LL_LLPREVIEWSCRIPT_H
+#pragma once
#include "llpreview.h"
#include "lltabcontainer.h"
@@ -377,4 +376,3 @@ private:
std::string mObjectName;
};
-#endif // LL_LLPREVIEWSCRIPT_H
diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp
index d9b2726992..16274f59bc 100644
--- a/indra/newview/llsyntaxid.cpp
+++ b/indra/newview/llsyntaxid.cpp
@@ -148,9 +148,14 @@ void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec)
if (isSupportedVersion(result))
{
- setKeywordsXml(result);
- cacheFile(fileSpec, result);
- loadKeywordsIntoLLSD();
+ // Shuttle this task to the main coro/worker.
+ // loadKeywordsIntoLLSD will attempt to get a mutex which is not coro aware.
+ LLAppViewer::instance()->postToMainCoro([this, result, fileSpec]()
+ {
+ setKeywordsXml(result);
+ cacheFile(fileSpec, result);
+ loadKeywordsIntoLLSD();
+ });
}
else
{
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 5e2d91d31e..eb8ace339e 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1828,7 +1828,7 @@ void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj,
}
}
}
- hit_obj->saveScript(new_script, active, true);
+ hit_obj->saveScript(new_script, active, true, LLUUID::null);
if (gFloaterTools)
{
gFloaterTools->dirty();
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 4d91b7675d..53d87e2869 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -1016,19 +1016,6 @@ void set_default_permissions(LLViewerInventoryItem* item, std::string perm_type)
}
}
-// See below comment in `create_script_cb()` about this hack :(
-static const std::string DEFAULT_SLUA_SCRIPT = R"(
-function LLEvents.touch_start(detected)
- ll.Say(0, "Touched.")
-end
-
-local function main()
- print("Hello, Avatar!")
-end
-
-main()
-)";
-
void create_script_cb(const LLUUID& inv_item)
{
if (!inv_item.isNull())
@@ -1036,40 +1023,6 @@ void create_script_cb(const LLUUID& inv_item)
LLViewerInventoryItem* item = gInventory.getItem(inv_item);
if (item)
{
- // ------------------------------------------------------------------------------------
- // Begin hack
- //
- // The current state of the server doesn't allow specifying a default script template,
- // so we have to update its code immediately after creation instead.
- //
- // This temporary workaround should be removed after a server-side fix.
- // See https://github.com/secondlife/viewer/issues/3731 for more information.
- //
- LLViewerRegion* region = gAgent.getRegion();
- if (region && region->simulatorFeaturesReceived())
- {
- LLSD simulatorFeatures;
- region->getSimulatorFeatures(simulatorFeatures);
- if (simulatorFeatures["LuaScriptsEnabled"].asBoolean())
- {
- std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent");
- if (!url.empty())
- {
- LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLScriptAssetUpload>(
- item->getUUID(),
- "luau",
- DEFAULT_SLUA_SCRIPT,
- nullptr,
- nullptr));
-
- LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
- }
- }
- }
- //
- // End hack
- // ------------------------------------------------------------------------------------
-
set_default_permissions(item, "Scripts");
// item was just created, update even if permissions did not changed
@@ -1763,6 +1716,7 @@ void create_new_item(const std::string& name,
std::function<void(const LLUUID&)> created_cb = nullptr)
{
std::string desc;
+ U8 subtype = NO_INV_SUBTYPE;
LLViewerAssetType::generateDescriptionFor(asset_type, desc);
next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER;
@@ -1774,6 +1728,20 @@ void create_new_item(const std::string& name,
{
cb = new LLBoostFuncInventoryCallback(create_script_cb);
next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Scripts");
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region && region->simulatorFeaturesReceived())
+ {
+ // *TODO* Setting the subtype for the script will cause the server to select
+ // either the LSL or Lua default script. We should perhaps allow the user to
+ // select which type of script they want to create.
+ LLSD simulatorFeatures;
+ region->getSimulatorFeatures(simulatorFeatures);
+ if (simulatorFeatures["LuaScriptsEnabled"].asBoolean())
+ {
+ subtype = SST_LUA;
+ }
+ }
break;
}
@@ -1816,7 +1784,7 @@ void create_new_item(const std::string& name,
desc,
asset_type,
inv_type,
- NO_INV_SUBTYPE,
+ subtype,
next_owner_perm,
cb);
}
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index a42bdaa2b0..23f85663e8 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -42,6 +42,8 @@ class LLViewerInventoryCategory;
class LLInventoryCallback;
class LLAvatarName;
+constexpr U8 NO_INV_SUBTYPE{ 0 };
+
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLViewerInventoryItem
//
@@ -359,8 +361,6 @@ public:
extern LLInventoryCallbackManager gInventoryCallbacks;
-const U8 NO_INV_SUBTYPE{ 0 };
-
// *TODO: Find a home for these
void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id,
const LLUUID& parent, const LLTransactionID& transaction_id,
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 0f4cbdd25c..d280f74fc7 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2762,10 +2762,15 @@ void LLViewerObject::doUpdateInventory(
// save a script, which involves removing the old one, and rezzing
// in the new one. This method should be called with the asset id
// of the new and old script AFTER the bytecode has been saved.
-void LLViewerObject::saveScript(
- const LLViewerInventoryItem* item,
- bool active,
- bool is_new)
+// When creating a new script, the asset should be null. The server
+// will create the new script based on the script_language (LSL or Lua)
+// If a template_id is provided, the new script will be a copy of that item.
+//
+// *IMPORTANT* If template_id is provided, it must be the ITEM ID of a
+// copy/mod-able script in the user's inventory. The simulator will verify
+// permissions.
+void LLViewerObject::saveScript(const LLViewerInventoryItem* item,
+ bool active, bool is_new, const LLUUID& template_id)
{
/*
* XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the
@@ -2794,6 +2799,15 @@ void LLViewerObject::saveScript(
msg->addBOOLFast(_PREHASH_Enabled, enabled);
msg->nextBlockFast(_PREHASH_InventoryBlock);
task_item->packMessage(msg);
+
+ // This is a completely new script (no asset id) and we've provided a template.
+ // Note that the script subtype on the template will override any subtype on the item.
+ if (task_item->getAssetUUID().isNull() && template_id.notNull())
+ {
+ msg->nextBlock("NewScriptInfo");
+ msg->addUUID("TemplateID", template_id);
+ }
+
msg->sendReliable(mRegionp->getHost());
// do the internal logic
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index cccf59a319..db1a412c78 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -25,8 +25,7 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLVIEWEROBJECT_H
-#define LL_LLVIEWEROBJECT_H
+#pragma once
#include <map>
#include <unordered_map>
@@ -549,7 +548,10 @@ public:
// save a script, which involves removing the old one, and rezzing
// in the new one. This method should be called with the asset id
// of the new and old script AFTER the bytecode has been saved.
- void saveScript(const LLViewerInventoryItem* item, bool active, bool is_new);
+ // The simulator treats the script as new when item->getAssetUUID().isNull() is true; in that case
+ // template_id will be used (if non-null) to copy an existing script asset, otherwise the
+ // script subtype in the item will be used to select the correct template.
+ void saveScript(const LLViewerInventoryItem* item, bool active, bool is_new, const LLUUID& template_id);
// move an inventory item out of the task and into agent
// inventory. This operation is based on messaging. No permissions
@@ -1102,5 +1104,3 @@ public:
virtual void updateDrawable(bool force_damped);
};
-
-#endif
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index 40ba2cc6b6..ad3ddd5a94 100644
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -6818,6 +6818,10 @@ version 2.0
{ CreationDate S32 }
{ CRC U32 }
}
+ {
+ NewScriptInfo Variable
+ { TemplateID LLUUID }
+ }
}
// Create inventory
diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1
index baa4f3f12b..96f24ca1ba 100644
--- a/scripts/messages/message_template.msg.sha1
+++ b/scripts/messages/message_template.msg.sha1
@@ -1 +1 @@
-aaecaf01b6954c156662f572dc3ecaf26de0ca67 \ No newline at end of file
+3edf45c784a5440d7dd24c59309faf52d1d01f47 \ No newline at end of file