diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs index b557ffe5f2..0271738aee 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs @@ -57,39 +57,36 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } /// - /// Return a xfer uploader if one does not already exist. + /// Return the xfer uploader for the given transaction. /// + /// + /// If an uploader does not already exist for this transaction then it is created, otherwise the existing + /// uploader is returned. + /// /// - /// - /// We must transfer the new asset ID into the uploader on creation, otherwise - /// we can see race conditions with other threads which can retrieve an item before it is updated with the new - /// asset id. - /// - /// - /// The xfer uploader requested. Null if one is already in existence. - /// FIXME: This is a bizarre thing to do, and is probably meant to signal an error condition if multiple - /// transfers are made. Needs to be corrected. - /// - public AssetXferUploader RequestXferUploader(UUID transactionID, UUID assetID) + /// The asset xfer uploader + public AssetXferUploader RequestXferUploader(UUID transactionID) { + AssetXferUploader uploader; + lock (XferUploaders) { if (!XferUploaders.ContainsKey(transactionID)) { - AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile); + uploader = new AssetXferUploader(this, m_Scene, transactionID, m_dumpAssetsToFile); // m_log.DebugFormat( // "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID); XferUploaders.Add(transactionID, uploader); - - return uploader; + } + else + { + uploader = XferUploaders[transactionID]; } } - m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID); - - return null; + return uploader; } public void HandleXfer(ulong xferID, uint packetID, byte[] data) @@ -151,115 +148,28 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction string description, string name, sbyte invType, sbyte type, byte wearableType, uint nextOwnerMask) { - AssetXferUploader uploader = null; + AssetXferUploader uploader = RequestXferUploader(transactionID); - lock (XferUploaders) - { - if (XferUploaders.ContainsKey(transactionID)) - uploader = XferUploaders[transactionID]; - } - - if (uploader != null) - uploader.RequestCreateInventoryItem( - remoteClient, transactionID, folderID, - callbackID, description, name, invType, type, - wearableType, nextOwnerMask); - else - m_log.ErrorFormat( - "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to create inventory item {1} from {2}", - transactionID, name, remoteClient.Name); - } - - /// - /// Get an uploaded asset. If the data is successfully retrieved, - /// the transaction will be removed. - /// - /// - /// The asset if the upload has completed, null if it has not. - private AssetBase GetTransactionAsset(UUID transactionID) - { - lock (XferUploaders) - { - if (XferUploaders.ContainsKey(transactionID)) - { - AssetXferUploader uploader = XferUploaders[transactionID]; - AssetBase asset = uploader.GetAssetData(); - RemoveXferUploader(transactionID); - - return asset; - } - } - - return null; + uploader.RequestCreateInventoryItem( + remoteClient, folderID, callbackID, + description, name, invType, type, wearableType, nextOwnerMask); } public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) { - AssetXferUploader uploader = null; + AssetXferUploader uploader = RequestXferUploader(transactionID); - lock (XferUploaders) - { - if (XferUploaders.ContainsKey(transactionID)) - uploader = XferUploaders[transactionID]; - } - - if (uploader != null) - { - AssetBase asset = GetTransactionAsset(transactionID); - - // Only legacy viewers use this, and they prefer CAPS, which - // we have, so this really never runs. - // Allow it, but only for "safe" types. - if ((InventoryType)item.InvType != InventoryType.Notecard && - (InventoryType)item.InvType != InventoryType.LSL) - return; - - if (asset != null) - { -// m_log.DebugFormat( -// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}", -// item.Name, part.Name, transactionID); - - asset.FullID = UUID.Random(); - asset.Name = item.Name; - asset.Description = item.Description; - asset.Type = (sbyte)item.Type; - item.AssetID = asset.FullID; - - m_Scene.AssetService.Store(asset); - } - } - else - { - m_log.ErrorFormat( - "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update task inventory item {1} in {2}", - transactionID, item.Name, part.Name); - } + uploader.RequestUpdateTaskInventoryItem(remoteClient, item); } public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) { - AssetXferUploader uploader = null; + AssetXferUploader uploader = RequestXferUploader(transactionID); - lock (XferUploaders) - { - if (XferUploaders.ContainsKey(transactionID)) - uploader = XferUploaders[transactionID]; - } - - if (uploader != null) - { - uploader.RequestUpdateInventoryItem(remoteClient, transactionID, item); - } - else - { - m_log.ErrorFormat( - "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update inventory item {1} for {2}", - transactionID, item.Name, remoteClient.Name); - } + uploader.RequestUpdateInventoryItem(remoteClient, item); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs index 708198923a..73d1f72b2a 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs @@ -215,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) { m_log.DebugFormat( - "[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", + "[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); AgentAssetTransactions transactions = @@ -274,13 +274,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); - AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID); - - if (uploader != null) - { - uploader.Initialise(remoteClient, assetID, transaction, type, - data, storeLocal, tempFile); - } + AssetXferUploader uploader = transactions.RequestXferUploader(transaction); + uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile); } /// diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs index ec4dfd0bbb..8d21202541 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs @@ -40,39 +40,73 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Upload state. + /// + /// + /// New -> Uploading -> Complete + /// + private enum UploadState + { + New, + Uploading, + Complete + } + /// /// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we /// are performing a delayed update. /// AgentAssetTransactions m_transactions; + private UploadState m_uploadState = UploadState.New; + private AssetBase m_asset; private UUID InventFolder = UUID.Zero; private sbyte invType = 0; - private bool m_createItem = false; - private uint m_createItemCallback = 0; - private bool m_updateItem = false; + private bool m_createItem; + private uint m_createItemCallback; + + private bool m_updateItem; private InventoryItemBase m_updateItemData; + private bool m_updateTaskItem; + private TaskInventoryItem m_updateTaskItemData; + private string m_description = String.Empty; private bool m_dumpAssetToFile; - private bool m_finished = false; private string m_name = String.Empty; - private bool m_storeLocal; +// private bool m_storeLocal; private uint nextPerm = 0; private IClientAPI ourClient; - private UUID TransactionID = UUID.Zero; + + private UUID m_transactionID; + private sbyte type = 0; private byte wearableType = 0; public ulong XferID; private Scene m_Scene; - public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile) + /// + /// AssetXferUploader constructor + /// + /// /param> + /// + /// + /// + /// If true then when the asset is uploaded it is dumped to a file with the format + /// String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat", + /// now.Year, now.Month, now.Day, now.Hour, now.Minute, + /// now.Second, m_asset.Name, m_asset.Type); + /// for debugging purposes. + /// + public AssetXferUploader( + AgentAssetTransactions transactions, Scene scene, UUID transactionID, bool dumpAssetToFile) { m_transactions = transactions; + m_transactionID = transactionID; m_Scene = scene; - m_asset = new AssetBase() { FullID = assetID }; m_dumpAssetToFile = dumpAssetToFile; } @@ -118,20 +152,43 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } /// - /// Initialise asset transfer from the client + /// Start asset transfer from the client /// - /// - /// - /// - public void Initialise(IClientAPI remoteClient, UUID assetID, - UUID transaction, sbyte type, byte[] data, bool storeLocal, - bool tempFile) + /// + /// + /// + /// + /// + /// Optional data. If present then the asset is created immediately with this data + /// rather than requesting an upload from the client. The data must be longer than 2 bytes. + /// + /// + /// + public void StartUpload( + IClientAPI remoteClient, UUID assetID, UUID transaction, sbyte type, byte[] data, bool storeLocal, + bool tempFile) { // m_log.DebugFormat( // "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}", // remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length); + lock (this) + { + if (m_uploadState != UploadState.New) + { + m_log.WarnFormat( + "[ASSET XFER UPLOADER]: Tried to start upload of asset {0}, transaction {1} for {2} but this is already in state {3}. Aborting.", + assetID, transaction, remoteClient.Name, m_uploadState); + + return; + } + + m_uploadState = UploadState.Uploading; + } + ourClient = remoteClient; + + m_asset = new AssetBase() { FullID = assetID }; m_asset.Name = "blank"; m_asset.Description = "empty"; m_asset.Type = type; @@ -140,8 +197,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction m_asset.Local = storeLocal; m_asset.Temporary = tempFile; - TransactionID = transaction; - m_storeLocal = storeLocal; +// m_storeLocal = storeLocal; if (m_asset.Data.Length > 2) { @@ -166,14 +222,14 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction protected void SendCompleteMessage() { - ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, - m_asset.FullID); - // We must lock in order to avoid a race with a separate thread dealing with an inventory item or create // message from other client UDP. lock (this) { - m_finished = true; + m_uploadState = UploadState.Complete; + + ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID); + if (m_createItem) { DoCreateItem(m_createItemCallback); @@ -185,17 +241,23 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction // Remove ourselves from the list of transactions if completion was delayed until the transaction // was complete. // TODO: Should probably do the same for create item. - m_transactions.RemoveXferUploader(TransactionID); + m_transactions.RemoveXferUploader(m_transactionID); } - else if (m_storeLocal) + else if (m_updateTaskItem) { - m_Scene.AssetService.Store(m_asset); + StoreAssetForTaskItemUpdate(m_updateTaskItemData); + + m_transactions.RemoveXferUploader(m_transactionID); } +// else if (m_storeLocal) +// { +// m_Scene.AssetService.Store(m_asset); +// } } m_log.DebugFormat( "[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}", - m_asset.FullID, TransactionID); + m_asset.FullID, m_transactionID); if (m_dumpAssetToFile) { @@ -223,40 +285,37 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } public void RequestCreateInventoryItem(IClientAPI remoteClient, - UUID transactionID, UUID folderID, uint callbackID, + UUID folderID, uint callbackID, string description, string name, sbyte invType, sbyte type, byte wearableType, uint nextOwnerMask) { - if (TransactionID == transactionID) - { - InventFolder = folderID; - m_name = name; - m_description = description; - this.type = type; - this.invType = invType; - this.wearableType = wearableType; - nextPerm = nextOwnerMask; - m_asset.Name = name; - m_asset.Description = description; - m_asset.Type = type; + InventFolder = folderID; + m_name = name; + m_description = description; + this.type = type; + this.invType = invType; + this.wearableType = wearableType; + nextPerm = nextOwnerMask; + m_asset.Name = name; + m_asset.Description = description; + m_asset.Type = type; - // We must lock to avoid a race with a separate thread uploading the asset. - lock (this) + // We must lock to avoid a race with a separate thread uploading the asset. + lock (this) + { + if (m_uploadState == UploadState.Complete) { - if (m_finished) - { - DoCreateItem(callbackID); - } - else - { - m_createItem = true; //set flag so the inventory item is created when upload is complete - m_createItemCallback = callbackID; - } + DoCreateItem(callbackID); + } + else + { + m_createItem = true; //set flag so the inventory item is created when upload is complete + m_createItemCallback = callbackID; } } } - public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) + public void RequestUpdateInventoryItem(IClientAPI remoteClient, InventoryItemBase item) { // We must lock to avoid a race with a separate thread uploading the asset. lock (this) @@ -271,7 +330,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction item.AssetID = m_asset.FullID; m_Scene.InventoryService.UpdateItem(item); - if (m_finished) + if (m_uploadState == UploadState.Complete) { StoreAssetForItemUpdate(item); } @@ -287,8 +346,30 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } } + public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, TaskInventoryItem taskItem) + { + // We must lock to avoid a race with a separate thread uploading the asset. + lock (this) + { + m_asset.Name = taskItem.Name; + m_asset.Description = taskItem.Description; + m_asset.Type = (sbyte)taskItem.Type; + taskItem.AssetID = m_asset.FullID; + + if (m_uploadState == UploadState.Complete) + { + StoreAssetForTaskItemUpdate(taskItem); + } + else + { + m_updateTaskItem = true; + m_updateTaskItemData = taskItem; + } + } + } + /// - /// Store the asset for the given item. + /// Store the asset for the given item when it has been uploaded. /// /// private void StoreAssetForItemUpdate(InventoryItemBase item) @@ -300,6 +381,19 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction m_Scene.AssetService.Store(m_asset); } + /// + /// Store the asset for the given task item when it has been uploaded. + /// + /// + private void StoreAssetForTaskItemUpdate(TaskInventoryItem taskItem) + { +// m_log.DebugFormat( +// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}", +// m_asset.FullID, taskItem.Name, ourClient.Name); + + m_Scene.AssetService.Store(m_asset); + } + private void DoCreateItem(uint callbackID) { m_Scene.AssetService.Store(m_asset); @@ -327,19 +421,5 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction else ourClient.SendAlertMessage("Unable to create inventory item"); } - - /// - /// Get the asset data uploaded in this transfer. - /// - /// null if the asset has not finished uploading - public AssetBase GetAssetData() - { - if (m_finished) - { - return m_asset; - } - - return null; - } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 96e979703f..e25fa94191 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -345,15 +345,58 @@ namespace OpenSim.Region.Framework.Scenes public event StopScript OnStopScript; public delegate bool SceneGroupMoved(UUID groupID, Vector3 delta); + + /// + /// Triggered when an object is moved. + /// + /// + /// Triggered by + /// in , + /// + /// public event SceneGroupMoved OnSceneGroupMove; public delegate void SceneGroupGrabed(UUID groupID, Vector3 offset, UUID userID); + + /// + /// Triggered when an object is grabbed. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// via + /// public event SceneGroupGrabed OnSceneGroupGrab; public delegate bool SceneGroupSpinStarted(UUID groupID); + + /// + /// Triggered when an object starts to spin. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event SceneGroupSpinStarted OnSceneGroupSpinStart; public delegate bool SceneGroupSpun(UUID groupID, Quaternion rotation); + + /// + /// Triggered when an object is being spun. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event SceneGroupSpun OnSceneGroupSpin; public delegate void LandObjectAdded(ILandObject newParcel); @@ -460,36 +503,170 @@ namespace OpenSim.Region.Framework.Scenes } /// + /// Triggered when some scene object properties change. + /// + /// /// ScriptChangedEvent is fired when a scene object property that a script might be interested /// in (such as color, scale or inventory) changes. Only enough information sent is for the LSL changed event. /// This is not an indication that the script has changed (see OnUpdateScript for that). /// This event is sent to a script to tell it that some property changed on /// the object the script is in. See http://lslwiki.net/lslwiki/wakka.php?wakka=changed . - /// + /// Triggered by + /// in , + /// + /// public event ScriptChangedEvent OnScriptChangedEvent; public delegate void ScriptChangedEvent(uint localID, uint change); public delegate void ScriptControlEvent(UUID item, UUID avatarID, uint held, uint changed); + + /// + /// Triggered when a script receives control input from an agent. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event ScriptControlEvent OnScriptControlEvent; public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos); + + /// + /// Triggered when an object has arrived within a tolerance distance + /// of a motion target. + /// + /// + /// Triggered by + /// in + /// via , + /// via + /// public event ScriptAtTargetEvent OnScriptAtTargetEvent; public delegate void ScriptNotAtTargetEvent(uint localID); + + /// + /// Triggered when an object has a motion target but has not arrived + /// within a tolerance distance. + /// + /// + /// Triggered by + /// in + /// via , + /// via + /// public event ScriptNotAtTargetEvent OnScriptNotAtTargetEvent; public delegate void ScriptAtRotTargetEvent(uint localID, uint handle, Quaternion targetrot, Quaternion atrot); + + /// + /// Triggered when an object has arrived within a tolerance rotation + /// of a rotation target. + /// + /// + /// Triggered by + /// in + /// via , + /// via + /// public event ScriptAtRotTargetEvent OnScriptAtRotTargetEvent; public delegate void ScriptNotAtRotTargetEvent(uint localID); + + /// + /// Triggered when an object has a rotation target but has not arrived + /// within a tolerance rotation. + /// + /// + /// Triggered by + /// in + /// via , + /// via + /// public event ScriptNotAtRotTargetEvent OnScriptNotAtRotTargetEvent; public delegate void ScriptColliding(uint localID, ColliderArgs colliders); + + /// + /// Triggered when a physical collision has started between a prim + /// and something other than the region terrain. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event ScriptColliding OnScriptColliderStart; + + /// + /// Triggered when something that previously collided with a prim has + /// not stopped colliding with it. + /// + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event ScriptColliding OnScriptColliding; + + /// + /// Triggered when something that previously collided with a prim has + /// stopped colliding with it. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event ScriptColliding OnScriptCollidingEnd; + + /// + /// Triggered when a physical collision has started between an object + /// and the region terrain. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event ScriptColliding OnScriptLandColliderStart; + + /// + /// Triggered when an object that previously collided with the region + /// terrain has not yet stopped colliding with it. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event ScriptColliding OnScriptLandColliding; + + /// + /// Triggered when an object that previously collided with the region + /// terrain has stopped colliding with it. + /// + /// + /// Triggered by + /// in + /// via + /// via + /// via + /// public event ScriptColliding OnScriptLandColliderEnd; public delegate void OnMakeChildAgentDelegate(ScenePresence presence); @@ -550,6 +727,13 @@ namespace OpenSim.Region.Framework.Scenes /* public delegate void ScriptTimerEvent(uint localID, double timerinterval); + /// + /// Used to be triggered when the LSL timer event fires. + /// + /// + /// Triggered by + /// via + /// public event ScriptTimerEvent OnScriptTimerEvent; */ @@ -2293,7 +2477,11 @@ namespace OpenSim.Region.Framework.Scenes } } - // this lets us keep track of nasty script events like timer, etc. + /// + /// this lets us keep track of nasty script events like timer, etc. + /// + /// + /// public void TriggerTimerEvent(uint objLocalID, double Interval) { throw new NotImplementedException("TriggerTimerEvent was thought to be not used anymore and the registration for the event from scene object part has been commented out due to a memory leak");