From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Interfaces/IAgentAssetTransactions.cs | 4 +- .../Framework/Interfaces/IAttachmentsModule.cs | 15 +- .../Framework/Interfaces/IBakedTextureModule.cs | 5 +- .../Region/Framework/Interfaces/IBuySellModule.cs | 2 +- .../Framework/Interfaces/ICapabilitiesModule.cs | 20 +- .../Region/Framework/Interfaces/ICloudModule.cs | 2 +- OpenSim/Region/Framework/Interfaces/ICommander.cs | 4 +- .../Region/Framework/Interfaces/IDwellModule.cs | 1 + .../Framework/Interfaces/IDynamicFloaterModule.cs | 2 +- .../Framework/Interfaces/IDynamicMenuModule.cs | 1 + .../Framework/Interfaces/IDynamicTextureManager.cs | 26 +- .../Region/Framework/Interfaces/IEntityCreator.cs | 2 +- .../Framework/Interfaces/IEntityInventory.cs | 27 +- .../Framework/Interfaces/IEntityTransferModule.cs | 9 +- .../Region/Framework/Interfaces/IEstateModule.cs | 2 + OpenSim/Region/Framework/Interfaces/IEtcdModule.cs | 37 + OpenSim/Region/Framework/Interfaces/IEventQueue.cs | 22 +- .../Framework/Interfaces/IExternalCapsModule.cs | 2 +- .../Region/Framework/Interfaces/IFriendsModule.cs | 2 + OpenSim/Region/Framework/Interfaces/IGodsModule.cs | 7 +- .../Framework/Interfaces/IGroupsMessagingModule.cs | 12 +- .../Region/Framework/Interfaces/IGroupsModule.cs | 7 +- .../Region/Framework/Interfaces/IHttpRequests.cs | 6 +- .../Framework/Interfaces/IInventoryAccessModule.cs | 17 +- .../Framework/Interfaces/IJsonStoreModule.cs | 6 +- .../Framework/Interfaces/IMapImageUploadModule.cs | 9 +- .../Framework/Interfaces/IMessageTransferModule.cs | 2 +- OpenSim/Region/Framework/Interfaces/IMoapModule.cs | 8 +- OpenSim/Region/Framework/Interfaces/INPCModule.cs | 21 +- .../Framework/Interfaces/IPermissionsModule.cs | 2 +- .../Region/Framework/Interfaces/IPresenceModule.cs | 2 +- .../Framework/Interfaces/IRegionArchiverModule.cs | 28 +- .../Framework/Interfaces/IRegionCombinerModule.cs | 64 - .../Region/Framework/Interfaces/IRegionConsole.cs | 4 + .../Framework/Interfaces/IRegionModuleBase.cs | 2 +- .../Interfaces/IRegionSerialiserModule.cs | 4 +- .../Region/Framework/Interfaces/IRestartModule.cs | 1 + .../Region/Framework/Interfaces/ISearchModule.cs | 2 +- .../Framework/Interfaces/ISimulationDataService.cs | 12 +- .../Framework/Interfaces/ISimulationDataStore.cs | 22 +- OpenSim/Region/Framework/Interfaces/ISnmpModule.cs | 47 + .../Region/Framework/Interfaces/ISoundModule.cs | 2 +- .../Region/Framework/Interfaces/ITerrainChannel.cs | 8 + .../Region/Framework/Interfaces/ITerrainModule.cs | 12 +- OpenSim/Region/Framework/Interfaces/IUrlModule.cs | 7 +- .../Interfaces/IUserAccountCacheModule.cs | 35 + .../Region/Framework/Interfaces/IVoiceModule.cs | 2 +- .../Framework/Interfaces/IWindModelPlugin.cs | 2 +- OpenSim/Region/Framework/Interfaces/IWindModule.cs | 2 +- OpenSim/Region/Framework/Interfaces/IWorldComm.cs | 2 +- .../Region/Framework/Interfaces/IWorldMapModule.cs | 3 +- .../Region/Framework/Properties/AssemblyInfo.cs | 10 +- .../Framework/Scenes/Animation/AnimationSet.cs | 18 +- .../Framework/Scenes/Animation/BinBVHAnimation.cs | 40 +- .../Scenes/Animation/DefaultAvatarAnimations.cs | 6 +- .../Scenes/Animation/MovementAnimationOverrides.cs | 102 + .../Scenes/Animation/ScenePresenceAnimator.cs | 518 +- .../Framework/Scenes/AsyncInventorySender.cs | 9 +- .../Scenes/AsyncSceneObjectGroupDeleter.cs | 38 +- OpenSim/Region/Framework/Scenes/Border.cs | 148 - .../Framework/Scenes/CoalescedSceneObjects.cs | 40 +- OpenSim/Region/Framework/Scenes/CollisionSounds.cs | 342 ++ OpenSim/Region/Framework/Scenes/EntityManager.cs | 4 +- OpenSim/Region/Framework/Scenes/EventManager.cs | 337 +- OpenSim/Region/Framework/Scenes/GodController.cs | 287 ++ OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 372 +- OpenSim/Region/Framework/Scenes/Prioritizer.cs | 164 +- .../Region/Framework/Scenes/RegionStatsHandler.cs | 8 +- OpenSim/Region/Framework/Scenes/SOPMaterial.cs | 177 + OpenSim/Region/Framework/Scenes/SOPVehicle.cs | 803 ++++ OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 948 ++-- .../Framework/Scenes/Scene.PacketHandlers.cs | 291 +- .../Region/Framework/Scenes/Scene.Permissions.cs | 525 +- OpenSim/Region/Framework/Scenes/Scene.cs | 2560 +++++----- OpenSim/Region/Framework/Scenes/SceneBase.cs | 23 +- .../Framework/Scenes/SceneCommunicationService.cs | 59 +- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 833 ++-- OpenSim/Region/Framework/Scenes/SceneManager.cs | 256 +- .../Framework/Scenes/SceneObjectGroup.Inventory.cs | 337 +- .../Region/Framework/Scenes/SceneObjectGroup.cs | 3442 ++++++++++---- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 3024 +++++++----- .../Framework/Scenes/SceneObjectPartInventory.cs | 973 ++-- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 5029 +++++++++++++------- .../Framework/Scenes/ScenePresenceStateMachine.cs | 6 +- .../CoalescedSceneObjectsSerializer.cs | 30 +- .../Scenes/Serialization/SceneObjectSerializer.cs | 317 +- .../Scenes/Serialization/SceneXmlLoader.cs | 14 +- .../Region/Framework/Scenes/SimStatsReporter.cs | 629 ++- OpenSim/Region/Framework/Scenes/TerrainChannel.cs | 182 +- .../Region/Framework/Scenes/TerrainCompressor.cs | 1611 ++++--- .../Region/Framework/Scenes/Tests/BorderTests.cs | 340 -- .../Framework/Scenes/Tests/EntityManagerTests.cs | 22 +- .../Framework/Scenes/Tests/SceneGraphTests.cs | 20 +- .../Scenes/Tests/SceneObjectBasicTests.cs | 39 +- .../Framework/Scenes/Tests/SceneObjectCopyTests.cs | 34 +- .../Scenes/Tests/SceneObjectCrossingTests.cs | 51 +- .../Scenes/Tests/SceneObjectDeRezTests.cs | 71 +- .../Scenes/Tests/SceneObjectLinkingTests.cs | 56 +- .../Scenes/Tests/SceneObjectResizeTests.cs | 6 +- .../Scenes/Tests/SceneObjectSpatialTests.cs | 3 +- .../Scenes/Tests/SceneObjectStatusTests.cs | 16 +- .../Scenes/Tests/SceneObjectUndoRedoTests.cs | 4 +- .../Scenes/Tests/SceneObjectUserGroupTests.cs | 37 +- .../Scenes/Tests/ScenePresenceAgentTests.cs | 15 +- .../Scenes/Tests/ScenePresenceAnimationTests.cs | 2 +- .../Scenes/Tests/ScenePresenceAutopilotTests.cs | 4 +- .../Scenes/Tests/ScenePresenceCapabilityTests.cs | 8 +- .../Scenes/Tests/ScenePresenceCrossingTests.cs | 8 +- .../Scenes/Tests/ScenePresenceSitTests.cs | 4 +- .../Scenes/Tests/ScenePresenceTeleportTests.cs | 10 +- .../Framework/Scenes/Tests/SceneStatisticsTests.cs | 2 +- .../Framework/Scenes/Tests/SceneTelehubTests.cs | 4 +- .../Region/Framework/Scenes/Tests/SceneTests.cs | 4 +- .../Scenes/Tests/SharedRegionModuleTests.cs | 18 +- .../Framework/Scenes/Tests/TaskInventoryTests.cs | 22 +- .../Framework/Scenes/Tests/UserInventoryTests.cs | 68 +- .../Framework/Scenes/Tests/UuidGathererTests.cs | 18 +- OpenSim/Region/Framework/Scenes/UndoState.cs | 367 +- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 231 +- 119 files changed, 17335 insertions(+), 9206 deletions(-) create mode 100644 OpenSim/Region/Framework/Interfaces/IEtcdModule.cs delete mode 100644 OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs create mode 100644 OpenSim/Region/Framework/Interfaces/ISnmpModule.cs create mode 100644 OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs create mode 100644 OpenSim/Region/Framework/Scenes/Animation/MovementAnimationOverrides.cs delete mode 100644 OpenSim/Region/Framework/Scenes/Border.cs create mode 100644 OpenSim/Region/Framework/Scenes/CollisionSounds.cs create mode 100644 OpenSim/Region/Framework/Scenes/GodController.cs create mode 100644 OpenSim/Region/Framework/Scenes/SOPMaterial.cs create mode 100644 OpenSim/Region/Framework/Scenes/SOPVehicle.cs mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/Scene.cs mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/SceneGraph.cs mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/SimStatsReporter.cs delete mode 100644 OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs (limited to 'OpenSim/Region/Framework') diff --git a/OpenSim/Region/Framework/Interfaces/IAgentAssetTransactions.cs b/OpenSim/Region/Framework/Interfaces/IAgentAssetTransactions.cs index 0cc8fb6..b8278d6 100644 --- a/OpenSim/Region/Framework/Interfaces/IAgentAssetTransactions.cs +++ b/OpenSim/Region/Framework/Interfaces/IAgentAssetTransactions.cs @@ -36,10 +36,10 @@ namespace OpenSim.Region.Framework.Interfaces void HandleItemUpdateFromTransaction(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item); - void HandleItemCreationFromTransaction(IClientAPI remoteClient, UUID transactionID, UUID folderID, + bool HandleItemCreationFromTransaction(IClientAPI remoteClient, UUID transactionID, UUID folderID, uint callbackID, string description, string name, sbyte invType, sbyte type, byte wearableType, uint nextOwnerMask); - + void HandleTaskItemUpdateFromTransaction( IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item); diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index d9901bd..2f5ff9b 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -26,6 +26,7 @@ */ using System; +using System.Xml; using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; @@ -89,7 +90,8 @@ namespace OpenSim.Region.Framework.Interfaces /// If true then add object to user inventory /// Append to attachment point rather than replace. /// true if the object was successfully attached, false otherwise - bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, bool addToInventory, bool append); + bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent, + bool addToInventory, bool append); /// /// Rez an attachment from user inventory and change inventory status to match. @@ -98,7 +100,11 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// The scene object that was attached. Null if the scene object could not be found - SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt); + ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt); + + // Same as above, but also load script states from a separate doc + ISceneEntity RezSingleAttachmentFromInventory( + IScenePresence presence, UUID itemID, uint AttachmentPt, XmlDocument doc); /// /// Rez multiple attachments from a user's inventory @@ -106,7 +112,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void RezMultipleAttachmentsFromInventory(IScenePresence sp,List> rezlist); - + /// /// Detach the given item to the ground. /// @@ -129,8 +135,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /param> /// The attachment to detach. void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup grp); - - /// + /// Update the position of an attachment. /// /// diff --git a/OpenSim/Region/Framework/Interfaces/IBakedTextureModule.cs b/OpenSim/Region/Framework/Interfaces/IBakedTextureModule.cs index b536a49..4d8409be 100644 --- a/OpenSim/Region/Framework/Interfaces/IBakedTextureModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IBakedTextureModule.cs @@ -35,6 +35,9 @@ namespace OpenSim.Services.Interfaces public interface IBakedTextureModule { WearableCacheItem[] Get(UUID id); - void Store(UUID id, WearableCacheItem[] data); + + void Store(UUID id); + void Store(UUID id, WearableCacheItem[] WearableCache); + void UpdateMeshAvatar(UUID id); } } diff --git a/OpenSim/Region/Framework/Interfaces/IBuySellModule.cs b/OpenSim/Region/Framework/Interfaces/IBuySellModule.cs index d1ce4c0..1bbf10e 100644 --- a/OpenSim/Region/Framework/Interfaces/IBuySellModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IBuySellModule.cs @@ -31,7 +31,7 @@ using OpenSim.Framework; namespace OpenSim.Region.Framework.Interfaces { public interface IBuySellModule - { + { /// /// Try to buy an object /// diff --git a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs index 522c82d..761b1bb 100644 --- a/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ICapabilitiesModule.cs @@ -40,30 +40,32 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void CreateCaps(UUID agentId); - + void CreateCaps(UUID agentId, uint circuitCode); + /// /// Remove the caps handler for a given agent. /// /// - void RemoveCaps(UUID agentId); - + void RemoveCaps(UUID agentId, uint circuitCode); + /// /// Will return null if the agent doesn't have a caps handler registered /// /// - Caps GetCapsForUser(UUID agentId); + Caps GetCapsForUser(uint circuitCode); void SetAgentCapsSeeds(AgentCircuitData agent); - + Dictionary GetChildrenSeeds(UUID agentID); - + string GetChildSeed(UUID agentID, ulong handle); - + void SetChildrenSeed(UUID agentID, Dictionary seeds); - + void DropChildSeed(UUID agentID, ulong handle); string GetCapsPath(UUID agentId); + + void ActivateCaps(uint circuitCode); } } diff --git a/OpenSim/Region/Framework/Interfaces/ICloudModule.cs b/OpenSim/Region/Framework/Interfaces/ICloudModule.cs index 54172bd..a73b564 100644 --- a/OpenSim/Region/Framework/Interfaces/ICloudModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ICloudModule.cs @@ -27,7 +27,7 @@ namespace OpenSim.Region.Framework.Interfaces { - public interface ICloudModule + public interface ICloudModule { /// /// Retrieves the cloud density at the given region coordinates diff --git a/OpenSim/Region/Framework/Interfaces/ICommander.cs b/OpenSim/Region/Framework/Interfaces/ICommander.cs index 6b872c1..5d6428a 100644 --- a/OpenSim/Region/Framework/Interfaces/ICommander.cs +++ b/OpenSim/Region/Framework/Interfaces/ICommander.cs @@ -40,12 +40,12 @@ namespace OpenSim.Region.Framework.Interfaces /// Provide general help information about this commander. /// string Help { get; } - + /// /// The commands available for this commander /// Dictionary Commands { get; } - + void ProcessConsoleCommand(string function, string[] args); void RegisterCommand(string commandName, ICommand command); void Run(string function, object[] args); diff --git a/OpenSim/Region/Framework/Interfaces/IDwellModule.cs b/OpenSim/Region/Framework/Interfaces/IDwellModule.cs index db50439..ebef5a4 100644 --- a/OpenSim/Region/Framework/Interfaces/IDwellModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IDwellModule.cs @@ -33,5 +33,6 @@ namespace OpenSim.Region.Framework.Interfaces public interface IDwellModule { int GetDwell(UUID parcelID); + int GetDwell(LandData land); } } diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs b/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs index 7684ce3..1ff8fd2 100644 --- a/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IDynamicFloaterModule.cs @@ -36,7 +36,7 @@ namespace OpenSim.Region.Framework.Interfaces public abstract class FloaterData { - public abstract int Channel { get; } + public abstract int Channel { get; } public abstract string FloaterName { get; set; } public virtual string XmlName { get; set; } public virtual string XmlText { get; set; } diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs index 08b71e4..4d000b6 100644 --- a/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs @@ -43,6 +43,7 @@ namespace OpenSim.Region.Framework.Interfaces public enum UserMode : int { Normal = 0, + RegionManager = 2, God = 3 } diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs index 6df5cc2..093ea9c 100644 --- a/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs +++ b/OpenSim/Region/Framework/Interfaces/IDynamicTextureManager.cs @@ -44,14 +44,13 @@ namespace OpenSim.Region.Framework.Interfaces /// void ReturnData(UUID id, IDynamicTexture texture); + UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams); UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, - int updateTimer); + bool SetBlending, byte AlphaValue); UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, - int updateTimer, bool SetBlending, byte AlphaValue); - UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams, - int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face); - UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, string extraParams, - int updateTimer); + bool SetBlending, int disp, byte AlphaValue, int face); + + UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, string extraParams); /// Apply a dynamically generated texture to all sides of the given prim. The texture is not persisted to the /// asset service. @@ -62,8 +61,6 @@ namespace OpenSim.Region.Framework.Interfaces /// based texture or "image" to create a texture from an image at a particular URL /// The data for the generator /// Parameters for the generator that don't form part of the main data. - /// If zero, the image is never updated after the first generation. If positive - /// the image is updated at the given interval. Not implemented for /// /// If true, the newly generated texture is blended with the appropriate existing ones on the prim /// @@ -76,7 +73,7 @@ namespace OpenSim.Region.Framework.Interfaces /// can be obtained as SceneObjectPart.Shape.Textures.DefaultTexture.TextureID /// UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, string extraParams, - int updateTimer, bool SetBlending, byte AlphaValue); + bool SetBlending, byte AlphaValue); /// /// Apply a dynamically generated texture to the given prim. @@ -87,8 +84,6 @@ namespace OpenSim.Region.Framework.Interfaces /// based texture or "image" to create a texture from an image at a particular URL /// The data for the generator /// Parameters for the generator that don't form part of the main data. - /// If zero, the image is never updated after the first generation. If positive - /// the image is updated at the given interval. Not implemented for /// /// If true, the newly generated texture is blended with the appropriate existing ones on the prim /// @@ -109,10 +104,9 @@ namespace OpenSim.Region.Framework.Interfaces /// to obtain it directly from the SceneObjectPart. For instance, if ALL_SIDES is set then this texture /// can be obtained as SceneObjectPart.Shape.Textures.DefaultTexture.TextureID /// - UUID AddDynamicTextureData( - UUID simID, UUID primID, string contentType, string data, string extraParams, - int updateTimer, bool SetBlending, int disp, byte AlphaValue, int face); - + UUID AddDynamicTextureData(UUID simID, UUID primID, string contentType, string data, string extraParams, + bool SetBlending, int disp, byte AlphaValue, int face); + void GetDrawStringSize(string contentType, string text, string fontName, int fontSize, out double xSize, out double ySize); } @@ -140,7 +134,7 @@ namespace OpenSim.Region.Framework.Interfaces bool AsyncConvertUrl(UUID id, string url, string extraParams); bool AsyncConvertData(UUID id, string bodyData, string extraParams); - void GetDrawStringSize(string text, string fontName, int fontSize, + void GetDrawStringSize(string text, string fontName, int fontSize, out double xSize, out double ySize); } diff --git a/OpenSim/Region/Framework/Interfaces/IEntityCreator.cs b/OpenSim/Region/Framework/Interfaces/IEntityCreator.cs index c39627c..1df6486 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityCreator.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityCreator.cs @@ -41,7 +41,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// PCode[] CreationCapabilities { get; } - + /// /// Create an entity /// diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs index 9ffda51..e7c2428 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs @@ -36,8 +36,8 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Interface to an entity's (SceneObjectPart's) inventory /// - /// - /// This is not a finished 1.0 candidate interface + /// + /// This is not a finished 1.0 candidate interface public interface IEntityInventory { /// @@ -48,21 +48,21 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Reset UUIDs for all the items in the prim's inventory. /// - /// + /// /// This involves either generating /// new ones or setting existing UUIDs to the correct parent UUIDs. /// /// If this method is called and there are inventory items, then we regard the inventory as having changed. - /// + /// /// Link number for the part void ResetInventoryIDs(); /// /// Reset parent object UUID for all the items in the prim's inventory. /// - /// + /// /// If this method is called and there are inventory items, then we regard the inventory as having changed. - /// + /// /// Link number for the part void ResetObjectID(); @@ -87,7 +87,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Number of scripts started. int CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource); - + ArrayList GetScriptErrors(UUID itemID); void ResumeScripts(); @@ -133,6 +133,8 @@ namespace OpenSim.Region.Framework.Interfaces /// bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); + ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); + /// /// Stop and remove a script which is in this prim's inventory from the scene. /// @@ -236,15 +238,15 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Get the scene object(s) referenced by an inventory item. /// - /// + /// /// This is returned in a 'rez ready' state. That is, name, description, permissions and other details have /// been adjusted to reflect the part and item from which it originates. - /// + /// /// Inventory item /// The scene objects /// Relative offsets for each object /// true = success, false = the scene object asset couldn't be found - bool GetRezReadySceneObjects(TaskInventoryItem item, out List objlist, out List veclist); + bool GetRezReadySceneObjects(TaskInventoryItem item, out List objlist, out List veclist, out Vector3 bbox, out float offsetHeight); /// /// Update an existing inventory item. @@ -276,6 +278,8 @@ namespace OpenSim.Region.Framework.Interfaces /// void ProcessInventoryBackup(ISimulationDataService datastore); + void AggregateInnerPerms(ref uint owner, ref uint group, ref uint everyone); + uint MaskEffectivePermissions(); void ApplyNextOwnerPermissions(); @@ -310,7 +314,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// List GetInventoryList(); - + /// /// Get the xml representing the saved states of scripts in this inventory. /// @@ -318,5 +322,6 @@ namespace OpenSim.Region.Framework.Interfaces /// A /// Dictionary GetScriptStates(); + Dictionary GetScriptStates(bool oldIDs); } } diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs index d07b15a..1b690ba 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs @@ -36,6 +36,7 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.Framework.Interfaces { public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx); + public delegate ScenePresence CrossAsyncDelegate(ScenePresence agent, bool isFlying); public interface IEntityTransferModule { @@ -82,7 +83,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// The agent ID /// true if the agent is in the process of being teleported, false otherwise. - bool IsInTransit(UUID id); + bool IsInTransit(UUID id); bool Cross(ScenePresence agent, bool isFlying); @@ -94,11 +95,15 @@ namespace OpenSim.Region.Framework.Interfaces GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, EntityTransferContext ctx, out Vector3 newpos, out string reason); + GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition, out Vector3 newpos); + bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, EntityTransferContext ctx, out string reason); - void Cross(SceneObjectGroup sog, Vector3 position, bool silent); + bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent, bool removeScripts); ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx); + bool CrossAgentCreateFarChild(ScenePresence agent, GridRegion neighbourRegion, Vector3 pos, EntityTransferContext ctx); + bool HandleIncomingSceneObject(SceneObjectGroup so, Vector3 newPosition); } diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs index 461c880..6b8b999 100644 --- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs @@ -39,6 +39,8 @@ namespace OpenSim.Region.Framework.Interfaces event ChangeDelegate OnRegionInfoChange; event ChangeDelegate OnEstateInfoChange; event MessageDelegate OnEstateMessage; + event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; + event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; uint GetRegionFlags(); bool IsManager(UUID avatarID); diff --git a/OpenSim/Region/Framework/Interfaces/IEtcdModule.cs b/OpenSim/Region/Framework/Interfaces/IEtcdModule.cs new file mode 100644 index 0000000..123cb67 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IEtcdModule.cs @@ -0,0 +1,37 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +public interface IEtcdModule +{ + bool Store(string k, string v); + bool Store(string k, string v, int ttl); + string Get(string k); + void Watch(string k, Action callback); + void Delete(string k); +} diff --git a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs index dfc269e..7edd75a 100644 --- a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs +++ b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs @@ -30,6 +30,7 @@ using OpenMetaverse; using OpenMetaverse.Packets; using OpenMetaverse.Messages.Linden; using OpenMetaverse.StructuredData; +using OpenSim.Framework; namespace OpenSim.Region.Framework.Interfaces { @@ -38,26 +39,27 @@ namespace OpenSim.Region.Framework.Interfaces bool Enqueue(OSD o, UUID avatarID); // These are required to decouple Scenes from EventQueueHelper - void DisableSimulator(ulong handle, UUID avatarID); +// void DisableSimulator(ulong handle, UUID avatarID); void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY); - void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, + void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, ulong regionHandle, int regionSizeX, int regionSizeY); - void TeleportFinishEvent(ulong regionHandle, byte simAccess, + void TeleportFinishEvent(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, - uint locationID, uint flags, string capsURL, + uint locationID, uint flags, string capsURL, UUID agentID, int regionSizeX, int regionSizeY); void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY); void ChatterboxInvitation(UUID sessionID, string sessionName, - UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, - uint timeStamp, bool offline, int parentEstateID, Vector3 position, - uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket); - void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, - bool isModerator, bool textMute); + UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, + uint timeStamp, bool offline, int parentEstateID, Vector3 position, + uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket); + void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, + bool canVoiceChat, bool isModerator, bool textMute, bool isEnterorLeave); + void ChatterBoxForceClose(UUID toAgent, UUID sessionID, string reason); void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID); - void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID); + void GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data); OSD ScriptRunningEvent(UUID objectID, UUID itemID, bool running, bool mono); OSD BuildEvent(string eventName, OSD eventBody); void partPhysicsProperties(uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID); diff --git a/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs b/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs index a730cfd..4ce150f 100644 --- a/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs @@ -37,7 +37,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// This function extends the simple URL configuration in the caps handlers /// to facilitate more interesting computation when an external handler is - /// sent to the viewer. + /// sent to the viewer. /// /// New user UUID /// Internal caps registry, where the external handler will be registered diff --git a/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs b/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs index 7e87006..ec014f4 100644 --- a/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; namespace OpenSim.Region.Framework.Interfaces @@ -93,6 +94,7 @@ namespace OpenSim.Region.Framework.Interfaces /// These come from the FriendRights enum. void GrantRights(IClientAPI remoteClient, UUID friendID, int perms); + void IsNowRoot(ScenePresence sp); bool SendFriendsOnlineIfNeeded(IClientAPI client); } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Interfaces/IGodsModule.cs b/OpenSim/Region/Framework/Interfaces/IGodsModule.cs index 552ce01..52615e3 100644 --- a/OpenSim/Region/Framework/Interfaces/IGodsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IGodsModule.cs @@ -43,16 +43,15 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void RequestGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient); - + void RequestGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godLike); + /// /// Kicks User specified from the simulator. This logs them off of the grid. /// /// The person doing the kicking - /// The session of the person doing the kicking /// the person that is being kicked /// This isn't used apparently /// The message to send to the user after it's been turned into a field - void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason); + void KickUser(UUID godID, UUID agentID, uint kickflags, byte[] reason); } } diff --git a/OpenSim/Region/Framework/Interfaces/IGroupsMessagingModule.cs b/OpenSim/Region/Framework/Interfaces/IGroupsMessagingModule.cs index 7dc1552..46d6863 100644 --- a/OpenSim/Region/Framework/Interfaces/IGroupsMessagingModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IGroupsMessagingModule.cs @@ -34,9 +34,9 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Provide mechanisms for messaging groups. /// - /// + /// /// TODO: Provide a mechanism for receiving group messages as well as sending them - /// + /// public interface IGroupsMessagingModule { /// @@ -56,13 +56,13 @@ namespace OpenSim.Region.Framework.Interfaces /// True if the chat session was started successfully, false otherwise. /// bool StartGroupChatSession(UUID agentID, UUID groupID); - + /// /// Send a message to each member of a group whose chat session is active. /// /// /// The message itself. The fields that must be populated are - /// + /// /// imSessionID - Populate this with the group ID (session ID and group ID are currently identical) /// fromAgentName - Populate this with whatever arbitrary name you want to show up in the chat dialog /// message - The message itself @@ -76,7 +76,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// The message itself. The fields that must be populated are - /// + /// /// imSessionID - Populate this with the group ID (session ID and group ID are currently identical) /// fromAgentName - Populate this with whatever arbitrary name you want to show up in the chat dialog /// message - The message itself @@ -84,7 +84,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - /// The requesting agent to use when querying the groups service. Sometimes this is different from + /// The requesting agent to use when querying the groups service. Sometimes this is different from /// im.fromAgentID, with group notices, for example. /// /// diff --git a/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs b/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs index 9ae5e87..0d1f4f4 100644 --- a/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs @@ -51,7 +51,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// The UUID of the created group UUID CreateGroup( - IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, + IClientAPI remoteClient, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish); /// @@ -67,7 +67,7 @@ namespace OpenSim.Region.Framework.Interfaces /// ID of the group /// The group's data. Null if there is no such group. GroupRecord GetGroupRecord(UUID GroupID); - + void ActivateGroup(IClientAPI remoteClient, UUID groupID); List GroupTitlesRequest(IClientAPI remoteClient, UUID groupID); List GroupMembersRequest(IClientAPI remoteClient, UUID groupID); @@ -76,13 +76,14 @@ namespace OpenSim.Region.Framework.Interfaces GroupProfileData GroupProfileRequest(IClientAPI remoteClient, UUID groupID); GroupMembershipData[] GetMembershipData(UUID UserID); GroupMembershipData GetMembershipData(UUID GroupID, UUID UserID); + GroupMembershipData GetActiveMembershipData(UUID UserID); void UpdateGroupInfo(IClientAPI remoteClient, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish); void SetGroupAcceptNotices(IClientAPI remoteClient, UUID groupID, bool acceptNotices, bool listInProfile); void GroupTitleUpdate(IClientAPI remoteClient, UUID GroupID, UUID TitleRoleID); - + GroupNoticeData[] GroupNoticesListRequest(IClientAPI remoteClient, UUID GroupID); string GetGroupTitle(UUID avatarID); void GroupRoleUpdate(IClientAPI remoteClient, UUID GroupID, UUID RoleID, string name, string description, string title, ulong powers, byte updateType); diff --git a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs index 124504c..978c248 100644 --- a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs +++ b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs @@ -58,7 +58,6 @@ namespace OpenSim.Region.Framework.Interfaces public interface IHttpRequestModule { UUID MakeHttpRequest(string url, string parameters, string body); - /// /// Starts the http request. /// @@ -78,15 +77,14 @@ namespace OpenSim.Region.Framework.Interfaces /// then returned via IServiceRequest when the response is asynchronously fetched. /// UUID StartHttpRequest( - uint localID, UUID itemID, string url, List parameters, Dictionary headers, string body, + uint localID, UUID itemID, string url, List parameters, Dictionary headers, string body, out HttpInitialRequestStatus status); /// /// Stop and remove all http requests for the given script. /// /// - void StopHttpRequestsForScript(UUID id); - + void StopHttpRequest(uint m_localID, UUID m_itemID); IServiceRequest GetNextCompletedRequest(); void RemoveCompletedRequest(UUID id); } diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 6bad018..292b0d6 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs @@ -70,6 +70,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// + /// /// /// /// @@ -81,6 +82,11 @@ namespace OpenSim.Region.Framework.Interfaces /// /// The SceneObjectGroup rezzed or null if rez was unsuccessful. SceneObjectGroup RezObject( + IClientAPI remoteClient, UUID itemID, UUID rezGroupID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); + // compatibily do not use + SceneObjectGroup RezObject( IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); @@ -97,6 +103,7 @@ namespace OpenSim.Region.Framework.Interfaces /// The item from which the object asset came. Can be null, in which case pre and post rez item adjustment and checks are not performed. /// /// The asset id for the object to rez. + /// The requested group id for the object to rez. /// /// /// @@ -107,8 +114,16 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// The SceneObjectGroup rezzed or null if rez was unsuccessful. + + SceneObjectGroup RezObject(IClientAPI remoteClient, InventoryItemBase item, UUID rezGroupID, + UUID assetID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); + + // compatibility do not use SceneObjectGroup RezObject( - IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart, + IClientAPI remoteClient, InventoryItemBase item, + UUID assetID, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs index 1a89721..86aca8e 100644 --- a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) Contributors + * Copyright (c) Contributors * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,7 @@ namespace OpenSim.Region.Framework.Interfaces Array = 2, Value = 3 } - + public enum JsonStoreValueType { Undefined = 0, @@ -50,7 +50,7 @@ namespace OpenSim.Region.Framework.Interfaces String = 4, UUID = 5 } - + public struct JsonStoreStats { public int StoreCount; diff --git a/OpenSim/Region/Framework/Interfaces/IMapImageUploadModule.cs b/OpenSim/Region/Framework/Interfaces/IMapImageUploadModule.cs index 6a7d4a1..5151567 100644 --- a/OpenSim/Region/Framework/Interfaces/IMapImageUploadModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IMapImageUploadModule.cs @@ -25,13 +25,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System.Drawing; +using OpenMetaverse; using OpenSim.Framework; +using System.Drawing; namespace OpenSim.Region.Framework.Interfaces { public interface IMapImageUploadModule { + /// + /// Upload a new maptile + /// + void UploadMapTile(IScene scene); void UploadMapTile(IScene scene, Bitmap mapTile); } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Interfaces/IMessageTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IMessageTransferModule.cs index 290b826..b06ff2b 100644 --- a/OpenSim/Region/Framework/Interfaces/IMessageTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IMessageTransferModule.cs @@ -31,7 +31,7 @@ namespace OpenSim.Region.Framework.Interfaces { public delegate void MessageResultNotification(bool success); public delegate void UndeliveredMessage(GridInstantMessage im); - + public interface IMessageTransferModule { event UndeliveredMessage OnUndeliveredMessage; diff --git a/OpenSim/Region/Framework/Interfaces/IMoapModule.cs b/OpenSim/Region/Framework/Interfaces/IMoapModule.cs index 1d3d240..e8be70f 100644 --- a/OpenSim/Region/Framework/Interfaces/IMoapModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IMoapModule.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// MediaEntry GetMediaEntry(SceneObjectPart part, int face); - + /// /// Set the media entry for a given prim face. /// @@ -53,13 +53,13 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void SetMediaEntry(SceneObjectPart part, int face, MediaEntry me); - + /// /// Clear the media entry for a given prim face. /// - /// + /// /// This is the equivalent of setting a media entry of null - /// + /// /// /// /param> void ClearMediaEntry(SceneObjectPart part, int face); diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index 478833e..df872f4 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -31,6 +31,17 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.Framework.Interfaces { + // option flags for NPCs + public enum NPCOptionsFlags : int + { + None = 0x00, // no flags (max restriction) + AllowNotOwned = 0x01, // allow NPCs to be created not Owned + AllowSenseAsAvatar = 0x02, // allow NPCs to set to be sensed as Avatars + AllowCloneOtherAvatars = 0x04, // allow NPCs to created cloning a avatar in region + NoNPCGroup = 0x08, // NPCs will have no group title, otherwise will have "- NPC -" + objectGroup = 0x10 // NPC will have host sog groupID + } + /// /// Temporary interface. More methods to come at some point to make NPCs /// more object oriented rather than controlling purely through module @@ -38,12 +49,18 @@ namespace OpenSim.Region.Framework.Interfaces /// public interface INPC { + /// /// Should this NPC be sensed by LSL sensors as an 'agent' /// (interpreted here to mean a normal user) rather than an OpenSim /// specific NPC extension? /// bool SenseAsAgent { get; } + UUID ActiveGroupId { get; set; } + UUID Owner { get; } + string profileAbout { get; set; } + UUID profileImage { get; set; } + string Born { get; set; } } public interface INPCModule @@ -94,7 +111,7 @@ namespace OpenSim.Region.Framework.Interfaces /// failure. /// UUID CreateNPC(string firstname, string lastname, - Vector3 position, UUID agentID, UUID owner, bool senseAsAgent, Scene scene, + Vector3 position, UUID agentID, UUID owner, string groupTitle, UUID groupID, bool senseAsAgent, Scene scene, AvatarAppearance appearance); /// @@ -284,5 +301,7 @@ namespace OpenSim.Region.Framework.Interfaces /// agent, the agent is unowned or the agent was not an NPC. /// UUID GetOwner(UUID agentID); + + NPCOptionsFlags NPCOptionFlags {get;} } } diff --git a/OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs b/OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs index 1ed978b..933ca14 100644 --- a/OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs @@ -42,7 +42,7 @@ namespace OpenSim.Region.Framework.Interfaces public interface IPermissionsModule { - + /// /// Returns the type of permissions that the user has over an object. /// diff --git a/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs b/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs index d44c1e1..fb5933c 100644 --- a/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs @@ -33,7 +33,7 @@ namespace OpenSim.Region.Framework.Interfaces { public string UserID; public UUID RegionID; - + public PresenceInfo(string userID, UUID regionID) { UserID = userID; diff --git a/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs index 99bc87d..9370ccd 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs @@ -40,17 +40,17 @@ namespace OpenSim.Region.Framework.Interfaces { void HandleLoadOarConsoleCommand(string module, string[] cmdparams); void HandleSaveOarConsoleCommand(string module, string[] cmdparams); - + /// /// Archive the region to the given path /// - /// + /// /// This method occurs asynchronously. If you want notification of when it has completed then subscribe to /// the EventManager.OnOarFileSaved event. - /// + /// /// void ArchiveRegion(string savePath, Dictionary options); - + /// /// Archive the region to the given path /// @@ -94,35 +94,35 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void DearchiveRegion(string loadPath); - + /// /// Dearchive the given region archive. This replaces the existing scene. /// - /// + /// /// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event. - /// + /// /// /// If supplied, this request Id is later returned in the saved event /// /// Dictionary of options. /// void DearchiveRegion(string loadPath, Guid requestId, Dictionary options); - + /// - /// Dearchive a region from a stream. This replaces the existing scene. + /// Dearchive a region from a stream. This replaces the existing scene. /// - /// + /// /// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event. - /// + /// /// void DearchiveRegion(Stream loadStream); - + /// /// Dearchive a region from a stream. This replaces the existing scene. /// - /// + /// /// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event. - /// + /// /// /// If supplied, this request Id is later returned in the saved event /// diff --git a/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs deleted file mode 100644 index c6f531e..0000000 --- a/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OpenSim.Region.Framework.Scenes; -using System.IO; -using OpenMetaverse; - -namespace OpenSim.Region.Framework.Interfaces -{ - public interface IRegionCombinerModule - { - /// - /// Does the given id belong to the root region of a megaregion? - /// - bool IsRootForMegaregion(UUID regionId); - - /// - /// Gets the size of megaregion. - /// - /// - /// Returns size in meters. - /// Do not rely on this method remaining the same - this area is actively under development. - /// - /// - /// The id of the root region for a megaregion. - /// This may change in the future to allow any region id that makes up a megaregion. - /// Currently, will throw an exception if this does not match a root region. - /// - Vector2 GetSizeOfMegaregion(UUID regionId); - - /// - /// Tests to see of position (relative to the region) is within the megaregion - /// - bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy); - } -} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Interfaces/IRegionConsole.cs b/OpenSim/Region/Framework/Interfaces/IRegionConsole.cs index 4d261d6..5d5ce34 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionConsole.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionConsole.cs @@ -30,8 +30,12 @@ using OpenSim.Framework; namespace OpenSim.Region.Framework.Interfaces { + public delegate void ConsoleMessage(UUID toAgentID, string message); + public interface IRegionConsole { + event ConsoleMessage OnConsoleMessage; + bool RunCommand(string command, UUID invokerID); void SendConsoleOutput(UUID agentID, string message); void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn); diff --git a/OpenSim/Region/Framework/Interfaces/IRegionModuleBase.cs b/OpenSim/Region/Framework/Interfaces/IRegionModuleBase.cs index 2089bce..5b8f0f0 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionModuleBase.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionModuleBase.cs @@ -92,7 +92,7 @@ namespace OpenSim.Region.Framework.Interfaces /// this will be multiple times in one instance, while a nonshared /// module instance will only be called once. /// This method is called after AddRegion has been called in all - /// modules for that scene, providing an opportunity to request + /// modules for that scene, providing an opportunity to request /// another module's interface, or hook an event from another module. /// /// diff --git a/OpenSim/Region/Framework/Interfaces/IRegionSerialiserModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionSerialiserModule.cs index c5b21a8..60586ff 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionSerialiserModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionSerialiserModule.cs @@ -102,9 +102,9 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void SavePrimListToXml2(EntityBase[] entityList, TextWriter stream, Vector3 min, Vector3 max); - + void SaveNamedPrimsToXml2(Scene scene, string primName, string fileName); - + /// /// Deserializes a scene object from its xml2 representation. This does not load the object into the scene. /// diff --git a/OpenSim/Region/Framework/Interfaces/IRestartModule.cs b/OpenSim/Region/Framework/Interfaces/IRestartModule.cs index c68550f..9b25beb 100644 --- a/OpenSim/Region/Framework/Interfaces/IRestartModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRestartModule.cs @@ -35,5 +35,6 @@ namespace OpenSim.Region.Framework.Interfaces TimeSpan TimeUntilRestart { get; } void ScheduleRestart(UUID initiator, string message, int[] alerts, bool notice); void AbortRestart(string message); + void DelayRestart(int seconds, string message); } } diff --git a/OpenSim/Region/Framework/Interfaces/ISearchModule.cs b/OpenSim/Region/Framework/Interfaces/ISearchModule.cs index 64bf72c..d56d188 100644 --- a/OpenSim/Region/Framework/Interfaces/ISearchModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ISearchModule.cs @@ -31,6 +31,6 @@ namespace OpenSim.Framework { public interface ISearchModule { - + void Refresh(); } } diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs index 8948f04..f8a6b53 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs @@ -64,12 +64,19 @@ namespace OpenSim.Region.Framework.Interfaces List LoadObjects(UUID regionUUID); /// - /// Store a terrain revision in region storage + /// Store terrain in region storage /// /// HeightField data /// region UUID void StoreTerrain(TerrainData terrain, UUID regionID); + /// + /// Store baked terrain in region storage + /// + /// HeightField data + /// region UUID + void StoreBakedTerrain(TerrainData terrain, UUID regionID); + // Legacy version kept for downward compabibility void StoreTerrain(double[,] terrain, UUID regionID); @@ -82,6 +89,7 @@ namespace OpenSim.Region.Framework.Interfaces /// the Z dimension of the region being filled /// Heightfield data TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ); + TerrainData LoadBakedTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ); // Legacy version kept for downward compabibility double[,] LoadTerrain(UUID regionID); @@ -125,6 +133,8 @@ namespace OpenSim.Region.Framework.Interfaces /// the region UUID void RemoveRegionEnvironmentSettings(UUID regionUUID); + UUID[] GetObjectIDs(UUID regionID); + void SaveExtra(UUID regionID, string name, string value); void RemoveExtra(UUID regionID, string name); diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs index 917b5d1..19ba787 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.Framework.Interfaces /// Dispose the database /// void Dispose(); - + /// /// Stores all object's details apart from inventory /// @@ -75,17 +75,25 @@ namespace OpenSim.Region.Framework.Interfaces List LoadObjects(UUID regionUUID); /// - /// Store a terrain revision in region storage + /// Store a terrain in region storage /// /// HeightField data /// region UUID void StoreTerrain(TerrainData terrain, UUID regionID); + /// + /// Store baked terrain in region storage + /// + /// HeightField data + /// region UUID + void StoreBakedTerrain(TerrainData terrain, UUID regionID); + + // Legacy version kept for downward compabibility void StoreTerrain(double[,] terrain, UUID regionID); - + /// - /// Load the latest terrain revision from region storage + /// Load terrain from region storage /// /// the region UUID /// the X dimension of the terrain being filled @@ -93,12 +101,13 @@ namespace OpenSim.Region.Framework.Interfaces /// the Z dimension of the terrain being filled /// Heightfield data TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ); + TerrainData LoadBakedTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ); // Legacy version kept for downward compabibility double[,] LoadTerrain(UUID regionID); void StoreLandObject(ILandObject Parcel); - + /// /// /// delete from land where UUID=globalID @@ -107,7 +116,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void RemoveLandObject(UUID globalID); - + List LoadLandObjects(UUID regionUUID); void StoreRegionSettings(RegionSettings rs); @@ -115,6 +124,7 @@ namespace OpenSim.Region.Framework.Interfaces RegionLightShareData LoadRegionWindlightSettings(UUID regionUUID); void StoreRegionWindlightSettings(RegionLightShareData wl); void RemoveRegionWindlightSettings(UUID regionID); + UUID[] GetObjectIDs(UUID regionID); /// /// Load Environment settings from region storage diff --git a/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs b/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs new file mode 100644 index 0000000..10f421b --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs @@ -0,0 +1,47 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenSim.Region.Framework.Scenes; + +public interface ISnmpModule +{ + void Trap(int code, string Message, Scene scene); + void Critical(string Message, Scene scene); + void Warning(string Message, Scene scene); + void Major(string Message, Scene scene); + void ColdStart(int step , Scene scene); + void Shutdown(int step , Scene scene); + // + // Node Start/stop events + // + void LinkUp(Scene scene); + void LinkDown(Scene scene); + void BootInfo(string data, Scene scene); + void trapDebug(string Module,string data, Scene scene); + void trapXMRE(int data, string Message, Scene scene); + +} diff --git a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs index 8372ddd..f7c6513 100644 --- a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs @@ -95,7 +95,7 @@ namespace OpenSim.Region.Framework.Interfaces /// Sound radius /// Set object to sync master if true void LoopSound(UUID objectID, UUID soundID, double gain, - double radius, bool isMaster); + double radius, bool isMaster, bool isSlave); /// /// Trigger or play an attached sound in this part's inventory. diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs index f660b8d..78db02a 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs @@ -59,5 +59,13 @@ namespace OpenSim.Region.Framework.Interfaces void LoadFromXmlString(string data); // Merge some terrain into this channel void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement); + + /// + /// + /// <x, y, z> + /// + /// <x, y> + /// <x, y> + void MergeWithBounding(ITerrainChannel newTerrain, Vector3 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize); } } diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs index 28f797a..3fc5ce7 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs @@ -24,10 +24,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System.IO; +using System.IO; using OpenSim.Framework; - using OpenMetaverse; namespace OpenSim.Region.Framework.Interfaces @@ -43,13 +42,13 @@ namespace OpenSim.Region.Framework.Interfaces /// Use this if you change terrain data outside of the terrain module (e.g. in osTerrainSetHeight) /// void TaintTerrain(); - + /// /// When a client initially connects, all the terrain must be pushed to the viewer. /// This call causes all the terrain patches to be sent to the client. /// void PushTerrain(IClientAPI pClient); - + /// /// Load a terrain from a stream. /// @@ -58,8 +57,11 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void LoadFromStream(string filename, Stream stream); - void LoadFromStream(string filename, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement, Stream stream); void LoadFromStream(string filename, System.Uri pathToTerrainHeightmap); + void LoadFromStream(string filename, Vector3 displacement, + float radianRotation, Vector2 rotationDisplacement, Stream stream); + void LoadFromStream(string filename, Vector3 displacement, + float rotationDegress, Vector2 boundingOrigin, Vector2 boundingSize, Stream stream); /// /// Save a terrain to a stream. /// diff --git a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs index 79e9f9d..3fc0c44 100644 --- a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System.Collections; using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; @@ -35,12 +36,12 @@ namespace OpenSim.Region.Framework.Interfaces public interface IUrlModule { string ExternalHostNameForLSL { get; } - UUID RequestURL(IScriptModule engine, SceneObjectPart host, UUID itemID); - UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID); + UUID RequestURL(IScriptModule engine, SceneObjectPart host, UUID itemID, Hashtable options); + UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID, Hashtable options); void ReleaseURL(string url); void HttpResponse(UUID request, int status, string body); void HttpContentType(UUID request, string type); - + string GetHttpHeader(UUID request, string header); int GetFreeUrls(); diff --git a/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs new file mode 100644 index 0000000..027a7e2 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs @@ -0,0 +1,35 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenSim.Region.Framework.Scenes; +using OpenMetaverse; + +public interface IUserAccountCacheModule +{ + void Remove(string name); + void Remove(UUID id); +} diff --git a/OpenSim/Region/Framework/Interfaces/IVoiceModule.cs b/OpenSim/Region/Framework/Interfaces/IVoiceModule.cs index 2e555fa..2fe7454 100644 --- a/OpenSim/Region/Framework/Interfaces/IVoiceModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IVoiceModule.cs @@ -40,6 +40,6 @@ namespace OpenSim.Region.Framework.Interfaces /// This is used by osSetParcelSIPAddress /// void setLandSIPAddress(string SIPAddress,UUID GlobalID); - + } } diff --git a/OpenSim/Region/Framework/Interfaces/IWindModelPlugin.cs b/OpenSim/Region/Framework/Interfaces/IWindModelPlugin.cs index 16b6024..b4bc15c 100644 --- a/OpenSim/Region/Framework/Interfaces/IWindModelPlugin.cs +++ b/OpenSim/Region/Framework/Interfaces/IWindModelPlugin.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Update wind. /// - void WindUpdate(uint frame); + bool WindUpdate(uint frame); /// /// Returns the wind vector at the given local region coordinates. diff --git a/OpenSim/Region/Framework/Interfaces/IWindModule.cs b/OpenSim/Region/Framework/Interfaces/IWindModule.cs index 4a26a71..424df87 100644 --- a/OpenSim/Region/Framework/Interfaces/IWindModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IWindModule.cs @@ -31,7 +31,7 @@ namespace OpenSim.Region.Framework.Interfaces { public interface IWindModule : INonSharedRegionModule { - + /// /// Retrieves the current wind speed at the given Region Coordinates /// diff --git a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs index d76a0d7..3da4130 100644 --- a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs +++ b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs @@ -140,7 +140,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// ListenerInfo with filter filled in IWorldCommListenerInfo GetNextMessage(); - + void ListenControl(UUID itemID, int handle, int active); void ListenRemove(UUID itemID, int handle); void DeleteListener(UUID itemID); diff --git a/OpenSim/Region/Framework/Interfaces/IWorldMapModule.cs b/OpenSim/Region/Framework/Interfaces/IWorldMapModule.cs index 9c781e1..ee7c4ec 100644 --- a/OpenSim/Region/Framework/Interfaces/IWorldMapModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IWorldMapModule.cs @@ -36,7 +36,6 @@ namespace OpenSim.Region.Framework.Interfaces /// Generate a map tile for the scene. a terrain texture for this scene /// void GenerateMaptile(); - List Map2BlockFromGridRegion(GridRegion r, uint flag); - MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag); + void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag); } } diff --git a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs index e5a3a4c..f91dfd3 100644 --- a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Mono.Addins; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Region.Framework")] @@ -15,8 +15,8 @@ using Mono.Addins; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -27,10 +27,10 @@ using Mono.Addins; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("0.8.3.*")] +[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] [assembly: AddinRoot("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs index eb1a970..4d350dd 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs @@ -48,16 +48,16 @@ namespace OpenSim.Region.Framework.Scenes.Animation private OpenSim.Framework.Animation m_defaultAnimation = new OpenSim.Framework.Animation(); private List m_animations = new List(); - public OpenSim.Framework.Animation DefaultAnimation + public OpenSim.Framework.Animation DefaultAnimation { - get { return m_defaultAnimation; } + get { return m_defaultAnimation; } } - - public OpenSim.Framework.Animation ImplicitDefaultAnimation + + public OpenSim.Framework.Animation ImplicitDefaultAnimation { - get { return m_implicitDefaultAnimation; } + get { return m_implicitDefaultAnimation; } } - + public AnimationSet() { ResetDefaultAnimation(); @@ -101,7 +101,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// /// /// - /// If true, then the default animation can be entirely removed. + /// If true, then the default animation can be entirely removed. /// If false, then removing the default animation will reset it to the simulator default (currently STAND). /// public bool Remove(UUID animID, bool allowNoDefault) @@ -215,9 +215,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation foreach (OpenSim.Framework.Animation anim in m_animations) theArray[i++] = anim; } - catch + catch { - /* S%^t happens. Ignore. */ + /* S%^t happens. Ignore. */ } return theArray; } diff --git a/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs b/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs index b3b38b2..def993f 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs @@ -33,8 +33,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation { /// /// Written to decode and encode a binary animation asset. - /// The SecondLife Client reads in a BVH file and converts - /// it to the format described here. This isn't + /// The SecondLife Client reads in a BVH file and converts + /// it to the format described here. This isn't /// public class BinBVHAnimation { @@ -109,7 +109,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// Contains an array of joints /// public binBVHJoint[] Joints; - + public byte[] ToBytes() { @@ -136,14 +136,14 @@ namespace OpenSim.Region.Framework.Scenes.Animation Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint); } iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0))); - + using (MemoryStream ms2 = (MemoryStream)iostream.BaseStream) outputbytes = ms2.ToArray(); } return outputbytes; } - + public BinBVHAnimation() { rotationkeys = 0; @@ -160,7 +160,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation EaseOutTime = 0; HandPose = 1; m_jointCount = 0; - + Joints = new binBVHJoint[1]; Joints[0] = new binBVHJoint(); Joints[0].Name = "mPelvis"; @@ -180,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation Joints[0].positionkeys[0].key_element.X = ((float)rnd.NextDouble() * 2 - 1); Joints[0].positionkeys[0].key_element.Y = ((float)rnd.NextDouble() * 2 - 1); Joints[0].positionkeys[0].key_element.Z = ((float)rnd.NextDouble() * 2 - 1); - + } @@ -235,7 +235,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation } } - + /// /// Variable length strings seem to be null terminated in the animation asset.. but.. /// use with caution, home grown. @@ -294,7 +294,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// The Joint data serialized into the binBVHJoint structure private binBVHJoint readJoint(byte[] data, ref int i) { - + binBVHJointKey[] positions; binBVHJointKey[] rotations; @@ -312,14 +312,14 @@ namespace OpenSim.Region.Framework.Scenes.Animation pJoint.Name = ReadBytesUntilNull(data, ref i); // Joint name - /* + /* 2 <- Priority Revisited 0 0 0 */ - /* + /* 5 <-- 5 keyframes 0 0 @@ -327,7 +327,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation ... 5 Keyframe data blocks */ - /* + /* 2 <-- 2 keyframes 0 0 @@ -428,8 +428,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation } return m_keys; } - - + + } /// @@ -443,7 +443,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation public string Name; /// - /// Joint Animation Override? Was the same as the Priority in testing.. + /// Joint Animation Override? Was the same as the Priority in testing.. /// public int Priority; @@ -523,7 +523,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation public static class BinBVHUtil { public const float ONE_OVER_U16_MAX = 1.0f / UInt16.MaxValue; - + public static UInt16 FloatToUInt16(float val, float lower, float upper) { UInt16 uival = 0; @@ -536,7 +536,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation { upper -= lower; val = val - lower; - + // start with 500 upper and 200 lower.. subtract 200 from the upper and the value } else //if (lower < 0 && upper > 0) @@ -558,8 +558,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation return uival; } - - + + /// /// Endian Swap /// Swaps endianness if necessary @@ -590,7 +590,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation output[i] = Convert.ToByte(chr[i]); } - + output[i] = Convert.ToByte('\0'); return output; } diff --git a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs index b79dd8f..2128d58 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs @@ -55,10 +55,14 @@ namespace OpenSim.Region.Framework.Scenes.Animation private static void LoadAnimations(string path) { // Dictionary animations = new Dictionary(); - + using (XmlTextReader reader = new XmlTextReader(path)) { + reader.ProhibitDtd = true; + XmlDocument doc = new XmlDocument(); + doc.XmlResolver = null; + doc.Load(reader); // if (doc.DocumentElement != null) // { diff --git a/OpenSim/Region/Framework/Scenes/Animation/MovementAnimationOverrides.cs b/OpenSim/Region/Framework/Scenes/Animation/MovementAnimationOverrides.cs new file mode 100644 index 0000000..ca3ebfb --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Animation/MovementAnimationOverrides.cs @@ -0,0 +1,102 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Xml; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Timers; +using Timer = System.Timers.Timer; +using OpenMetaverse; +using log4net; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes.Animation; +using OpenSim.Region.Framework.Scenes.Types; +using OpenSim.Region.PhysicsModules.SharedBase; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Services.Interfaces; +using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; + +namespace OpenSim.Region.Framework.Scenes +{ + public class MovementAnimationOverrides + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private object MAOLock = new object(); + private Dictionary m_overrides = new Dictionary(); + public void SetOverride(string state, UUID animID) + { + if (animID == UUID.Zero) + { + if (state == "ALL") + m_overrides.Clear(); + else + m_overrides.Remove(state); + return; + } + + m_log.DebugFormat("Setting override for {0} to {1}", state, animID); + + lock (MAOLock) + m_overrides[state] = animID; + } + + public UUID GetOverriddenAnimation(string state) + { + lock (MAOLock) + { + if (m_overrides.ContainsKey(state)) + return m_overrides[state]; + } + + return UUID.Zero; + } + + public Dictionary CloneAOPairs() + { + lock (MAOLock) + { + return new Dictionary(m_overrides); + } + } + + public void CopyAOPairsFrom(Dictionary src) + { + lock (MAOLock) + { + m_overrides.Clear(); + m_overrides = new Dictionary(src); + } + } + } +} diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index 6d51029..5c33f12 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation public AnimationSet Animations { - get { return m_animations; } + get { return m_animations; } } protected AnimationSet m_animations = new AnimationSet(); @@ -56,39 +56,42 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// The current movement animation /// public string CurrentMovementAnimation { get; private set; } - + private int m_animTickFall; - public int m_animTickJump; // ScenePresence has to see this to control +Z force - public bool m_jumping = false; - public float m_jumpVelocity = 0f; -// private int m_landing = 0; + private int m_animTickLand; + private int m_animTickJump; + + public bool m_jumping = false; + + // private int m_landing = 0; /// /// Is the avatar falling? /// public bool Falling { get; private set; } - private float m_fallHeight; + private float m_lastFallVelocity; /// /// The scene presence that this animator applies to /// protected ScenePresence m_scenePresence; - + public ScenePresenceAnimator(ScenePresence sp) { m_scenePresence = sp; CurrentMovementAnimation = "CROUCH"; } - + public void AddAnimation(UUID animID, UUID objectID) { if (m_scenePresence.IsChildAgent) return; + // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} for {1}", animID, m_scenePresence.Name); if (m_scenePresence.Scene.DebugAnimations) m_log.DebugFormat( - "[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}", + "[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}", GetAnimName(animID), animID, m_scenePresence.Name); if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) @@ -110,7 +113,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation if (animID == UUID.Zero) return; -// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}", animID, name, m_scenePresence.Name); + // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Adding animation {0} {1} for {2}", animID, name, m_scenePresence.Name); AddAnimation(animID, objectID); } @@ -120,7 +123,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// /// /// - /// If true, then the default animation can be entirely removed. + /// If true, then the default animation can be entirely removed. /// If false, then removing the default animation will reset it to the simulator default (currently STAND). /// public void RemoveAnimation(UUID animID, bool allowNoDefault) @@ -130,7 +133,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation if (m_scenePresence.Scene.DebugAnimations) m_log.DebugFormat( - "[SCENE PRESENCE ANIMATOR]: Removing animation {0} {1} for {2}", + "[SCENE PRESENCE ANIMATOR]: Removing animation {0} {1} for {2}", GetAnimName(animID), animID, m_scenePresence.Name); if (m_animations.Remove(animID, allowNoDefault)) @@ -140,6 +143,22 @@ namespace OpenSim.Region.Framework.Scenes.Animation } } + public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack) + { + if (m_scenePresence.IsChildAgent) + return; + + if (animID != UUID.Zero) + { + if (addRemove) + m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, UUID.Zero); + else + m_animations.Remove(animID, false); + } + if (sendPack) + SendAnimPack(); + } + // Called from scripts public void RemoveAnimation(string name) { @@ -164,12 +183,19 @@ namespace OpenSim.Region.Framework.Scenes.Animation m_animations.Clear(); } - + + + UUID aoSitGndAnim = UUID.Zero; + /// /// The movement animation is reserved for "main" animations /// that are mutually exclusive, e.g. flying and sitting. /// /// 'true' if the animation was updated + /// + + + public bool TrySetMovementAnimation(string anim) { bool ret = false; @@ -179,17 +205,50 @@ namespace OpenSim.Region.Framework.Scenes.Animation // "[SCENE PRESENCE ANIMATOR]: Setting movement animation {0} for {1}", // anim, m_scenePresence.Name); - if (m_animations.TrySetDefaultAnimation( - anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID)) + if (aoSitGndAnim != UUID.Zero) + { + avnChangeAnim(aoSitGndAnim, false, true); + aoSitGndAnim = UUID.Zero; + } + + UUID overridenAnim = m_scenePresence.Overrides.GetOverriddenAnimation(anim); + if (overridenAnim != UUID.Zero) { + if (anim == "SITGROUND") + { + UUID defsit = DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]; + if (defsit == UUID.Zero) + return false; + m_animations.SetDefaultAnimation(defsit, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID); + aoSitGndAnim = overridenAnim; + avnChangeAnim(overridenAnim, true, false); + } + else + { + m_animations.SetDefaultAnimation(overridenAnim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID); + } + m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION }); + SendAnimPack(); + ret = true; + } + else + { + // translate sit and sitground state animations + if (anim == "SIT" || anim == "SITGROUND") + anim = m_scenePresence.sitAnimation; + + if (m_animations.TrySetDefaultAnimation( + anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, m_scenePresence.UUID)) + { // m_log.DebugFormat( // "[SCENE PRESENCE ANIMATOR]: Updating movement animation to {0} for {1}", // anim, m_scenePresence.Name); - // 16384 is CHANGED_ANIMATION - m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); - SendAnimPack(); - ret = true; + // 16384 is CHANGED_ANIMATION + m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION }); + SendAnimPack(); + ret = true; + } } } else @@ -201,78 +260,119 @@ namespace OpenSim.Region.Framework.Scenes.Animation return ret; } + public enum motionControlStates : byte + { + sitted = 0, + flying, + falling, + jumping, + landing, + onsurface + } + + public motionControlStates currentControlState = motionControlStates.onsurface; + /// /// This method determines the proper movement related animation /// private string DetermineMovementAnimation() { - const float FALL_DELAY = 800f; - const float PREJUMP_DELAY = 200f; - const float JUMP_PERIOD = 800f; + const int FALL_DELAY = 800; + const int PREJUMP_DELAY = 200; + const int JUMP_PERIOD = 800; #region Inputs + if (m_scenePresence.IsInTransit) + return CurrentMovementAnimation; + + if (m_scenePresence.SitGround) + { + currentControlState = motionControlStates.sitted; + return "SITGROUND"; + } + if (m_scenePresence.ParentID != 0 || m_scenePresence.ParentUUID != UUID.Zero) + { + currentControlState = motionControlStates.sitted; + return "SIT"; + } + AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags; PhysicsActor actor = m_scenePresence.PhysicsActor; - // Create forward and left vectors from the current avatar rotation - Matrix4 rotMatrix = Matrix4.CreateFromQuaternion(m_scenePresence.Rotation); - Vector3 fwd = Vector3.Transform(Vector3.UnitX, rotMatrix); - Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix); + const AgentManager.ControlFlags ANYXYMASK = ( + AgentManager.ControlFlags.AGENT_CONTROL_AT_POS | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS | + AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG | + AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS | + AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG + ); // Check control flags - bool heldForward = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS); - bool heldBack = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG); - bool heldLeft = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS); - bool heldRight = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG); + /* not in use + bool heldForward = ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_AT_POS | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS)) != 0); + bool heldBack = ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG)) != 0); + bool heldLeft = ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS)) != 0); + bool heldRight = ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG)) != 0); + */ bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; - bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; - bool heldDown = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG; + // bool heldUp = ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_UP_POS | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS)) != 0); + // excluded nudge up so it doesn't trigger jump state + bool heldUp = ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_UP_POS)) != 0); + bool heldDown = ((controlFlags & (AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG)) != 0); //bool flying = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) == AgentManager.ControlFlags.AGENT_CONTROL_FLY; //bool mouselook = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) == AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK; - if (heldForward || heldBack || heldLeft || heldRight || heldUp || heldDown) + + bool heldOnXY = ((controlFlags & ANYXYMASK) != 0); + if (heldOnXY || heldUp || heldDown) { heldTurnLeft = false; heldTurnRight = false; } - // Direction in which the avatar is trying to move - Vector3 move = Vector3.Zero; - if (heldForward) { move.X += fwd.X; move.Y += fwd.Y; } - if (heldBack) { move.X -= fwd.X; move.Y -= fwd.Y; } - if (heldLeft) { move.X += left.X; move.Y += left.Y; } - if (heldRight) { move.X -= left.X; move.Y -= left.Y; } - if (heldUp) { move.Z += 1; } - if (heldDown) { move.Z -= 1; } - - // Is the avatar trying to move? -// bool moving = (move != Vector3.Zero); #endregion Inputs + // no physics actor case + if (actor == null) + { + // well what to do? + + currentControlState = motionControlStates.onsurface; + if (heldOnXY) + return "WALK"; + + return "STAND"; + } + #region Flying - if (actor != null && actor.Flying) + bool isColliding = actor.IsColliding; + + if (actor.Flying) { m_animTickFall = 0; m_animTickJump = 0; m_jumping = false; Falling = false; - m_jumpVelocity = 0f; - actor.Selected = false; - m_fallHeight = actor.Position.Z; // save latest flying height - if (move.X != 0f || move.Y != 0f) + currentControlState = motionControlStates.flying; + + if (heldOnXY) { return (m_scenePresence.Scene.m_useFlySlow ? "FLYSLOW" : "FLY"); } - else if (move.Z > 0f) + else if (heldUp) { return "HOVER_UP"; } - else if (move.Z < 0f) + else if (heldDown) { - if (actor != null && actor.IsColliding) + if (isColliding) + { + actor.Flying = false; + currentControlState = motionControlStates.landing; + m_animTickLand = Environment.TickCount; return "LAND"; + } else return "HOVER_DOWN"; } @@ -281,128 +381,151 @@ namespace OpenSim.Region.Framework.Scenes.Animation return "HOVER"; } } + else + { + if (isColliding && currentControlState == motionControlStates.flying) + { + currentControlState = motionControlStates.landing; + m_animTickLand = Environment.TickCount; + return "LAND"; + } + } #endregion Flying #region Falling/Floating/Landing - if ((actor == null || !actor.IsColliding) && !m_jumping) + if (!isColliding && currentControlState != motionControlStates.jumping) { - float fallElapsed = (float)(Environment.TickCount - m_animTickFall); - float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f; + float fallVelocity = actor.Velocity.Z; - if (!m_jumping && (fallVelocity < -3.0f)) + // if stable on Hover assume falling + if(actor.PIDHoverActive && fallVelocity < 0.05f) + { Falling = true; + currentControlState = motionControlStates.falling; + m_lastFallVelocity = fallVelocity; + return "FALLDOWN"; + } - if (m_animTickFall == 0 || (fallVelocity >= 0.0f)) + if (fallVelocity < -2.5f) + Falling = true; + + if (m_animTickFall == 0 || (fallVelocity >= -0.5f)) { - // not falling yet, or going up - // reset start of fall time m_animTickFall = Environment.TickCount; } - else if (!m_jumping && (fallElapsed > FALL_DELAY) && (fallVelocity < -3.0f) && (m_scenePresence.WasFlying)) + else { - // Falling long enough to trigger the animation - return "FALLDOWN"; + int fallElapsed = (Environment.TickCount - m_animTickFall); + if ((fallElapsed > FALL_DELAY) && (fallVelocity < -3.0f)) + { + currentControlState = motionControlStates.falling; + m_lastFallVelocity = fallVelocity; + // Falling long enough to trigger the animation + return "FALLDOWN"; + } } // Check if the user has stopped walking just now - if (CurrentMovementAnimation == "WALK" && (move == Vector3.Zero)) + if (CurrentMovementAnimation == "WALK" && !heldOnXY && !heldDown && !heldUp) return "STAND"; return CurrentMovementAnimation; } - #endregion Falling/Floating/Landing + m_animTickFall = 0; + #endregion Falling/Floating/Landing #region Jumping // section added for jumping... - int jumptime; - jumptime = Environment.TickCount - m_animTickJump; - - if ((move.Z > 0f) && (!m_jumping)) + if (isColliding && heldUp && currentControlState != motionControlStates.jumping && !actor.PIDHoverActive) { // Start jumping, prejump - m_animTickFall = 0; + currentControlState = motionControlStates.jumping; m_jumping = true; Falling = false; - actor.Selected = true; // borrowed for jumping flag m_animTickJump = Environment.TickCount; - m_jumpVelocity = 0.35f; return "PREJUMP"; } - if (m_jumping) + if (currentControlState == motionControlStates.jumping) { + int jumptime = Environment.TickCount - m_animTickJump; if ((jumptime > (JUMP_PERIOD * 1.5f)) && actor.IsColliding) { // end jumping m_jumping = false; Falling = false; actor.Selected = false; // borrowed for jumping flag - m_jumpVelocity = 0f; - m_animTickFall = Environment.TickCount; + m_animTickLand = Environment.TickCount; + currentControlState = motionControlStates.landing; return "LAND"; } else if (jumptime > JUMP_PERIOD) { // jump down - m_jumpVelocity = 0f; return "JUMP"; } else if (jumptime > PREJUMP_DELAY) { // jump up m_jumping = true; - m_jumpVelocity = 10f; return "JUMP"; } + return CurrentMovementAnimation; } #endregion Jumping #region Ground Movement - if (CurrentMovementAnimation == "FALLDOWN") + if (currentControlState == motionControlStates.falling) { Falling = false; - m_animTickFall = Environment.TickCount; + currentControlState = motionControlStates.landing; + m_animTickLand = Environment.TickCount; // TODO: SOFT_LAND support - float fallHeight = m_fallHeight - actor.Position.Z; - if (fallHeight > 15.0f) + float fallVsq = m_lastFallVelocity * m_lastFallVelocity; + if (fallVsq > 300f) // aprox 20*h return "STANDUP"; - else if (fallHeight > 8.0f) + else if (fallVsq > 160f) return "SOFT_LAND"; else return "LAND"; } - else if ((CurrentMovementAnimation == "LAND") || (CurrentMovementAnimation == "SOFT_LAND") || (CurrentMovementAnimation == "STANDUP")) + + + if (currentControlState == motionControlStates.landing) { - int landElapsed = Environment.TickCount - m_animTickFall; + Falling = false; + int landElapsed = Environment.TickCount - m_animTickLand; int limit = 1000; if (CurrentMovementAnimation == "LAND") limit = 350; // NB if the above is set too long a weird anim reset from some place prevents STAND from being sent to client - if ((m_animTickFall != 0) && (landElapsed <= limit)) + if ((m_animTickLand != 0) && (landElapsed <= limit)) { return CurrentMovementAnimation; } else { - m_fallHeight = actor.Position.Z; // save latest flying height + currentControlState = motionControlStates.onsurface; + m_animTickLand = 0; return "STAND"; } } // next section moved outside paren. and realigned for jumping - if (move.X != 0f || move.Y != 0f) + + if (heldOnXY) { - m_fallHeight = actor.Position.Z; // save latest flying height + currentControlState = motionControlStates.onsurface; Falling = false; // Walking / crouchwalking / running - if (move.Z < 0f) + if (heldDown) { return "CROUCHWALK"; } @@ -416,11 +539,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation return "WALK"; } } - else if (!m_jumping) + else { + currentControlState = motionControlStates.onsurface; Falling = false; // Not walking - if (move.Z < 0) + if (heldDown) return "CROUCH"; else if (heldTurnLeft) return "TURNLEFT"; @@ -431,8 +555,6 @@ namespace OpenSim.Region.Framework.Scenes.Animation } #endregion Ground Movement - Falling = false; - return CurrentMovementAnimation; } @@ -442,7 +564,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// 'true' if the animation was changed public bool UpdateMovementAnimations() { -// m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Updating movement animations for {0}", m_scenePresence.Name); + // m_log.DebugFormat("[SCENE PRESENCE ANIMATOR]: Updating movement animations for {0}", m_scenePresence.Name); bool ret = false; lock (m_animations) @@ -450,7 +572,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation string newMovementAnimation = DetermineMovementAnimation(); if (CurrentMovementAnimation != newMovementAnimation) { - CurrentMovementAnimation = DetermineMovementAnimation(); + CurrentMovementAnimation = newMovementAnimation; // m_log.DebugFormat( // "[SCENE PRESENCE ANIMATOR]: Determined animation {0} for {1} in UpdateMovementAnimations()", @@ -464,6 +586,24 @@ namespace OpenSim.Region.Framework.Scenes.Animation return ret; } + public bool ForceUpdateMovementAnimations() + { + lock (m_animations) + { + CurrentMovementAnimation = DetermineMovementAnimation(); + return TrySetMovementAnimation(CurrentMovementAnimation); + } + } + + public bool SetMovementAnimations(string motionState) + { + lock (m_animations) + { + CurrentMovementAnimation = motionState; + return TrySetMovementAnimation(CurrentMovementAnimation); + } + } + public UUID[] GetAnimationArray() { UUID[] animIDs; @@ -472,19 +612,153 @@ namespace OpenSim.Region.Framework.Scenes.Animation m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs); return animIDs; } - + public BinBVHAnimation GenerateRandomAnimation() { int rnditerations = 3; BinBVHAnimation anim = new BinBVHAnimation(); List parts = new List(); - parts.Add("mPelvis");parts.Add("mHead");parts.Add("mTorso"); - parts.Add("mHipLeft");parts.Add("mHipRight");parts.Add("mHipLeft");parts.Add("mKneeLeft"); - parts.Add("mKneeRight");parts.Add("mCollarLeft");parts.Add("mCollarRight");parts.Add("mNeck"); - parts.Add("mElbowLeft");parts.Add("mElbowRight");parts.Add("mWristLeft");parts.Add("mWristRight"); - parts.Add("mShoulderLeft");parts.Add("mShoulderRight");parts.Add("mAnkleLeft");parts.Add("mAnkleRight"); - parts.Add("mEyeRight");parts.Add("mChest");parts.Add("mToeLeft");parts.Add("mToeRight"); - parts.Add("mFootLeft");parts.Add("mFootRight");parts.Add("mEyeLeft"); + + /// Torso and Head + parts.Add("mPelvis"); + parts.Add("mTorso"); + parts.Add("mChest"); + parts.Add("mNeck"); + parts.Add("mHead"); + parts.Add("mSkull"); + parts.Add("mEyeRight"); + parts.Add("mEyeLeft"); + /// Arms + parts.Add("mCollarLeft"); + parts.Add("mShoulderLeft"); + parts.Add("mElbowLeft"); + parts.Add("mWristLeft"); + parts.Add("mCollarRight"); + parts.Add("mShoulderRight"); + parts.Add("mElbowRight"); + parts.Add("mWristRight"); + /// Legs + parts.Add("mHipLeft"); + parts.Add("mKneeLeft"); + parts.Add("mAnkleLeft"); + parts.Add("mFootLeft"); + parts.Add("mToeLeft"); + parts.Add("mHipRight"); + parts.Add("mKneeRight"); + parts.Add("mAnkleRight"); + parts.Add("mFootRight"); + parts.Add("mToeRight"); + ///Hands + parts.Add("mHandThumb1Left"); + parts.Add("mHandThumb1Right"); + parts.Add("mHandThumb2Left"); + parts.Add("mHandThumb2Right"); + parts.Add("mHandThumb3Left"); + parts.Add("mHandThumb3Right"); + parts.Add("mHandIndex1Left"); + parts.Add("mHandIndex1Right"); + parts.Add("mHandIndex2Left"); + parts.Add("mHandIndex2Right"); + parts.Add("mHandIndex3Left"); + parts.Add("mHandIndex3Right"); + parts.Add("mHandMiddle1Left"); + parts.Add("mHandMiddle1Right"); + parts.Add("mHandMiddle2Left"); + parts.Add("mHandMiddle2Right"); + parts.Add("mHandMiddle3Left"); + parts.Add("mHandMiddle3Right"); + parts.Add("mHandRing1Left"); + parts.Add("mHandRing1Right"); + parts.Add("mHandRing2Left"); + parts.Add("mHandRing2Right"); + parts.Add("mHandRing3Left"); + parts.Add("mHandRing3Right"); + parts.Add("mHandPinky1Left"); + parts.Add("mHandPinky1Right"); + parts.Add("mHandPinky2Left"); + parts.Add("mHandPinky2Right"); + parts.Add("mHandPinky3Left"); + parts.Add("mHandPinky3Right"); + ///Face + parts.Add("mFaceForeheadLeft"); + parts.Add("mFaceForeheadCenter"); + parts.Add("mFaceForeheadRight"); + parts.Add("mFaceEyebrowOuterLeft"); + parts.Add("mFaceEyebrowCenterLeft"); + parts.Add("mFaceEyebrowInnerLeft"); + parts.Add("mFaceEyebrowOuterRight"); + parts.Add("mFaceEyebrowCenterRight"); + parts.Add("mFaceEyebrowInnerRight"); + parts.Add("mFaceEyeLidUpperLeft"); + parts.Add("mFaceEyeLidLowerLeft"); + parts.Add("mFaceEyeLidUpperRight"); + parts.Add("mFaceEyeLidLowerRight"); + parts.Add("mFaceEyeAltLeft"); + parts.Add("mFaceEyeAltRight"); + parts.Add("mFaceEyecornerInnerLeft"); + parts.Add("mFaceEyecornerInnerRight"); + parts.Add("mFaceEar1Left"); + parts.Add("mFaceEar2Left"); + parts.Add("mFaceEar1Right"); + parts.Add("mFaceEar2Right"); + parts.Add("mFaceNoseLeft"); + parts.Add("mFaceNoseCenter"); + parts.Add("mFaceNoseRight"); + parts.Add("mFaceNoseBase"); + parts.Add("mFaceNoseBridge"); + parts.Add("mFaceCheekUpperInnerLeft"); + parts.Add("mFaceCheekUpperOuterLeft"); + parts.Add("mFaceCheekUpperInnerRight"); + parts.Add("mFaceCheekUpperOuterRight"); + parts.Add("mFaceJaw"); + parts.Add("mFaceLipUpperLeft"); + parts.Add("mFaceLipUpperCenter"); + parts.Add("mFaceLipUpperRight"); + parts.Add("mFaceLipCornerLeft"); + parts.Add("mFaceLipCornerRight"); + parts.Add("mFaceTongueBase"); + parts.Add("mFaceTongueTip"); + parts.Add("mFaceLipLowerLeft"); + parts.Add("mFaceLipLowerCenter"); + parts.Add("mFaceLipLowerRight"); + parts.Add("mFaceTeethLower"); + parts.Add("mFaceTeethUpper"); + parts.Add("mFaceChin"); + ///Spine + parts.Add("mSpine1"); + parts.Add("mSpine2"); + parts.Add("mSpine3"); + parts.Add("mSpine4"); + ///Wings + parts.Add("mWingsRoot"); + parts.Add("mWing1Left"); + parts.Add("mWing2Left"); + parts.Add("mWing3Left"); + parts.Add("mWing4Left"); + parts.Add("mWing1Right"); + parts.Add("mWing2Right"); + parts.Add("mWing3Right"); + parts.Add("mWing4Right"); + parts.Add("mWing4FanRight"); + parts.Add("mWing4FanLeft"); + ///Hind Limbs + parts.Add("mHindLimbsRoot"); + parts.Add("mHindLimb1Left"); + parts.Add("mHindLimb2Left"); + parts.Add("mHindLimb3Left"); + parts.Add("mHindLimb4Left"); + parts.Add("mHindLimb1Right"); + parts.Add("mHindLimb2Right"); + parts.Add("mHindLimb3Right"); + parts.Add("mHindLimb4Right"); + ///Tail + parts.Add("mTail1"); + parts.Add("mTail2"); + parts.Add("mTail3"); + parts.Add("mTail4"); + parts.Add("mTail5"); + parts.Add("mTail6"); + anim.HandPose = 1; anim.InPoint = 0; anim.OutPoint = (rnditerations * .10f); @@ -508,12 +782,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation for (int i = 0; i < rnditerations; i++) { anim.Joints[j].rotationkeys[i] = new binBVHJointKey(); - anim.Joints[j].rotationkeys[i].time = (i*.10f); - anim.Joints[j].rotationkeys[i].key_element.X = ((float) rnd.NextDouble()*2 - 1); - anim.Joints[j].rotationkeys[i].key_element.Y = ((float) rnd.NextDouble()*2 - 1); - anim.Joints[j].rotationkeys[i].key_element.Z = ((float) rnd.NextDouble()*2 - 1); + anim.Joints[j].rotationkeys[i].time = (i * .10f); + anim.Joints[j].rotationkeys[i].key_element.X = ((float)rnd.NextDouble() * 2 - 1); + anim.Joints[j].rotationkeys[i].key_element.Y = ((float)rnd.NextDouble() * 2 - 1); + anim.Joints[j].rotationkeys[i].key_element.Z = ((float)rnd.NextDouble() * 2 - 1); anim.Joints[j].positionkeys[i] = new binBVHJointKey(); - anim.Joints[j].positionkeys[i].time = (i*.10f); + anim.Joints[j].positionkeys[i].time = (i * .10f); anim.Joints[j].positionkeys[i].key_element.X = 0; anim.Joints[j].positionkeys[i].key_element.Y = 0; anim.Joints[j].positionkeys[i].key_element.Z = 0; @@ -540,20 +814,17 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// public void SendAnimPack(UUID[] animations, int[] seqs, UUID[] objectIDs) { - if (m_scenePresence.IsChildAgent) - return; + m_scenePresence.SendAnimPack(animations, seqs, objectIDs); + } -// m_log.DebugFormat( -// "[SCENE PRESENCE ANIMATOR]: Sending anim pack with animations '{0}', sequence '{1}', uuids '{2}'", -// string.Join(",", Array.ConvertAll(animations, a => a.ToString())), -// string.Join(",", Array.ConvertAll(seqs, s => s.ToString())), -// string.Join(",", Array.ConvertAll(objectIDs, o => o.ToString()))); - - m_scenePresence.Scene.ForEachClient( - delegate(IClientAPI client) - { - client.SendAnimations(animations, seqs, m_scenePresence.ControllingClient.AgentId, objectIDs); - }); + public void GetArrays(out UUID[] animIDs, out int[] sequenceNums, out UUID[] objectIDs) + { + animIDs = null; + sequenceNums = null; + objectIDs = null; + + if (m_animations != null) + m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs); } public void SendAnimPackToClient(IClientAPI client) @@ -575,7 +846,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation public void SendAnimPack() { //m_log.Debug("Sending animation pack to all"); - + if (m_scenePresence.IsChildAgent) return; @@ -585,7 +856,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs); - SendAnimPack(animIDs, sequenceNums, objectIDs); + // SendAnimPack(animIDs, sequenceNums, objectIDs); + m_scenePresence.SendAnimPack(animIDs, sequenceNums, objectIDs); } public string GetAnimName(UUID animId) diff --git a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs index d9d2e64..c874fdb 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs @@ -143,14 +143,13 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[ASYNC INVENTORY SENDER]: Handling request from {0} for {1} on queue", fh.Client.Name, fh.ItemID); - InventoryItemBase item = new InventoryItemBase(fh.ItemID, fh.Client.AgentId); - item = m_scene.InventoryService.GetItem(item); - + InventoryItemBase item = m_scene.InventoryService.GetItem(fh.Client.AgentId, fh.ItemID); + if (item != null) fh.Client.SendInventoryItemDetails(item.Owner, item); - + // TODO: Possibly log any failure } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index 11a0146..7509686 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -44,29 +44,29 @@ namespace OpenSim.Region.Framework.Scenes public UUID folderID; public bool permissionToDelete; } - + /// - /// Asynchronously derez objects. This is used to derez large number of objects to inventory without holding + /// Asynchronously derez objects. This is used to derez large number of objects to inventory without holding /// up the main client thread. /// public class AsyncSceneObjectGroupDeleter { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + /// /// Is the deleter currently enabled? /// public bool Enabled; - + private Timer m_inventoryTicker = new Timer(2000); private readonly Queue m_inventoryDeletes = new Queue(); private Scene m_scene; - + public AsyncSceneObjectGroupDeleter(Scene scene) { m_scene = scene; - + m_inventoryTicker.AutoReset = false; m_inventoryTicker.Elapsed += InventoryRunDeleteTimer; } @@ -75,7 +75,7 @@ namespace OpenSim.Region.Framework.Scenes /// Delete the given object from the scene /// public void DeleteToInventory(DeRezAction action, UUID folderID, - List objectGroups, IClientAPI remoteClient, + List objectGroups, IClientAPI remoteClient, bool permissionToDelete) { if (Enabled) @@ -97,7 +97,7 @@ namespace OpenSim.Region.Framework.Scenes if (Enabled) lock (m_inventoryTicker) m_inventoryTicker.Start(); - + // Visually remove it, even if it isnt really gone yet. This means that if we crash before the object // has gone to inventory, it will reappear in the region again on restart instead of being lost. // This is not ideal since the object will still be available for manipulation when it should be, but it's @@ -108,7 +108,7 @@ namespace OpenSim.Region.Framework.Scenes g.DeleteGroupFromScene(false); } } - + private void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e) { // m_log.Debug("[ASYNC DELETER]: Starting send to inventory loop"); @@ -116,8 +116,8 @@ namespace OpenSim.Region.Framework.Scenes // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved // in a culture where decimal points are commas and then reloaded in a culture which just treats them as // number seperators. - Culture.SetCurrentCulture(); - + Culture.SetCurrentCulture(); + while (InventoryDeQueueAndDelete()) { //m_log.Debug("[ASYNC DELETER]: Sent item successfully to inventory, continuing..."); @@ -131,7 +131,7 @@ namespace OpenSim.Region.Framework.Scenes public bool InventoryDeQueueAndDelete() { DeleteToInventoryHolder x = null; - + try { lock (m_inventoryDeletes) @@ -144,13 +144,13 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[ASYNC DELETER]: Sending object to user's inventory, action {1}, count {2}, {0} item(s) remaining.", // left, x.action, x.objectGroups.Count); - + try { IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); if (invAccess != null) invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient, false); - + if (x.permissionToDelete) { foreach (SceneObjectGroup g in x.objectGroups) @@ -162,7 +162,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat( "[ASYNC DELETER]: Exception background sending object: {0}{1}", e.Message, e.StackTrace); } - + return true; } } @@ -173,14 +173,14 @@ namespace OpenSim.Region.Framework.Scenes // FIXME: This needs to be fixed. m_log.ErrorFormat( "[ASYNC DELETER]: Queued sending of scene object to agent {0} {1} failed: {2} {3}", - (x != null ? x.remoteClient.Name : "unavailable"), - (x != null ? x.remoteClient.AgentId.ToString() : "unavailable"), - e.Message, + (x != null ? x.remoteClient.Name : "unavailable"), + (x != null ? x.remoteClient.AgentId.ToString() : "unavailable"), + e.Message, e.StackTrace); } // m_log.Debug("[ASYNC DELETER]: No objects left in inventory send queue."); - + return false; } } diff --git a/OpenSim/Region/Framework/Scenes/Border.cs b/OpenSim/Region/Framework/Scenes/Border.cs deleted file mode 100644 index 08c0c31..0000000 --- a/OpenSim/Region/Framework/Scenes/Border.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Framework.Scenes -{ - public class Border - { - /// - /// Line perpendicular to the Direction Cardinal. Z value is the - /// - public Vector3 BorderLine = Vector3.Zero; - - /// - /// Direction cardinal of the border, think, 'which side of the region this is'. EX South border: Cardinal.S - /// - public Cardinals CrossDirection = Cardinals.N; - public uint TriggerRegionX = 0; - public uint TriggerRegionY = 0; - - public Border() - { - } - - /// - /// Creates a Border. The line is perpendicular to the direction cardinal. - /// IE: if the direction cardinal is South, the line is West->East - /// - /// The starting point for the line of the border. - /// The position of an object must be greater then this for this border to trigger. - /// Perpendicular to the direction cardinal - /// The ending point for the line of the border. - /// The position of an object must be less then this for this border to trigger. - /// Perpendicular to the direction cardinal - /// The position that triggers border the border - /// cross parallel to the direction cardinal. On the North cardinal, this - /// normally 256. On the South cardinal, it's normally 0. Any position past this - /// point on the cartesian coordinate will trigger the border cross as long as it - /// falls within the line start and the line end. - /// When this border triggers, teleport to this regionX - /// in the grid - /// When this border triggers, teleport to this regionY - /// in the grid - /// Cardinal for border direction. Think, 'which side of the - /// region is this' - public Border(float lineStart, float lineEnd, float triggerCoordinate, uint triggerRegionX, - uint triggerRegionY, Cardinals direction) - { - BorderLine = new Vector3(lineStart,lineEnd,triggerCoordinate); - CrossDirection = direction; - TriggerRegionX = triggerRegionX; - TriggerRegionY = triggerRegionY; - } - - /// - /// Tests to see if the given position would cross this border. - /// - /// - public bool TestCross(Vector3 position) - { - bool result = false; - switch (CrossDirection) - { - case Cardinals.N: // x+0, y+1 - if (position.X >= BorderLine.X && position.X <= BorderLine.Y && position.Y > BorderLine.Z) - { - return true; - } - break; - case Cardinals.NE: // x+1, y+1 - break; - case Cardinals.E: // x+1, y+0 - if (position.Y >= BorderLine.X && position.Y <= BorderLine.Y && position.X > BorderLine.Z) - { - return true; - } - break; - case Cardinals.SE: // x+1, y-1 - break; - case Cardinals.S: // x+0, y-1 - if (position.X >= BorderLine.X && position.X <= BorderLine.Y && position.Y < BorderLine.Z) - { - return true; - } - break; - case Cardinals.SW: // x-1, y-1 - break; - case Cardinals.W: // x-1, y+0 - if (position.Y >= BorderLine.X && position.Y <= BorderLine.Y && position.X < BorderLine.Z) - { - return true; - } - break; - case Cardinals.NW: // x-1, y+1 - break; - } - - return result; - } - - public float Extent - { - get - { - switch (CrossDirection) - { - case Cardinals.N: - break; - case Cardinals.S: - break; - case Cardinals.W: - break; - case Cardinals.E: - break; - } - return 0; - } - } - } -} diff --git a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs index af8ccda..8831764 100644 --- a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs +++ b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs @@ -37,12 +37,12 @@ namespace OpenSim.Region.Framework.Scenes /// are grouped together. /// public class CoalescedSceneObjects - { + { /// /// The creator of this coalesence, though not necessarily the objects within it. /// public UUID CreatorId { get; set; } - + /// /// The number of objects in this coalesence /// @@ -54,12 +54,12 @@ namespace OpenSim.Region.Framework.Scenes return m_memberObjects.Count; } } - + /// /// Does this coalesence have any member objects? /// public bool HasObjects { get { return Count > 0; } } - + /// /// Get the objects currently in this coalescence /// @@ -70,13 +70,13 @@ namespace OpenSim.Region.Framework.Scenes lock (m_memberObjects) return new List(m_memberObjects); } - } - + } + /// /// Get the scene that contains the objects in this coalescence. If there are no objects then null is returned. /// - public Scene Scene - { + public Scene Scene + { get { if (!HasObjects) @@ -85,24 +85,24 @@ namespace OpenSim.Region.Framework.Scenes return Objects[0].Scene; } } - + /// /// At this point, we need to preserve the order of objects added to the coalescence, since the first /// one will end up matching the item name when rerezzed. /// protected List m_memberObjects = new List(); - - public CoalescedSceneObjects(UUID creatorId) + + public CoalescedSceneObjects(UUID creatorId) { CreatorId = creatorId; } - + public CoalescedSceneObjects(UUID creatorId, params SceneObjectGroup[] objs) : this(creatorId) - { + { foreach (SceneObjectGroup obj in objs) Add(obj); } - + /// /// Add an object to the coalescence. /// @@ -113,7 +113,7 @@ namespace OpenSim.Region.Framework.Scenes lock (m_memberObjects) m_memberObjects.Add(obj); } - + /// /// Removes a scene object from the coalescene /// @@ -124,7 +124,7 @@ namespace OpenSim.Region.Framework.Scenes lock (m_memberObjects) return m_memberObjects.Remove(obj); } - + /// /// Get the total size of the coalescence (the size required to cover all the objects within it) and the /// offsets of each of those objects. @@ -138,16 +138,16 @@ namespace OpenSim.Region.Framework.Scenes float minX, minY, minZ; float maxX, maxY, maxZ; - Vector3[] offsets + Vector3[] offsets = Scene.GetCombinedBoundingBox( Objects, out minX, out maxX, out minY, out maxY, out minZ, out maxZ); - + float sizeX = maxX - minX; float sizeY = maxY - minY; float sizeZ = maxZ - minZ; - + size = new Vector3(sizeX, sizeY, sizeZ); - + return offsets; } } diff --git a/OpenSim/Region/Framework/Scenes/CollisionSounds.cs b/OpenSim/Region/Framework/Scenes/CollisionSounds.cs new file mode 100644 index 0000000..63aafcd --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/CollisionSounds.cs @@ -0,0 +1,342 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +// Ubit 2012 + +using System; +using System.Reflection; +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; +using log4net; + +namespace OpenSim.Region.Framework.Scenes +{ + public struct CollisionForSoundInfo + { + public uint colliderID; + public Vector3 position; + public float relativeVel; + } + + public static class CollisionSounds + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private const int MaxMaterials = 7; + // part part + + private static UUID snd_StoneStone = new UUID("be7295c0-a158-11e1-b3dd-0800200c9a66"); + private static UUID snd_StoneMetal = new UUID("be7295c0-a158-11e1-b3dd-0800201c9a66"); + private static UUID snd_StoneGlass = new UUID("be7295c0-a158-11e1-b3dd-0800202c9a66"); + private static UUID snd_StoneWood = new UUID("be7295c0-a158-11e1-b3dd-0800203c9a66"); + private static UUID snd_StoneFlesh = new UUID("be7295c0-a158-11e1-b3dd-0800204c9a66"); + private static UUID snd_StonePlastic = new UUID("be7295c0-a158-11e1-b3dd-0800205c9a66"); + private static UUID snd_StoneRubber = new UUID("be7295c0-a158-11e1-b3dd-0800206c9a66"); + + private static UUID snd_MetalMetal = new UUID("be7295c0-a158-11e1-b3dd-0801201c9a66"); + private static UUID snd_MetalGlass = new UUID("be7295c0-a158-11e1-b3dd-0801202c9a66"); + private static UUID snd_MetalWood = new UUID("be7295c0-a158-11e1-b3dd-0801203c9a66"); + private static UUID snd_MetalFlesh = new UUID("be7295c0-a158-11e1-b3dd-0801204c9a66"); + private static UUID snd_MetalPlastic = new UUID("be7295c0-a158-11e1-b3dd-0801205c9a66"); + private static UUID snd_MetalRubber = new UUID("be7295c0-a158-11e1-b3dd-0801206c9a66"); + + private static UUID snd_GlassGlass = new UUID("be7295c0-a158-11e1-b3dd-0802202c9a66"); + private static UUID snd_GlassWood = new UUID("be7295c0-a158-11e1-b3dd-0802203c9a66"); + private static UUID snd_GlassFlesh = new UUID("be7295c0-a158-11e1-b3dd-0802204c9a66"); + private static UUID snd_GlassPlastic = new UUID("be7295c0-a158-11e1-b3dd-0802205c9a66"); + private static UUID snd_GlassRubber = new UUID("be7295c0-a158-11e1-b3dd-0802206c9a66"); + + private static UUID snd_WoodWood = new UUID("be7295c0-a158-11e1-b3dd-0803203c9a66"); + private static UUID snd_WoodFlesh = new UUID("be7295c0-a158-11e1-b3dd-0803204c9a66"); + private static UUID snd_WoodPlastic = new UUID("be7295c0-a158-11e1-b3dd-0803205c9a66"); + private static UUID snd_WoodRubber = new UUID("be7295c0-a158-11e1-b3dd-0803206c9a66"); + + private static UUID snd_FleshFlesh = new UUID("be7295c0-a158-11e1-b3dd-0804204c9a66"); + private static UUID snd_FleshPlastic = new UUID("be7295c0-a158-11e1-b3dd-0804205c9a66"); + private static UUID snd_FleshRubber = new UUID("be7295c0-a158-11e1-b3dd-0804206c9a66"); + + private static UUID snd_PlasticPlastic = new UUID("be7295c0-a158-11e1-b3dd-0805205c9a66"); + private static UUID snd_PlasticRubber = new UUID("be7295c0-a158-11e1-b3dd-0805206c9a66"); + + private static UUID snd_RubberRubber = new UUID("be7295c0-a158-11e1-b3dd-0806206c9a66"); + + // terrain part + private static UUID snd_TerrainStone = new UUID("be7295c0-a158-11e1-b3dd-0807200c9a66"); + private static UUID snd_TerrainMetal = new UUID("be7295c0-a158-11e1-b3dd-0807200c9a66"); + private static UUID snd_TerrainGlass = new UUID("be7295c0-a158-11e1-b3dd-0807200c9a66"); + private static UUID snd_TerrainWood = new UUID("be7295c0-a158-11e1-b3dd-0807200c9a66"); + private static UUID snd_TerrainFlesh = new UUID("be7295c0-a158-11e1-b3dd-0807200c9a66"); + private static UUID snd_TerrainPlastic = new UUID("be7295c0-a158-11e1-b3dd-0807200c9a66"); + private static UUID snd_TerrainRubber = new UUID("be7295c0-a158-11e1-b3dd-0807200c9a66"); + + public static UUID[] m_TerrainPart = { + snd_TerrainStone, + snd_TerrainMetal, + snd_TerrainGlass, + snd_TerrainWood, + snd_TerrainFlesh, + snd_TerrainPlastic, + snd_TerrainRubber + }; + + // simetric sounds + public static UUID[] m_PartPart = { + snd_StoneStone, snd_StoneMetal, snd_StoneGlass, snd_StoneWood, snd_StoneFlesh, snd_StonePlastic, snd_StoneRubber, + snd_StoneMetal, snd_MetalMetal, snd_MetalGlass, snd_MetalWood, snd_MetalFlesh, snd_MetalPlastic, snd_MetalRubber, + snd_StoneGlass, snd_MetalGlass, snd_GlassGlass, snd_GlassWood, snd_GlassFlesh, snd_GlassPlastic, snd_GlassRubber, + snd_StoneWood, snd_MetalWood, snd_GlassWood, snd_WoodWood, snd_WoodFlesh, snd_WoodPlastic, snd_WoodRubber, + snd_StoneFlesh, snd_MetalFlesh, snd_GlassFlesh, snd_WoodFlesh, snd_FleshFlesh, snd_FleshPlastic, snd_FleshRubber, + snd_StonePlastic, snd_MetalPlastic, snd_GlassPlastic, snd_WoodPlastic, snd_FleshPlastic, snd_PlasticPlastic, snd_PlasticRubber, + snd_StoneRubber, snd_MetalRubber, snd_GlassRubber, snd_WoodRubber, snd_FleshRubber, snd_PlasticRubber, snd_RubberRubber + }; + + public static void PartCollisionSound(SceneObjectPart part, List collidersinfolist) + { + if (part.CollisionSoundType < 0) + return; + + if (collidersinfolist.Count == 0 || part == null) + return; + + if (part.VolumeDetectActive || (part.Flags & PrimFlags.Physics) == 0) + return; + + SceneObjectGroup sog = part.ParentGroup; + if (sog == null || sog.IsDeleted || sog.inTransit) + return; + + if(sog.CollisionSoundThrottled(part.CollisionSoundType)) + return; + + float volume = part.CollisionSoundVolume; + + UUID soundID = part.CollisionSound; + + bool HaveSound = false; + switch (part.CollisionSoundType) + { + case 0: // default sounds + volume = 1.0f; + break; + case 1: // selected sound + if(soundID == part.invalidCollisionSoundUUID) + return; + HaveSound = true; + break; + case 2: // default sounds with volume set by script + default: + break; + } + + if (volume == 0.0f) + return; + + bool doneownsound = false; + + int thisMaterial = (int)part.Material; + if (thisMaterial >= MaxMaterials) + thisMaterial = 3; + int thisMatScaled = thisMaterial * MaxMaterials; + + CollisionForSoundInfo colInfo; + uint id; + + for(int i = 0; i < collidersinfolist.Count; i++) + { + colInfo = collidersinfolist[i]; + + id = colInfo.colliderID; + if (id == 0) // terrain collision + { + if (!doneownsound) + { + if (!HaveSound) + { + float vol = Math.Abs(colInfo.relativeVel); + if (vol < 0.2f) + continue; + + vol *= vol * .0625f; // 4m/s == full volume + if (vol > 1.0f) + vol = 1.0f; + + soundID = m_TerrainPart[thisMaterial]; + volume *= vol; + } + part.SendCollisionSound(soundID, volume, colInfo.position); + doneownsound = true; + } + continue; + } + + SceneObjectPart otherPart = sog.Scene.GetSceneObjectPart(id); + if (otherPart != null) + { + SceneObjectGroup othersog = otherPart.ParentGroup; + if(othersog == null || othersog.IsDeleted || othersog.inTransit) + continue; + + int otherType = otherPart.CollisionSoundType; + if (otherType < 0 || otherPart.VolumeDetectActive) + continue; + + if (!HaveSound) + { + if(othersog.CollisionSoundThrottled(otherType)) + continue; + + if (otherType == 1) + { + soundID = otherPart.CollisionSound; + volume = otherPart.CollisionSoundVolume; + if (volume == 0.0f) + continue; + } + else + { + if (otherType == 2) + { + volume = otherPart.CollisionSoundVolume; + if (volume == 0.0f) + continue; + } + + float vol = Math.Abs(colInfo.relativeVel); + if (vol < 0.2f) + continue; + + vol *= vol * .0625f; // 4m/s == full volume + if (vol > 1.0f) + vol = 1.0f; + + int otherMaterial = (int)otherPart.Material; + if (otherMaterial >= MaxMaterials) + otherMaterial = 3; + + soundID = m_PartPart[thisMatScaled + otherMaterial]; + volume *= vol; + } + } + + if (doneownsound) + otherPart.SendCollisionSound(soundID, volume, colInfo.position); + else + { + part.SendCollisionSound(soundID, volume, colInfo.position); + doneownsound = true; + } + } + } + } + + public static void AvatarCollisionSound(ScenePresence av, List collidersinfolist) + { + if (collidersinfolist.Count == 0 || av == null) + return; + + UUID soundID; + int otherMaterial; + + int thisMaterial = 4; // flesh + + int thisMatScaled = thisMaterial * MaxMaterials; + + // bool doneownsound = false; + + CollisionForSoundInfo colInfo; + uint id; + float volume; + + for(int i = 0; i< collidersinfolist.Count; i++) + { + colInfo = collidersinfolist[i]; + + id = colInfo.colliderID; + + if (id == 0) // no terrain collision sounds for now + { + continue; +// volume = Math.Abs(colInfo.relativeVel); +// if (volume < 0.2f) +// continue; + + } + + SceneObjectPart otherPart = av.Scene.GetSceneObjectPart(id); + if (otherPart != null) + { + if (otherPart.CollisionSoundType < 0) + continue; + if (otherPart.CollisionSoundType == 1 && otherPart.CollisionSoundVolume > 0f) + otherPart.SendCollisionSound(otherPart.CollisionSound, otherPart.CollisionSoundVolume, colInfo.position); + else + { + float volmod = 1.0f; + if (otherPart.CollisionSoundType == 2) + { + volmod = otherPart.CollisionSoundVolume; + if(volmod == 0.0) + continue; + } + volume = Math.Abs(colInfo.relativeVel); + // Most noral collisions (running into walls, stairs) + // should never be heard. + if (volume < 3.2f) + continue; +// m_log.DebugFormat("Collision speed was {0}", volume); + + // Cap to 0.2 times volume because climbing stairs should not be noisy + // Also changed scaling + volume *= volume * .0125f; // 4m/s == volume 0.2 + if (volume > 0.2f) + volume = 0.2f; + otherMaterial = (int)otherPart.Material; + if (otherMaterial >= MaxMaterials) + otherMaterial = 3; + + volume *= volmod; + soundID = m_PartPart[thisMatScaled + otherMaterial]; + otherPart.SendCollisionSound(soundID, volume, colInfo.position); + } + continue; + } +/* + else if (!doneownsound) + { + ScenePresence otherav = av.Scene.GetScenePresence(Id); + if (otherav != null && (!otherav.IsChildAgent)) + { + soundID = snd_FleshFlesh; + av.SendCollisionSound(soundID, 1.0); + doneownsound = true; + } + } + */ + } + } + } +} diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs index 7181313..4654efe 100644 --- a/OpenSim/Region/Framework/Scenes/EntityManager.cs +++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs @@ -38,8 +38,8 @@ namespace OpenSim.Region.Framework.Scenes public class EntityManager { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private readonly DoubleDictionaryThreadAbortSafe m_entities + + private readonly DoubleDictionaryThreadAbortSafe m_entities = new DoubleDictionaryThreadAbortSafe(); public int Count diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 97b9482..f76f882 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -44,7 +44,7 @@ namespace OpenSim.Region.Framework.Scenes public class EventManager { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public delegate void OnFrameDelegate(); /// @@ -80,6 +80,7 @@ namespace OpenSim.Region.Framework.Scenes public event OnTerrainTaintedDelegate OnTerrainTainted; public delegate void OnTerrainTickDelegate(); + public delegate void OnTerrainCheckUpdatesDelegate(); /// /// Triggered if the terrain has been edited @@ -89,6 +90,11 @@ namespace OpenSim.Region.Framework.Scenes /// but is used by core solely to update the physics engine. /// public event OnTerrainTickDelegate OnTerrainTick; + public event OnTerrainCheckUpdatesDelegate OnTerrainCheckUpdates; + + public delegate void OnTerrainUpdateDelegate(); + + public event OnTerrainUpdateDelegate OnTerrainUpdate; public delegate void OnBackupDelegate(ISimulationDataService datastore, bool forceBackup); @@ -115,7 +121,7 @@ namespace OpenSim.Region.Framework.Scenes public event OnClientConnectCoreDelegate OnClientConnect; public delegate void OnNewClientDelegate(IClientAPI client); - + /// /// Triggered when a new client is added to the scene. /// @@ -157,7 +163,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Triggered in which is used by both /// users and NPCs - /// + /// /// Triggered under per-agent lock. So if you want to perform any long-running operations, please /// do this on a separate thread. /// @@ -217,7 +223,7 @@ namespace OpenSim.Region.Framework.Scenes /// Triggered when the entire simulator is shutdown. /// public event Action OnShutdown; - + public delegate void ObjectDeGrabDelegate(uint localID, uint originalID, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); public delegate void ScriptResetDelegate(uint localID, UUID itemID); @@ -270,7 +276,7 @@ namespace OpenSim.Region.Framework.Scenes /// public event ObjectGrabDelegate OnObjectGrab; public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); - + /// /// Triggered when an object is being touched/grabbed continuously. /// @@ -339,8 +345,6 @@ namespace OpenSim.Region.Framework.Scenes /// in /// via , /// via - /// XXX: This is only triggered when it is the client that starts the script, not in other situations where - /// a script is started, unlike OnStopScript! /// public event StartScript OnStartScript; @@ -354,7 +358,6 @@ namespace OpenSim.Region.Framework.Scenes /// in , /// , /// - /// XXX: This is triggered when a sciprt is stopped for any reason, unlike OnStartScript! /// public event StopScript OnStopScript; @@ -500,7 +503,7 @@ namespace OpenSim.Region.Framework.Scenes /// via /// public event UpdateScript OnUpdateScript; - + public virtual void TriggerUpdateScript(UUID clientId, UUID itemId, UUID primId, bool isScriptRunning, UUID newAssetID) { UpdateScript handlerUpdateScript = OnUpdateScript; @@ -520,16 +523,16 @@ 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 + /// 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 + /// 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 , @@ -558,7 +561,7 @@ namespace OpenSim.Region.Framework.Scenes /// TODO: Should be triggered when a physics object starts moving. /// public event ScriptMovingStartEvent OnScriptMovingStartEvent; - + public delegate void ScriptMovingEndEvent(uint localID); /// @@ -735,7 +738,7 @@ namespace OpenSim.Region.Framework.Scenes /// and /// public event Action OnMakeRootAgent; - + public event OnSendNewWindlightProfileTargetedDelegate OnSendNewWindlightProfileTargeted; public event OnSaveNewWindlightProfileDelegate OnSaveNewWindlightProfile; @@ -745,14 +748,14 @@ namespace OpenSim.Region.Framework.Scenes public event OnIncomingSceneObjectDelegate OnIncomingSceneObject; public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so); - public delegate void NewInventoryItemUploadComplete(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel); + public delegate void NewInventoryItemUploadComplete(InventoryItemBase item, int userlevel); public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete; public delegate void RequestChangeWaterHeight(float height); public event RequestChangeWaterHeight OnRequestChangeWaterHeight; - + /// /// Fired if any avatar is 'killed' due to its health falling to zero /// @@ -775,7 +778,7 @@ namespace OpenSim.Region.Framework.Scenes public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID); public event EstateToolsSunUpdate OnEstateToolsSunUpdate; - + /// /// Triggered when an object is added to the scene. /// @@ -786,7 +789,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// public event Action OnObjectAddedToScene; - + /// /// When a client sends a derez request for an object inworld /// but before the object is deleted @@ -852,12 +855,16 @@ namespace OpenSim.Region.Framework.Scenes /// , /// , /// , - /// , + /// , /// /// public event ParcelPrimCountTainted OnParcelPrimCountTainted; public event GetScriptRunning OnGetScriptRunning; + public delegate void ThrottleUpdate(ScenePresence scenePresence); + + public event ThrottleUpdate OnThrottleUpdate; + /// /// RegisterCapsEvent is called by Scene after the Caps object /// has been instantiated and before it is return to the @@ -865,21 +872,21 @@ namespace OpenSim.Region.Framework.Scenes /// public delegate void RegisterCapsEvent(UUID agentID, Caps caps); public event RegisterCapsEvent OnRegisterCaps; - + /// /// DeregisterCapsEvent is called by Scene when the caps /// handler for an agent are removed. /// public delegate void DeregisterCapsEvent(UUID agentID, Caps caps); public event DeregisterCapsEvent OnDeregisterCaps; - + /// /// ChatFromWorldEvent is called via Scene when a chat message /// from world comes in. /// public delegate void ChatFromWorldEvent(Object sender, OSChatMessage chat); public event ChatFromWorldEvent OnChatFromWorld; - + /// /// ChatFromClientEvent is triggered via ChatModule (or /// substitutes thereof) when a chat message @@ -887,18 +894,18 @@ namespace OpenSim.Region.Framework.Scenes /// public delegate void ChatFromClientEvent(Object sender, OSChatMessage chat); public event ChatFromClientEvent OnChatFromClient; - + /// /// ChatToClientsEvent is triggered via ChatModule (or - /// substitutes thereof) when a chat message is actually sent to clients. Clients will only be sent a + /// substitutes thereof) when a chat message is actually sent to clients. Clients will only be sent a /// received chat message if they satisfy various conditions (within audible range, etc.) /// public delegate void ChatToClientsEvent( - UUID senderID, HashSet receiverIDs, - string message, ChatTypeEnum type, Vector3 fromPos, string fromName, + UUID senderID, HashSet receiverIDs, + string message, ChatTypeEnum type, Vector3 fromPos, string fromName, ChatSourceType src, ChatAudibleLevel level); public event ChatToClientsEvent OnChatToClients; - + /// /// ChatBroadcastEvent is called via Scene when a broadcast chat message /// from world comes in @@ -916,11 +923,11 @@ namespace OpenSim.Region.Framework.Scenes /// public delegate void OarFileLoaded(Guid guid, List loadedScenes, string message); public event OarFileLoaded OnOarFileLoaded; - + /// /// Called when an oar file has finished saving /// Message is non empty string if there were problems saving the oar file - /// If a guid was supplied on the original call to identify, the request, this is returned. Otherwise + /// If a guid was supplied on the original call to identify, the request, this is returned. Otherwise /// Guid.Empty is returned. /// public delegate void OarFileSaved(Guid guid, string message); @@ -940,14 +947,14 @@ namespace OpenSim.Region.Framework.Scenes /// the avatarID is UUID.Zero (I know, this doesn't make much sense but now it's historical). public delegate void Attach(uint localID, UUID itemID, UUID avatarID); public event Attach OnAttach; - - + + /// /// Called immediately after an object is loaded from storage. /// public event SceneObjectDelegate OnSceneObjectLoaded; public delegate void SceneObjectDelegate(SceneObjectGroup so); - + /// /// Called immediately before an object is saved to storage. /// @@ -960,7 +967,7 @@ namespace OpenSim.Region.Framework.Scenes /// public event SceneObjectPreSaveDelegate OnSceneObjectPreSave; public delegate void SceneObjectPreSaveDelegate(SceneObjectGroup persistingSo, SceneObjectGroup originalSo); - + /// /// Called when a scene object part is cloned within the region. /// @@ -994,7 +1001,7 @@ namespace OpenSim.Region.Framework.Scenes /// Fired when logins to a region are enabled or disabled. /// /// - /// + /// /// /// Fired public event RegionLoginsStatusChange OnRegionLoginsStatusChange; @@ -1150,7 +1157,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnAttach failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnAttach failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1171,7 +1178,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerGetScriptRunning failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerGetScriptRunning failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1192,7 +1199,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnScriptChangedEvent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnScriptChangedEvent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1213,7 +1220,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnClientMovement failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnClientMovement failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1234,7 +1241,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerPermissionError failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerPermissionError failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1255,7 +1262,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnPluginConsole failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnPluginConsole failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1276,7 +1283,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnFrame failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnFrame failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1297,7 +1304,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnNewClient failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnNewClient failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1317,7 +1324,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnNewClient (IClientCore) failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnNewClient (IClientCore) failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1361,7 +1368,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnNewPresence failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnNewPresence failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1377,12 +1384,14 @@ namespace OpenSim.Region.Framework.Scenes { try { +// m_log.ErrorFormat("[EVENT MANAGER]: OnRemovePresenceDelegate: {0}",d.Target.ToString()); d(agentId); +// m_log.ErrorFormat("[EVENT MANAGER]: OnRemovePresenceDelegate done "); } catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnRemovePresence failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnRemovePresence failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1403,7 +1412,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnBackup failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnBackup failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1424,7 +1433,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerParcelPrimCountUpdate failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerParcelPrimCountUpdate failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1445,7 +1454,27 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerMoneyTransfer failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerMoneyTransfer failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + public void TriggerTerrainUpdate() + { + OnTerrainUpdateDelegate handlerTerrainUpdate = OnTerrainUpdate; + if (handlerTerrainUpdate != null) + { + foreach (OnTerrainUpdateDelegate d in handlerTerrainUpdate.GetInvocationList()) + { + try + { + d(); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerTerrainUpdate failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1466,7 +1495,28 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerTerrainTick failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerTerrainTick failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + + public void TriggerTerrainCheckUpdates() + { + OnTerrainCheckUpdatesDelegate TerrainCheckUpdates = OnTerrainCheckUpdates; + if (TerrainCheckUpdates != null) + { + foreach (OnTerrainCheckUpdatesDelegate d in TerrainCheckUpdates.GetInvocationList()) + { + try + { + d(); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TerrainCheckUpdates failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1508,7 +1558,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerParcelPrimCountAdd failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerParcelPrimCountAdd failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1529,7 +1579,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerObjectAddedToScene failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerObjectAddedToScene failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1575,7 +1625,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerObjectBeingRemovedFromScene failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerObjectBeingRemovedFromScene failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1596,7 +1646,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerObjectAddedToPhysicalScene failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1617,7 +1667,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerObjectRemovedFromPhysicalScene failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1638,7 +1688,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerShutdown failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerShutdown failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1659,7 +1709,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerObjectGrab failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerObjectGrab failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1680,7 +1730,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerObjectGrabbing failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerObjectGrabbing failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1701,7 +1751,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerObjectDeGrab failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerObjectDeGrab failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1722,7 +1772,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerScriptReset failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptReset failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1743,7 +1793,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerRezScript failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerRezScript failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1764,7 +1814,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerStartScript failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerStartScript failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1785,7 +1835,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerStopScript failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerStopScript failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1806,8 +1856,9 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerRemoveScript failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerRemoveScript failed - continuing. {0} {1}", e.Message, e.StackTrace); + m_log.ErrorFormat(Environment.StackTrace); } } } @@ -1816,7 +1867,7 @@ namespace OpenSim.Region.Framework.Scenes public bool TriggerGroupMove(UUID groupID, Vector3 delta) { bool result = true; - + SceneGroupMoved handlerSceneGroupMove = OnSceneGroupMove; if (handlerSceneGroupMove != null) { @@ -1830,19 +1881,19 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnAttach failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerGroupMove failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } - + return result; } public bool TriggerGroupSpinStart(UUID groupID) { bool result = true; - + SceneGroupSpinStarted handlerSceneGroupSpinStarted = OnSceneGroupSpinStart; if (handlerSceneGroupSpinStarted != null) { @@ -1856,19 +1907,19 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerGroupSpinStart failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerGroupSpinStart failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } - + return result; } public bool TriggerGroupSpin(UUID groupID, Quaternion rotation) { bool result = true; - + SceneGroupSpun handlerSceneGroupSpin = OnSceneGroupSpin; if (handlerSceneGroupSpin != null) { @@ -1882,12 +1933,12 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerGroupSpin failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerGroupSpin failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } - + return result; } @@ -1905,7 +1956,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerGroupGrab failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerGroupGrab failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1926,7 +1977,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerLandObjectAdded failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerLandObjectAdded failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1947,7 +1998,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerLandObjectRemoved failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerLandObjectRemoved failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1973,7 +2024,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerAvatarEnteringNewParcel failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerAvatarEnteringNewParcel failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -1994,7 +2045,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerAvatarAppearanceChanged failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerAvatarAppearanceChanged failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2036,7 +2087,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerIncomingInstantMessage failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerIncomingInstantMessage failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2057,7 +2108,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnAttach failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnAttach failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2073,12 +2124,15 @@ namespace OpenSim.Region.Framework.Scenes { try { +// m_log.ErrorFormat("[EVENT MANAGER]: TriggerClientClosed: {0}", d.Target.ToString()); d(ClientID, scene); +// m_log.ErrorFormat("[EVENT MANAGER]: TriggerClientClosed done "); + } catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerClientClosed failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerClientClosed failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2099,7 +2153,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnMakeChildAgent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnMakeChildAgent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2138,7 +2192,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnMakeRootAgent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnMakeRootAgent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2159,7 +2213,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnIncomingSceneObject failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnIncomingSceneObject failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2180,7 +2234,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnRegisterCaps failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnRegisterCaps failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2201,14 +2255,14 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnDeregisterCaps failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnDeregisterCaps failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } } - public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, AssetType type, UUID AssetID, String AssetName, int userlevel) + public void TriggerOnNewInventoryItemUploadComplete(InventoryItemBase item, int userlevel) { NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete; if (handlerNewInventoryItemUpdateComplete != null) @@ -2217,12 +2271,12 @@ namespace OpenSim.Region.Framework.Scenes { try { - d(agentID, type, AssetID, AssetName, userlevel); + d(item, userlevel); } catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnNewInventoryItemUploadComplete failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnNewInventoryItemUploadComplete failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2243,7 +2297,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerLandBuy failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerLandBuy failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2264,7 +2318,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerValidateLandBuy failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerValidateLandBuy failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2285,7 +2339,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerAtTargetEvent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerAtTargetEvent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2306,7 +2360,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerNotAtTargetEvent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerNotAtTargetEvent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2327,7 +2381,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerAtRotTargetEvent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerAtRotTargetEvent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2348,7 +2402,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerNotAtRotTargetEvent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerNotAtRotTargetEvent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2417,7 +2471,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerRequestChangeWaterHeight failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerRequestChangeWaterHeight failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2438,7 +2492,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerAvatarKill failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerAvatarKill failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2459,7 +2513,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerSignificantClientMovement failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerSignificantClientMovement failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2480,7 +2534,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnChatFromWorld failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnChatFromWorld failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2501,16 +2555,16 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnChatFromClient failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnChatFromClient failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } } - + public void TriggerOnChatToClients( - UUID senderID, HashSet receiverIDs, - string message, ChatTypeEnum type, Vector3 fromPos, string fromName, + UUID senderID, HashSet receiverIDs, + string message, ChatTypeEnum type, Vector3 fromPos, string fromName, ChatSourceType src, ChatAudibleLevel level) { ChatToClientsEvent handler = OnChatToClients; @@ -2525,7 +2579,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnChatToClients failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnChatToClients failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2546,7 +2600,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnChatBroadcast failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnChatBroadcast failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2567,7 +2621,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerControlEvent failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerControlEvent failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2588,7 +2642,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerNoticeNoLandDataFromStorage failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerNoticeNoLandDataFromStorage failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2609,7 +2663,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerIncomingLandDataFromStorage failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerIncomingLandDataFromStorage failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2630,7 +2684,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerSetAllowForcefulBan failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerSetAllowForcefulBan failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2651,7 +2705,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerRequestParcelPrimCountUpdate failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerRequestParcelPrimCountUpdate failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2672,7 +2726,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerParcelPrimCountTainted failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerParcelPrimCountTainted failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2712,7 +2766,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerEstateToolsSunUpdate failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerEstateToolsSunUpdate failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2733,12 +2787,12 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnAttach failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnAttach failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } - + return 6; } @@ -2756,13 +2810,13 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOarFileLoaded failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOarFileLoaded failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } } - + public void TriggerOarFileSaved(Guid requestId, string message) { OarFileSaved handlerOarFileSaved = OnOarFileSaved; @@ -2777,7 +2831,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOarFileSaved failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOarFileSaved failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2798,7 +2852,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerEmptyScriptCompileQueue failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerEmptyScriptCompileQueue failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2819,7 +2873,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerScriptCollidingStart failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptCollidingStart failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2840,7 +2894,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerScriptColliding failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptColliding failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2861,7 +2915,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerScriptCollidingEnd failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptCollidingEnd failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2882,7 +2936,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerScriptLandCollidingStart failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptLandCollidingStart failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2903,7 +2957,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerScriptLandColliding failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptLandColliding failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2924,7 +2978,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerScriptLandCollidingEnd failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptLandCollidingEnd failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2945,7 +2999,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerSetRootAgentScene failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerSetRootAgentScene failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2966,13 +3020,13 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnRegionUp failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnRegionUp failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } } - + public void TriggerOnSceneObjectLoaded(SceneObjectGroup so) { SceneObjectDelegate handler = OnSceneObjectLoaded; @@ -2987,13 +3041,13 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectLoaded failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectLoaded failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } } - + public void TriggerOnSceneObjectPreSave(SceneObjectGroup persistingSo, SceneObjectGroup originalSo) { SceneObjectPreSaveDelegate handler = OnSceneObjectPreSave; @@ -3008,13 +3062,13 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectPreSave failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectPreSave failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } - } - + } + public void TriggerOnSceneObjectPartCopy(SceneObjectPart copy, SceneObjectPart original, bool userExposed) { SceneObjectPartCopyDelegate handler = OnSceneObjectPartCopy; @@ -3029,7 +3083,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectPartCopy failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectPartCopy failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -3050,7 +3104,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerSceneObjectPartUpdated failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerSceneObjectPartUpdated failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -3093,7 +3147,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectPartCopy failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectPartCopy failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -3107,6 +3161,7 @@ namespace OpenSim.Region.Framework.Scenes { foreach (Action d in handler.GetInvocationList()) { + m_log.InfoFormat("[EVENT MANAGER]: TriggerSceneShuttingDown invoke {0}", d.Method.Name.ToString()); try { d(s); @@ -3114,11 +3169,12 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerSceneShuttingDown failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerSceneShuttingDown failed - continuing. {0} {1}", e.Message, e.StackTrace); } } } + m_log.Info("[EVENT MANAGER]: TriggerSceneShuttingDown done"); } public void TriggerOnRegionStarted(Scene scene) @@ -3310,6 +3366,15 @@ namespace OpenSim.Region.Framework.Scenes } } + public void TriggerThrottleUpdate(ScenePresence scenePresence) + { + ThrottleUpdate handler = OnThrottleUpdate; + if (handler != null) + { + handler(scenePresence); + } + } + // public void TriggerGatherUuids(SceneObjectPart sop, IDictionary assetUuids) // { // GatherUuids handler = OnGatherUuids; diff --git a/OpenSim/Region/Framework/Scenes/GodController.cs b/OpenSim/Region/Framework/Scenes/GodController.cs new file mode 100644 index 0000000..9372366 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/GodController.cs @@ -0,0 +1,287 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Xml; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Timers; +using Timer = System.Timers.Timer; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using log4net; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes.Types; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Region.Framework.Scenes +{ + public class GodController + { + public enum ImplicitGodLevels : int + { + EstateManager = 210, // estate manager implicit god level + RegionOwner = 220 // region owner implicit god level should be >= than estate + } + + ScenePresence m_scenePresence; + Scene m_scene; + protected bool m_allowGridGods; + protected bool m_forceGridGodsOnly; + protected bool m_regionOwnerIsGod; + protected bool m_regionManagerIsGod; + protected bool m_forceGodModeAlwaysOn; + protected bool m_allowGodActionsWithoutGodMode; + + protected int m_userLevel = 0; + // the god level from local or grid user rights + protected int m_rightsGodLevel = 0; + // the level seen by viewers + protected int m_viewergodlevel = 0; + // new level that can be fixed or equal to godlevel, acording to options + protected int m_godlevel = 0; + protected int m_lastLevelToViewer = 0; + + public GodController(Scene scene, ScenePresence sp, int userlevel) + { + m_scene = scene; + m_scenePresence = sp; + m_userLevel = userlevel; + + IConfigSource config = scene.Config; + + string[] sections = new string[] { "Startup", "Permissions" }; + + // God level is based on UserLevel. Gods will have that + // level grid-wide. Others may become god locally but grid + // gods are god everywhere. + m_allowGridGods = + Util.GetConfigVarFromSections(config, + "allow_grid_gods", sections, false); + + // If grid gods are active, dont allow any other gods + m_forceGridGodsOnly = + Util.GetConfigVarFromSections(config, + "force_grid_gods_only", sections, false); + + if(!m_forceGridGodsOnly) + { + // The owner of a region is a god in his region only. + m_regionOwnerIsGod = + Util.GetConfigVarFromSections(config, + "region_owner_is_god", sections, true); + + // Region managers are gods in the regions they manage. + m_regionManagerIsGod = + Util.GetConfigVarFromSections(config, + "region_manager_is_god", sections, false); + + } + else + m_allowGridGods = true; // reduce potencial user mistakes + + // God mode should be turned on in the viewer whenever + // the user has god rights somewhere. They may choose + // to turn it off again, though. + m_forceGodModeAlwaysOn = + Util.GetConfigVarFromSections(config, + "automatic_gods", sections, false); + + // The user can execute any and all god functions, as + // permitted by the viewer UI, without actually "godding + // up". This is the default state in 0.8.2. + m_allowGodActionsWithoutGodMode = + Util.GetConfigVarFromSections(config, + "implicit_gods", sections, false); + + m_rightsGodLevel = CalcRightsGodLevel(); + + if(m_allowGodActionsWithoutGodMode) + { + m_godlevel = m_rightsGodLevel; + m_forceGodModeAlwaysOn = false; + } + + else if(m_forceGodModeAlwaysOn) + { + m_viewergodlevel = m_rightsGodLevel; + m_godlevel = m_rightsGodLevel; + } + + m_scenePresence.IsGod = (m_godlevel >= 200); + m_scenePresence.IsViewerUIGod = (m_viewergodlevel >= 200); + } + + // calculates god level at sp creation from local and grid user god rights + // for now this is assumed static until user leaves region. + // later estate and gride level updates may update this + protected int CalcRightsGodLevel() + { + int level = 0; + if (m_allowGridGods && m_userLevel >= 200) + level = m_userLevel; + + if(m_forceGridGodsOnly || level >= (int)ImplicitGodLevels.RegionOwner) + return level; + + if (m_regionOwnerIsGod && m_scene.RegionInfo.EstateSettings.IsEstateOwner(m_scenePresence.UUID)) + level = (int)ImplicitGodLevels.RegionOwner; + + if(level >= (int)ImplicitGodLevels.EstateManager) + return level; + + if (m_regionManagerIsGod && m_scene.Permissions.IsEstateManager(m_scenePresence.UUID)) + level = (int)ImplicitGodLevels.EstateManager; + + return level; + } + + protected bool CanBeGod() + { + return m_rightsGodLevel >= 200; + } + + protected void UpdateGodLevels(bool viewerState) + { + if(!CanBeGod()) + { + m_viewergodlevel = 0; + m_godlevel = 0; + m_scenePresence.IsGod = false; + m_scenePresence.IsViewerUIGod = false; + return; + } + + // legacy some are controled by viewer, others are static + if(m_allowGodActionsWithoutGodMode) + { + if(viewerState) + m_viewergodlevel = m_rightsGodLevel; + else + m_viewergodlevel = 0; + + m_godlevel = m_rightsGodLevel; + } + else + { + // new all change with viewer + if(viewerState) + { + m_viewergodlevel = m_rightsGodLevel; + m_godlevel = m_rightsGodLevel; + } + else + { + m_viewergodlevel = 0; + m_godlevel = 0; + } + } + m_scenePresence.IsGod = (m_godlevel >= 200); + m_scenePresence.IsViewerUIGod = (m_viewergodlevel >= 200); + } + + public void SyncViewerState() + { + if(m_lastLevelToViewer == m_viewergodlevel) + return; + + m_lastLevelToViewer = m_viewergodlevel; + + if(m_scenePresence.IsChildAgent) + return; + + m_scenePresence.ControllingClient.SendAdminResponse(UUID.Zero, (uint)m_viewergodlevel); + } + + public void RequestGodMode(bool god) + { + UpdateGodLevels(god); + + if(m_lastLevelToViewer != m_viewergodlevel) + { + m_scenePresence.ControllingClient.SendAdminResponse(UUID.Zero, (uint)m_viewergodlevel); + m_lastLevelToViewer = m_viewergodlevel; + } + } + + public OSD State() + { + OSDMap godMap = new OSDMap(2); + bool m_viewerUiIsGod = m_viewergodlevel >= 200; + godMap.Add("ViewerUiIsGod", OSD.FromBoolean(m_viewerUiIsGod)); + + return godMap; + } + + public void SetState(OSD state) + { + bool newstate = false; + if(m_forceGodModeAlwaysOn) + newstate = m_viewergodlevel >= 200; + if(state != null) + { + OSDMap s = (OSDMap)state; + + if (s.ContainsKey("ViewerUiIsGod")) + newstate = s["ViewerUiIsGod"].AsBoolean(); + m_lastLevelToViewer = m_viewergodlevel; // we are not changing viewer level by default + } + UpdateGodLevels(newstate); + } + + public void HasMovedAway() + { + m_lastLevelToViewer = 0; + if(m_forceGodModeAlwaysOn) + { + m_viewergodlevel = m_rightsGodLevel; + m_godlevel = m_rightsGodLevel; + } + } + + public int UserLevel + { + get { return m_userLevel; } + set { m_userLevel = value; } + } + + public int ViwerUIGodLevel + { + get { return m_viewergodlevel; } + } + + public int GodLevel + { + get { return m_godlevel; } + } + } +} diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index bbf3b51..80ee510 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -140,7 +140,7 @@ namespace OpenSim.Region.Framework.Scenes timer.Start(); }; } - + // Check again, in case the regions were started while we were adding the event handler if (SceneManager.Instance.AllRegionsReady) { @@ -292,14 +292,18 @@ namespace OpenSim.Region.Framework.Scenes private void StartTimer() { - KeyframeTimer.Add(this); - m_timerStopped = false; + lock (m_frames) + { + KeyframeTimer.Add(this); + m_lasttickMS = Util.GetTimeStampMS(); + m_timerStopped = false; + } } private void StopTimer() { - m_timerStopped = true; - KeyframeTimer.Remove(this); + lock (m_frames) + m_timerStopped = true; } public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) @@ -323,8 +327,8 @@ namespace OpenSim.Region.Framework.Scenes newMotion.m_selected = true; } - newMotion.m_timerStopped = false; - newMotion.m_running = true; +// newMotion.m_timerStopped = false; +// newMotion.m_running = true; newMotion.m_isCrossing = false; newMotion.m_waitingCrossing = false; } @@ -348,24 +352,26 @@ namespace OpenSim.Region.Framework.Scenes m_group = grp; m_scene = grp.Scene; - Vector3 grppos = grp.AbsolutePosition; - Vector3 offset = grppos - m_serializedPosition; - // avoid doing it more than once - // current this will happen dragging a prim to other region - m_serializedPosition = grppos; - m_basePosition += offset; - m_nextPosition += offset; - - m_currentFrame.StartPosition += offset; - m_currentFrame.Position += offset; - - for (int i = 0; i < m_frames.Count; i++) + lock (m_frames) { - Keyframe k = m_frames[i]; - k.StartPosition += offset; - k.Position += offset; - m_frames[i]=k; + Vector3 grppos = grp.AbsolutePosition; + Vector3 offset = grppos - m_serializedPosition; + // avoid doing it more than once + // current this will happen draging a prim to other region + m_serializedPosition = grppos; + + m_basePosition += offset; + m_currentFrame.Position += offset; + + m_nextPosition += offset; + + for (int i = 0; i < m_frames.Count; i++) + { + Keyframe k = m_frames[i]; + k.Position += offset; + m_frames[i] = k; + } } if (m_running) @@ -410,25 +416,28 @@ namespace OpenSim.Region.Framework.Scenes m_keyframes.CopyTo(newmotion.m_keyframes, 0); } - newmotion.m_frames = new List(m_frames); + lock (m_frames) + { + newmotion.m_frames = new List(m_frames); - newmotion.m_basePosition = m_basePosition; - newmotion.m_baseRotation = m_baseRotation; + newmotion.m_basePosition = m_basePosition; + newmotion.m_baseRotation = m_baseRotation; - if (m_selected) - newmotion.m_serializedPosition = m_serializedPosition; - else - { - if (m_group != null) - newmotion.m_serializedPosition = m_group.AbsolutePosition; - else + if (m_selected) newmotion.m_serializedPosition = m_serializedPosition; - } + else + { + if (m_group != null) + newmotion.m_serializedPosition = m_group.AbsolutePosition; + else + newmotion.m_serializedPosition = m_serializedPosition; + } - newmotion.m_currentFrame = m_currentFrame; + newmotion.m_currentFrame = m_currentFrame; - newmotion.m_iterations = m_iterations; - newmotion.m_running = m_running; + newmotion.m_iterations = m_iterations; + newmotion.m_running = m_running; + } if (m_running && !m_waitingCrossing) StartTimer(); @@ -458,39 +467,62 @@ namespace OpenSim.Region.Framework.Scenes } else { - m_running = false; StopTimer(); + m_running = false; } } public void Stop() { + StopTimer(); m_running = false; m_isCrossing = false; m_waitingCrossing = false; - StopTimer(); - m_basePosition = m_group.AbsolutePosition; m_baseRotation = m_group.GroupRotation; m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.AngularVelocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); -// m_group.RootPart.ScheduleTerseUpdate(); +// m_group.SendGroupRootTerseUpdate(); + m_group.RootPart.ScheduleTerseUpdate(); m_frames.Clear(); + m_group.Scene.EventManager.TriggerMovingEndEvent(m_group.RootPart.LocalId); } public void Pause() { - m_running = false; StopTimer(); + m_running = false; m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.AngularVelocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); -// m_group.RootPart.ScheduleTerseUpdate(); + m_skippedUpdates = 1000; +// m_group.SendGroupRootTerseUpdate(); + m_group.RootPart.ScheduleTerseUpdate(); + m_group.Scene.EventManager.TriggerMovingEndEvent(m_group.RootPart.LocalId); + } + + public void Suspend() + { + lock (m_frames) + { + if (m_timerStopped) + return; + m_timerStopped = true; + } + } + public void Resume() + { + lock (m_frames) + { + if (!m_timerStopped) + return; + if (m_running && !m_waitingCrossing) + StartTimer(); + m_skippedUpdates = 1000; + } } private void GetNextList() @@ -581,6 +613,7 @@ namespace OpenSim.Region.Framework.Scenes pos = (Vector3)k.Position; rot = (Quaternion)k.Rotation; + } m_basePosition = pos; @@ -592,15 +625,47 @@ namespace OpenSim.Region.Framework.Scenes public void OnTimer(double tickDuration) { + if (!Monitor.TryEnter(m_frames)) + return; + if (m_timerStopped) + KeyframeTimer.Remove(this); + else + DoOnTimer(tickDuration); + Monitor.Exit(m_frames); + } + + private void Done() + { + KeyframeTimer.Remove(this); + m_timerStopped = true; + m_running = false; + m_isCrossing = false; + m_waitingCrossing = false; + + m_basePosition = m_group.AbsolutePosition; + m_baseRotation = m_group.GroupRotation; + + m_group.RootPart.Velocity = Vector3.Zero; + m_group.RootPart.AngularVelocity = Vector3.Zero; +// m_group.SendGroupRootTerseUpdate(); + m_group.RootPart.ScheduleTerseUpdate(); + m_frames.Clear(); + } + + [NonSerialized()] Vector3 m_lastPosUpdate; + [NonSerialized()] Quaternion m_lastRotationUpdate; + [NonSerialized()] Vector3 m_currentVel; + [NonSerialized()] int m_skippedUpdates; + [NonSerialized()] double m_lasttickMS; + + private void DoOnTimer(double tickDuration) + { if (m_skipLoops > 0) { m_skipLoops--; return; } - if (m_timerStopped) // trap events still in air even after a timer.stop - return; - if (m_group == null) return; @@ -611,8 +676,9 @@ namespace OpenSim.Region.Framework.Scenes if (m_group.RootPart.Velocity != Vector3.Zero) { m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); - + m_skippedUpdates = 1000; +// m_group.SendGroupRootTerseUpdate(); + m_group.RootPart.ScheduleTerseUpdate(); } return; } @@ -624,7 +690,9 @@ namespace OpenSim.Region.Framework.Scenes // retry to set the position that evtually caused the outbound // if still outside region this will call startCrossing below m_isCrossing = false; + m_skippedUpdates = 1000; m_group.AbsolutePosition = m_nextPosition; + if (!m_isCrossing) { StopTimer(); @@ -633,43 +701,43 @@ namespace OpenSim.Region.Framework.Scenes return; } + double nowMS = Util.GetTimeStampMS(); + if (m_frames.Count == 0) { - if (!m_running) return; + lock (m_frames) + { + GetNextList(); - GetNextList(); + if (m_frames.Count == 0) + { + Done(); + m_group.Scene.EventManager.TriggerMovingEndEvent(m_group.RootPart.LocalId); + return; + } - if (m_frames.Count == 0) - { - Stop(); -// Scene scene = m_group.Scene; -// -// IScriptModule[] scriptModules = scene.RequestModuleInterfaces(); -// foreach (IScriptModule m in scriptModules) -// { -// if (m == null) -// continue; -// m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]); -// } - - m_group.Scene.EventManager.TriggerMovingEndEvent(m_group.RootPart.LocalId); - - return; + m_currentFrame = m_frames[0]; } + m_nextPosition = m_group.AbsolutePosition; + m_currentVel = (Vector3)m_currentFrame.Position - m_nextPosition; + m_currentVel /= (m_currentFrame.TimeMS * 0.001f); - m_currentFrame = m_frames[0]; m_currentFrame.TimeMS += (int)tickDuration; - - //force a update on a keyframe transition + m_lasttickMS = nowMS - 50f; update = true; } - m_currentFrame.TimeMS -= (int)tickDuration; + int elapsed = (int)(nowMS - m_lasttickMS); + if( elapsed > 3 * tickDuration) + elapsed = (int)tickDuration; + + m_currentFrame.TimeMS -= elapsed; + m_lasttickMS = nowMS; // Do the frame processing double remainingSteps = (double)m_currentFrame.TimeMS / tickDuration; - if (remainingSteps <= 0.0) + if (remainingSteps <= 1.0) { m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.AngularVelocity = Vector3.Zero; @@ -677,111 +745,99 @@ namespace OpenSim.Region.Framework.Scenes m_nextPosition = (Vector3)m_currentFrame.Position; m_group.AbsolutePosition = m_nextPosition; - // we are sending imediate updates, no doing force a extra terseUpdate - // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); - m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; - m_frames.RemoveAt(0); - if (m_frames.Count > 0) - m_currentFrame = m_frames[0]; + lock (m_frames) + { + m_frames.RemoveAt(0); + if (m_frames.Count > 0) + { + m_currentFrame = m_frames[0]; + m_currentVel = (Vector3)m_currentFrame.Position - m_nextPosition; + m_currentVel /= (m_currentFrame.TimeMS * 0.001f); + m_group.RootPart.Velocity = m_currentVel; + m_currentFrame.TimeMS += (int)tickDuration; + } + else + m_group.RootPart.Velocity = Vector3.Zero; + } update = true; } else { - float completed = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; - bool lastStep = m_currentFrame.TimeMS <= tickDuration; - - Vector3 positionThisStep = m_currentFrame.StartPosition + (m_currentFrame.Position.Value - m_currentFrame.StartPosition) * completed; - Vector3 motionThisStep = positionThisStep - m_group.AbsolutePosition; - - float mag = Vector3.Mag(motionThisStep); - - if ((mag >= 0.02f) || lastStep) +// bool lastSteps = remainingSteps < 4; + + Vector3 currentPosition = m_group.AbsolutePosition; + Vector3 motionThisFrame = (Vector3)m_currentFrame.Position - currentPosition; + motionThisFrame /= (float)remainingSteps; + + m_nextPosition = currentPosition + motionThisFrame; + + Quaternion currentRotation = m_group.GroupRotation; + if ((Quaternion)m_currentFrame.Rotation != currentRotation) { - m_nextPosition = m_group.AbsolutePosition + motionThisStep; - m_group.AbsolutePosition = m_nextPosition; - update = true; - } - - //int totalSteps = m_currentFrame.TimeTotal / (int)tickDuration; - //m_log.DebugFormat("KeyframeMotion.OnTimer: step {0}/{1}, curPosition={2}, finalPosition={3}, motionThisStep={4} (scene {5})", - // totalSteps - remainingSteps + 1, totalSteps, m_group.AbsolutePosition, m_currentFrame.Position, motionThisStep, m_scene.RegionInfo.RegionName); - - if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) - { - Quaternion current = m_group.GroupRotation; - + float completed = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, completed); step.Normalize(); -/* use simpler change detection -* float angle = 0; - - float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; - float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; - float aa_bb = aa * bb; - - if (aa_bb == 0) - { - angle = 0; - } - else - { - float ab = current.X * step.X + - current.Y * step.Y + - current.Z * step.Z + - current.W * step.W; - float q = (ab * ab) / aa_bb; - - if (q > 1.0f) - { - angle = 0; - } - else - { - angle = (float)Math.Acos(2 * q - 1); - } - } - - if (angle > 0.01f) -*/ - if(Math.Abs(step.X - current.X) > 0.001f - || Math.Abs(step.Y - current.Y) > 0.001f - || Math.Abs(step.Z - current.Z) > 0.001f - || lastStep) - // assuming w is a dependente var - - { -// m_group.UpdateGroupRotationR(step); - m_group.RootPart.RotationOffset = step; - - //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); + m_group.RootPart.RotationOffset = step; +/* + if (Math.Abs(step.X - m_lastRotationUpdate.X) > 0.001f + || Math.Abs(step.Y - m_lastRotationUpdate.Y) > 0.001f + || Math.Abs(step.Z - m_lastRotationUpdate.Z) > 0.001f) update = true; - } +*/ } - } - if (update) - { - m_group.SendGroupRootTerseUpdate(); + m_group.AbsolutePosition = m_nextPosition; +// if(lastSteps) +// m_group.RootPart.Velocity = Vector3.Zero; +// else + m_group.RootPart.Velocity = m_currentVel; +/* + if(!update && ( +// lastSteps || + m_skippedUpdates * tickDuration > 0.5 || + Math.Abs(m_nextPosition.X - currentPosition.X) > 5f || + Math.Abs(m_nextPosition.Y - currentPosition.Y) > 5f || + Math.Abs(m_nextPosition.Z - currentPosition.Z) > 5f + )) + { + update = true; + } + else + m_skippedUpdates++; +*/ } +// if(update) +// { +// m_lastPosUpdate = m_nextPosition; +// m_lastRotationUpdate = m_group.GroupRotation; +// m_skippedUpdates = 0; +// m_group.SendGroupRootTerseUpdate(); + m_group.RootPart.ScheduleTerseUpdate(); +// } } public Byte[] Serialize() { + bool timerWasStopped; + lock (m_frames) + { + timerWasStopped = m_timerStopped; + } StopTimer(); SceneObjectGroup tmp = m_group; m_group = null; - if (!m_selected && tmp != null) - m_serializedPosition = tmp.AbsolutePosition; using (MemoryStream ms = new MemoryStream()) { BinaryFormatter fmt = new BinaryFormatter(); + if (!m_selected && tmp != null) + m_serializedPosition = tmp.AbsolutePosition; fmt.Serialize(ms, this); m_group = tmp; - if (m_running && !m_waitingCrossing) + if (!timerWasStopped && m_running && !m_waitingCrossing) StartTimer(); return ms.ToArray(); @@ -791,10 +847,10 @@ namespace OpenSim.Region.Framework.Scenes public void StartCrossingCheck() { // timer will be restart by crossingFailure - // or never since crossing worked and this + // or never since crossing worked and this // should be deleted StopTimer(); - + m_isCrossing = true; m_waitingCrossing = true; @@ -802,8 +858,9 @@ namespace OpenSim.Region.Framework.Scenes if (m_group.RootPart.Velocity != Vector3.Zero) { m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); -// m_group.RootPart.ScheduleTerseUpdate(); + m_skippedUpdates = 1000; +// m_group.SendGroupRootTerseUpdate(); + m_group.RootPart.ScheduleTerseUpdate(); } } @@ -814,8 +871,9 @@ namespace OpenSim.Region.Framework.Scenes if (m_group != null) { m_group.RootPart.Velocity = Vector3.Zero; - m_group.SendGroupRootTerseUpdate(); -// m_group.RootPart.ScheduleTerseUpdate(); + m_skippedUpdates = 1000; +// m_group.SendGroupRootTerseUpdate(); + m_group.RootPart.ScheduleTerseUpdate(); if (m_running) { diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index ae85560..53ca849 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -35,7 +35,7 @@ using OpenSim.Region.PhysicsModules.SharedBase; /* * Steps to add a new prioritization policy: - * + * * - Add a new value to the UpdatePrioritizationSchemes enum. * - Specify this new value in the [InterestManagement] section of your * OpenSim.ini. The name in the config file must match the enum value name @@ -59,7 +59,7 @@ namespace OpenSim.Region.Framework.Scenes public class Prioritizer { private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - + private Scene m_scene; public Prioritizer(Scene scene) @@ -91,9 +91,10 @@ namespace OpenSim.Region.Framework.Scenes return 0; uint priority; - + switch (m_scene.UpdatePrioritizationScheme) { +/* case UpdatePrioritizationSchemes.Time: priority = GetPriorityByTime(client, entity); break; @@ -106,13 +107,16 @@ namespace OpenSim.Region.Framework.Scenes case UpdatePrioritizationSchemes.FrontBack: priority = GetPriorityByFrontBack(client, entity); break; +*/ + case UpdatePrioritizationSchemes.SimpleAngularDistance: + priority = GetPriorityByAngularDistance(client, entity); // TODO: Reimplement SimpleAngularDistance + break; case UpdatePrioritizationSchemes.BestAvatarResponsiveness: + default: priority = GetPriorityByBestAvatarResponsiveness(client, entity); break; - default: - throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); } - + return priority; } @@ -141,7 +145,7 @@ namespace OpenSim.Region.Framework.Scenes return ComputeDistancePriority(client,entity,false); } - + private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) { // And anything attached to this avatar gets top priority as well @@ -157,30 +161,39 @@ namespace OpenSim.Region.Framework.Scenes private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) { - uint pqueue = ComputeDistancePriority(client,entity,true); + uint pqueue = 2; // keep compiler happy ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (presence != null) { - if (!presence.IsChildAgent) + // All avatars other than our own go into pqueue 1 + if (entity is ScenePresence) + return 1; + + if (entity is SceneObjectPart) { - // All avatars other than our own go into pqueue 1 - if (entity is ScenePresence) - return 1; + SceneObjectGroup sog = ((SceneObjectPart)entity).ParentGroup; + // Attachments are high priority, + if (sog.IsAttachment) + return 2; - if (entity is SceneObjectPart) + + if(presence.ParentPart != null) { - // Attachments are high priority, - if (((SceneObjectPart)entity).ParentGroup.IsAttachment) - return 1; - - // Non physical prims are lower priority than physical prims - PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; - if (physActor == null || !physActor.IsPhysical) - pqueue++; + if(presence.ParentPart.ParentGroup == sog) + return 2; } + + pqueue = ComputeDistancePriority(client, entity, false); + + // Non physical prims are lower priority than physical prims + PhysicsActor physActor = sog.RootPart.PhysActor; + if (physActor == null || !physActor.IsPhysical) + pqueue++; } } + else + pqueue = ComputeDistancePriority(client, entity, false); return pqueue; } @@ -191,7 +204,7 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence presence = m_scene.GetScenePresence(client.AgentId); if (presence == null) { - // this shouldn't happen, it basically means that we are prioritizing + // this shouldn't happen, it basically means that we are prioritizing // updates to send to a client that doesn't have a presence in the scene // seems like there's race condition here... @@ -199,7 +212,7 @@ namespace OpenSim.Region.Framework.Scenes // throw new InvalidOperationException("Prioritization agent not defined"); return PriorityQueue.NumberOfQueues - 1; } - + // Use group position for child prims, since we are putting child prims in // the same queue with the root of the group, the root prim (which goes into // the queue first) should always be sent first, no need to adjust child prim @@ -212,25 +225,43 @@ namespace OpenSim.Region.Framework.Scenes } // Use the camera position for local agents and avatar position for remote agents - Vector3 presencePos = (presence.IsChildAgent) ? - presence.AbsolutePosition : - presence.CameraPosition; + // Why would I want that? They could be camming but I still see them at the + // avatar position, so why should I update them as if they were at their + // camera positions? Makes no sense! + // TODO: Fix this mess + //Vector3 presencePos = (presence.IsChildAgent) ? + // presence.AbsolutePosition : + // presence.CameraPosition; + + Vector3 presencePos = presence.AbsolutePosition; - // Compute the distance... + // Compute the distance... double distance = Vector3.Distance(presencePos, entityPos); // And convert the distance to a priority queue, this computation gives queues // at 10, 20, 40, 80, 160, 320, 640, and 1280m - uint pqueue = PriorityQueue.NumberOfImmediateQueues; + uint pqueue = PriorityQueue.NumberOfImmediateQueues + 1; // reserve attachments queue uint queues = PriorityQueue.NumberOfQueues - PriorityQueue.NumberOfImmediateQueues; - +/* for (int i = 0; i < queues - 1; i++) { - if (distance < 10 * Math.Pow(2.0,i)) + if (distance < 30 * Math.Pow(2.0,i)) break; pqueue++; } - +*/ + if (distance > 10f) + { + float tmp = (float)Math.Log((double)distance) * 1.442695f - 3.321928f; + // for a map identical to original: + // now + // 1st constant is 1/(log(2)) (natural log) so we get log2(distance) + // 2st constant makes it be log2(distance/10) + pqueue += (uint)tmp; + if (pqueue > queues - 1) + pqueue = queues - 1; + } + // If this is a root agent, then determine front & back // Bump up the priority queue (drop the priority) for any objects behind the avatar if (useFrontBack && ! presence.IsChildAgent) @@ -242,12 +273,81 @@ namespace OpenSim.Region.Framework.Scenes // Plane equation float d = -Vector3.Dot(camPosition, camAtAxis); float p = Vector3.Dot(camAtAxis, entityPos) + d; - if (p < 0.0f) + if (p < 0.0f) pqueue++; } return pqueue; } + private uint GetPriorityByAngularDistance(IClientAPI client, ISceneEntity entity) + { + ScenePresence presence = m_scene.GetScenePresence(client.AgentId); + if (presence == null) + return PriorityQueue.NumberOfQueues - 1; + + uint pqueue = ComputeAngleDistancePriority(presence, entity); + return pqueue; + } + + private uint ComputeAngleDistancePriority(ScenePresence presence, ISceneEntity entity) + { + // And convert the distance to a priority queue, this computation gives queues + // at 10, 20, 40, 80, 160, 320, 640, and 1280m +// uint minpqueue = PriorityQueue.NumberOfImmediateQueues; + uint maxqueue = PriorityQueue.NumberOfQueues - PriorityQueue.NumberOfImmediateQueues -1; +// uint pqueue = minpqueue; + uint pqueue = PriorityQueue.NumberOfImmediateQueues; + float distance; + + Vector3 presencePos = presence.AbsolutePosition; + if(entity is ScenePresence) + { + ScenePresence sp = entity as ScenePresence; + distance = Vector3.Distance(presencePos, sp.AbsolutePosition); + distance *= 0.5f; + } + else + { + SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; + if(presence.ParentPart != null) + { + if(presence.ParentPart.ParentGroup == group) + return pqueue; + } + if(group.IsAttachment) + { + if(group.RootPart.LocalId == presence.LocalId) + return pqueue; + } + + float bradius = group.GetBoundsRadius(); + Vector3 grppos = group.AbsolutePosition + group.getBoundsCenter(); + distance = Vector3.Distance(presencePos, grppos); + distance -= bradius; + distance *= group.getAreaFactor(); + if(group.IsAttachment) + distance *= 0.5f; + else if(group.UsesPhysics) + distance *= 0.6f; + else if(group.GetSittingAvatarsCount() > 0) + distance *= 0.5f; + } + + if (distance > 10f) + { + float tmp = (float)Math.Log(distance) * 1.442695f - 3.321928f; + // for a map identical to original: + // now + // 1st constant is 1/(log(2)) (natural log) so we get log2(distance) + // 2st constant makes it be log2(distance/10) + + pqueue += (uint)tmp; + if (pqueue > maxqueue) + pqueue = maxqueue; + } + + return pqueue; + } } } diff --git a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs index 3b31281..bf58885 100644 --- a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs +++ b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs @@ -55,13 +55,13 @@ namespace OpenSim.Region.Framework.Scenes public string localZone = TimeZone.CurrentTimeZone.StandardName; public TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now); - public RegionStatsHandler(RegionInfo region_info) + public RegionStatsHandler(RegionInfo region_info) : base("GET", "/" + Util.SHA1Hash(region_info.regionSecret), "RegionStats", "Region Statistics") { regionInfo = region_info; osXStatsURI = Util.SHA1Hash(regionInfo.osSecret); } - + protected override byte[] ProcessRequest( string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { @@ -72,7 +72,7 @@ namespace OpenSim.Region.Framework.Scenes { get { return "text/plain"; } } - + private string Report() { OSDMap args = new OSDMap(30); @@ -83,7 +83,7 @@ namespace OpenSim.Region.Framework.Scenes args["UxTime"] = OSD.FromInteger(Util.ToUnixTime(DateTime.Now)); args["Memory"] = OSD.FromReal(Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); args["Version"] = OSD.FromString(VersionInfo.Version); - + string strBuffer = ""; strBuffer = OSDParser.SerializeJsonString(args); diff --git a/OpenSim/Region/Framework/Scenes/SOPMaterial.cs b/OpenSim/Region/Framework/Scenes/SOPMaterial.cs new file mode 100644 index 0000000..d38ef61 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/SOPMaterial.cs @@ -0,0 +1,177 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Region.Framework.Scenes +{ + public static class SOPMaterialData + { + public enum SopMaterial : int // redundante and not in use for now + { + Stone = 0, + Metal = 1, + Glass = 2, + Wood = 3, + Flesh = 4, + Plastic = 5, + Rubber = 6, + light = 7 // compatibility with old viewers + } + + private struct MaterialData + { + public float friction; + public float bounce; + public MaterialData(float f, float b) + { + friction = f; + bounce = b; + } + } + + private static MaterialData[] m_materialdata = { + new MaterialData(0.8f,0.4f), // Stone + new MaterialData(0.3f,0.4f), // Metal + new MaterialData(0.2f,0.7f), // Glass + new MaterialData(0.6f,0.5f), // Wood + new MaterialData(0.9f,0.3f), // Flesh + new MaterialData(0.4f,0.7f), // Plastic + new MaterialData(0.9f,0.95f), // Rubber + new MaterialData(0.0f,0.0f) // light ?? + }; + + public static Material MaxMaterial + { + get { return (Material)(m_materialdata.Length - 1); } + } + + public static float friction(Material material) + { + int indx = (int)material; + if (indx < m_materialdata.Length) + return (m_materialdata[indx].friction); + else + return 0; + } + + public static float bounce(Material material) + { + int indx = (int)material; + if (indx < m_materialdata.Length) + return (m_materialdata[indx].bounce); + else + return 0; + } + } + + public class FaceMaterial + { + public UUID ID; + public UUID NormalMapID = UUID.Zero; + public float NormalOffsetX = 0.0f; + public float NormalOffsetY = 0.0f; + public float NormalRepeatX = 1.0f; + public float NormalRepeatY = 1.0f; + public float NormalRotation = 0.0f; + + public UUID SpecularMapID = UUID.Zero; + public float SpecularOffsetX = 0.0f; + public float SpecularOffsetY = 0.0f; + public float SpecularRepeatX = 1.0f; + public float SpecularRepeatY = 1.0f; + public float SpecularRotation = 0.0f; + + public Color4 SpecularLightColor = new Color4(255,255,255,255); + public Byte SpecularLightExponent = 51; + public Byte EnvironmentIntensity = 0; + public Byte DiffuseAlphaMode = 1; + public Byte AlphaMaskCutoff = 0; + + public FaceMaterial() + { } + + public FaceMaterial(UUID pID, OSDMap mat) + { + ID = pID; + if(mat == null) + return; + float scale = 0.0001f; + NormalMapID = mat["NormMap"].AsUUID(); + NormalOffsetX = scale * (float)mat["NormOffsetX"].AsReal(); + NormalOffsetY = scale * (float)mat["NormOffsetY"].AsReal(); + NormalRepeatX = scale * (float)mat["NormRepeatX"].AsReal(); + NormalRepeatY = scale * (float)mat["NormRepeatY"].AsReal(); + NormalRotation = scale * (float)mat["NormRotation"].AsReal(); + + SpecularMapID = mat["SpecMap"].AsUUID(); + SpecularOffsetX = scale * (float)mat["SpecOffsetX"].AsReal(); + SpecularOffsetY = scale * (float)mat["SpecOffsetY"].AsReal(); + SpecularRepeatX = scale * (float)mat["SpecRepeatX"].AsReal(); + SpecularRepeatY = scale * (float)mat["SpecRepeatY"].AsReal(); + SpecularRotation = scale * (float)mat["SpecRotation"].AsReal(); + + SpecularLightColor = mat["SpecColor"].AsColor4(); + SpecularLightExponent = (Byte)mat["SpecExp"].AsUInteger(); + EnvironmentIntensity = (Byte)mat["EnvIntensity"].AsUInteger(); + DiffuseAlphaMode = (Byte)mat["DiffuseAlphaMode"].AsUInteger(); + AlphaMaskCutoff = (Byte)mat["AlphaMaskCutoff"].AsUInteger(); + } + + public OSDMap toOSD() + { + OSDMap mat = new OSDMap(); + float scale = 10000f; + + mat["NormMap"] = NormalMapID; + mat["NormOffsetX"] = (int) (scale * NormalOffsetX); + mat["NormOffsetY"] = (int) (scale * NormalOffsetY); + mat["NormRepeatX"] = (int) (scale * NormalRepeatX); + mat["NormRepeatY"] = (int) (scale * NormalRepeatY); + mat["NormRotation"] = (int) (scale * NormalRotation); + + mat["SpecMap"] = SpecularMapID; + mat["SpecOffsetX"] = (int) (scale * SpecularOffsetX); + mat["SpecOffsetY"] = (int) (scale * SpecularOffsetY); + mat["SpecRepeatX"] = (int) (scale * SpecularRepeatX); + mat["SpecRepeatY"] = (int) (scale * SpecularRepeatY); + mat["SpecRotation"] = (int) (scale * SpecularRotation); + + mat["SpecColor"] = SpecularLightColor; + mat["SpecExp"] = SpecularLightExponent; + mat["EnvIntensity"] = EnvironmentIntensity; + mat["DiffuseAlphaMode"] = DiffuseAlphaMode; + mat["AlphaMaskCutoff"] = AlphaMaskCutoff; + + return mat; + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SOPVehicle.cs b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs new file mode 100644 index 0000000..6683614 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/SOPVehicle.cs @@ -0,0 +1,803 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.PhysicsModules.SharedBase; +using System.Text; +using System.IO; +using System.Xml; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Region.Framework.Scenes.Serialization; + +namespace OpenSim.Region.Framework.Scenes +{ + public class SOPVehicle + { + public VehicleData vd; + + public Vehicle Type + { + get { return vd.m_type; } + } + + public SOPVehicle() + { + vd = new VehicleData(); + ProcessTypeChange(Vehicle.TYPE_NONE); // is needed? + } + + public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) + { + float len; + float timestep = 0.01f; + switch (pParam) + { + case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: + if (pValue < 0f) pValue = 0f; + if (pValue > 1f) pValue = 1f; + vd.m_angularDeflectionEfficiency = pValue; + break; + case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_angularDeflectionTimescale = pValue; + break; + case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: + if (pValue < timestep) pValue = timestep; + else if (pValue > 120) pValue = 120; + vd.m_angularMotorDecayTimescale = pValue; + break; + case Vehicle.ANGULAR_MOTOR_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_angularMotorTimescale = pValue; + break; + case Vehicle.BANKING_EFFICIENCY: + if (pValue < -1f) pValue = -1f; + if (pValue > 1f) pValue = 1f; + vd.m_bankingEfficiency = pValue; + break; + case Vehicle.BANKING_MIX: + if (pValue < 0f) pValue = 0f; + if (pValue > 1f) pValue = 1f; + vd.m_bankingMix = pValue; + break; + case Vehicle.BANKING_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_bankingTimescale = pValue; + break; + case Vehicle.BUOYANCY: + if (pValue < -1f) pValue = -1f; + if (pValue > 1f) pValue = 1f; + vd.m_VehicleBuoyancy = pValue; + break; + case Vehicle.HOVER_EFFICIENCY: + if (pValue < 0f) pValue = 0f; + if (pValue > 1f) pValue = 1f; + vd.m_VhoverEfficiency = pValue; + break; + case Vehicle.HOVER_HEIGHT: + vd.m_VhoverHeight = pValue; + break; + case Vehicle.HOVER_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_VhoverTimescale = pValue; + break; + case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: + if (pValue < 0f) pValue = 0f; + if (pValue > 1f) pValue = 1f; + vd.m_linearDeflectionEfficiency = pValue; + break; + case Vehicle.LINEAR_DEFLECTION_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_linearDeflectionTimescale = pValue; + break; + case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: + if (pValue < timestep) pValue = timestep; + else if (pValue > 120) pValue = 120; + vd.m_linearMotorDecayTimescale = pValue; + break; + case Vehicle.LINEAR_MOTOR_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_linearMotorTimescale = pValue; + break; + case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: + if (pValue < 0f) pValue = 0f; + if (pValue > 1f) pValue = 1f; + vd.m_verticalAttractionEfficiency = pValue; + break; + case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_verticalAttractionTimescale = pValue; + break; + + // These are vector properties but the engine lets you use a single float value to + // set all of the components to the same value + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + vd.m_angularMotorDirection = new Vector3(pValue, pValue, pValue); + len = vd.m_angularMotorDirection.Length(); + if (len > 12.566f) + vd.m_angularMotorDirection *= (12.566f / len); + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + if (pValue < timestep) pValue = timestep; + vd.m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + vd.m_linearMotorDirection = new Vector3(pValue, pValue, pValue); + len = vd.m_linearMotorDirection.Length(); + if (len > 30.0f) + vd.m_linearMotorDirection *= (30.0f / len); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + vd.m_linearMotorOffset = new Vector3(pValue, pValue, pValue); + len = vd.m_linearMotorOffset.Length(); + if (len > 100.0f) + vd.m_linearMotorOffset *= (100.0f / len); + break; + } + }//end ProcessFloatVehicleParam + + public void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) + { + float len; + float timestep = 0.01f; + switch (pParam) + { + case Vehicle.ANGULAR_FRICTION_TIMESCALE: + if (pValue.X < timestep) pValue.X = timestep; + if (pValue.Y < timestep) pValue.Y = timestep; + if (pValue.Z < timestep) pValue.Z = timestep; + + vd.m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.ANGULAR_MOTOR_DIRECTION: + vd.m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + // Limit requested angular speed to 2 rps= 4 pi rads/sec + len = vd.m_angularMotorDirection.Length(); + if (len > 12.566f) + vd.m_angularMotorDirection *= (12.566f / len); + break; + case Vehicle.LINEAR_FRICTION_TIMESCALE: + if (pValue.X < timestep) pValue.X = timestep; + if (pValue.Y < timestep) pValue.Y = timestep; + if (pValue.Z < timestep) pValue.Z = timestep; + vd.m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + break; + case Vehicle.LINEAR_MOTOR_DIRECTION: + vd.m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); + len = vd.m_linearMotorDirection.Length(); + if (len > 30.0f) + vd.m_linearMotorDirection *= (30.0f / len); + break; + case Vehicle.LINEAR_MOTOR_OFFSET: + vd.m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); + len = vd.m_linearMotorOffset.Length(); + if (len > 100.0f) + vd.m_linearMotorOffset *= (100.0f / len); + break; + } + }//end ProcessVectorVehicleParam + + public void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) + { + switch (pParam) + { + case Vehicle.REFERENCE_FRAME: + vd.m_referenceFrame = pValue; + break; + } + }//end ProcessRotationVehicleParam + + public void ProcessVehicleFlags(int pParam, bool remove) + { + if (remove) + { + vd.m_flags &= ~((VehicleFlag)pParam); + } + else + { + vd.m_flags |= (VehicleFlag)pParam; + } + }//end ProcessVehicleFlags + + public void ProcessTypeChange(Vehicle pType) + { + vd.m_linearMotorDirection = Vector3.Zero; + vd.m_angularMotorDirection = Vector3.Zero; + vd.m_linearMotorOffset = Vector3.Zero; + vd.m_referenceFrame = Quaternion.Identity; + + // Set Defaults For Type + vd.m_type = pType; + switch (pType) + { + case Vehicle.TYPE_NONE: + vd.m_linearFrictionTimescale = new Vector3(1000, 1000, 1000); + vd.m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + vd.m_linearMotorTimescale = 1000; + vd.m_linearMotorDecayTimescale = 120; + vd.m_angularMotorTimescale = 1000; + vd.m_angularMotorDecayTimescale = 1000; + vd.m_VhoverHeight = 0; + vd.m_VhoverEfficiency = 1; + vd.m_VhoverTimescale = 1000; + vd.m_VehicleBuoyancy = 0; + vd.m_linearDeflectionEfficiency = 0; + vd.m_linearDeflectionTimescale = 1000; + vd.m_angularDeflectionEfficiency = 0; + vd.m_angularDeflectionTimescale = 1000; + vd.m_bankingEfficiency = 0; + vd.m_bankingMix = 1; + vd.m_bankingTimescale = 1000; + vd.m_verticalAttractionEfficiency = 0; + vd.m_verticalAttractionTimescale = 1000; + + vd.m_flags = (VehicleFlag)0; + break; + + case Vehicle.TYPE_SLED: + vd.m_linearFrictionTimescale = new Vector3(30, 1, 1000); + vd.m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + vd.m_linearMotorTimescale = 1000; + vd.m_linearMotorDecayTimescale = 120; + vd.m_angularMotorTimescale = 1000; + vd.m_angularMotorDecayTimescale = 120; + vd.m_VhoverHeight = 0; + vd.m_VhoverEfficiency = 1; + vd.m_VhoverTimescale = 10; + vd.m_VehicleBuoyancy = 0; + vd.m_linearDeflectionEfficiency = 1; + vd.m_linearDeflectionTimescale = 1; + vd.m_angularDeflectionEfficiency = 0; + vd.m_angularDeflectionTimescale = 1000; + vd.m_bankingEfficiency = 0; + vd.m_bankingMix = 1; + vd.m_bankingTimescale = 10; + vd.m_flags &= + ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); + vd.m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); + break; + case Vehicle.TYPE_CAR: + vd.m_linearFrictionTimescale = new Vector3(100, 2, 1000); + vd.m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); + vd.m_linearMotorTimescale = 1; + vd.m_linearMotorDecayTimescale = 60; + vd.m_angularMotorTimescale = 1; + vd.m_angularMotorDecayTimescale = 0.8f; + vd.m_VhoverHeight = 0; + vd.m_VhoverEfficiency = 0; + vd.m_VhoverTimescale = 1000; + vd.m_VehicleBuoyancy = 0; + vd.m_linearDeflectionEfficiency = 1; + vd.m_linearDeflectionTimescale = 2; + vd.m_angularDeflectionEfficiency = 0; + vd.m_angularDeflectionTimescale = 10; + vd.m_verticalAttractionEfficiency = 1f; + vd.m_verticalAttractionTimescale = 10f; + vd.m_bankingEfficiency = -0.2f; + vd.m_bankingMix = 1; + vd.m_bankingTimescale = 1; + vd.m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); + vd.m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | + VehicleFlag.LIMIT_MOTOR_UP | VehicleFlag.HOVER_UP_ONLY); + break; + case Vehicle.TYPE_BOAT: + vd.m_linearFrictionTimescale = new Vector3(10, 3, 2); + vd.m_angularFrictionTimescale = new Vector3(10, 10, 10); + vd.m_linearMotorTimescale = 5; + vd.m_linearMotorDecayTimescale = 60; + vd.m_angularMotorTimescale = 4; + vd.m_angularMotorDecayTimescale = 4; + vd.m_VhoverHeight = 0; + vd.m_VhoverEfficiency = 0.5f; + vd.m_VhoverTimescale = 2; + vd.m_VehicleBuoyancy = 1; + vd.m_linearDeflectionEfficiency = 0.5f; + vd.m_linearDeflectionTimescale = 3; + vd.m_angularDeflectionEfficiency = 0.5f; + vd.m_angularDeflectionTimescale = 5; + vd.m_verticalAttractionEfficiency = 0.5f; + vd.m_verticalAttractionTimescale = 5f; + vd.m_bankingEfficiency = -0.3f; + vd.m_bankingMix = 0.8f; + vd.m_bankingTimescale = 1; + vd.m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | + VehicleFlag.HOVER_UP_ONLY | + VehicleFlag.LIMIT_ROLL_ONLY); + vd.m_flags |= (VehicleFlag.NO_DEFLECTION_UP | + VehicleFlag.LIMIT_MOTOR_UP | + VehicleFlag.HOVER_WATER_ONLY); + break; + case Vehicle.TYPE_AIRPLANE: + vd.m_linearFrictionTimescale = new Vector3(200, 10, 5); + vd.m_angularFrictionTimescale = new Vector3(20, 20, 20); + vd.m_linearMotorTimescale = 2; + vd.m_linearMotorDecayTimescale = 60; + vd.m_angularMotorTimescale = 4; + vd.m_angularMotorDecayTimescale = 8; + vd.m_VhoverHeight = 0; + vd.m_VhoverEfficiency = 0.5f; + vd.m_VhoverTimescale = 1000; + vd.m_VehicleBuoyancy = 0; + vd.m_linearDeflectionEfficiency = 0.5f; + vd.m_linearDeflectionTimescale = 0.5f; + vd.m_angularDeflectionEfficiency = 1; + vd.m_angularDeflectionTimescale = 2; + vd.m_verticalAttractionEfficiency = 0.9f; + vd.m_verticalAttractionTimescale = 2f; + vd.m_bankingEfficiency = 1; + vd.m_bankingMix = 0.7f; + vd.m_bankingTimescale = 2; + vd.m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | + VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT | + VehicleFlag.HOVER_UP_ONLY | + VehicleFlag.NO_DEFLECTION_UP | + VehicleFlag.LIMIT_MOTOR_UP); + vd.m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); + break; + case Vehicle.TYPE_BALLOON: + vd.m_linearFrictionTimescale = new Vector3(5, 5, 5); + vd.m_angularFrictionTimescale = new Vector3(10, 10, 10); + vd.m_linearMotorTimescale = 5; + vd.m_linearMotorDecayTimescale = 60; + vd.m_angularMotorTimescale = 6; + vd.m_angularMotorDecayTimescale = 10; + vd.m_VhoverHeight = 5; + vd.m_VhoverEfficiency = 0.8f; + vd.m_VhoverTimescale = 10; + vd.m_VehicleBuoyancy = 1; + vd.m_linearDeflectionEfficiency = 0; + vd.m_linearDeflectionTimescale = 5; + vd.m_angularDeflectionEfficiency = 0; + vd.m_angularDeflectionTimescale = 5; + vd.m_verticalAttractionEfficiency = 0f; + vd.m_verticalAttractionTimescale = 1000f; + vd.m_bankingEfficiency = 0; + vd.m_bankingMix = 0.7f; + vd.m_bankingTimescale = 5; + vd.m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | + VehicleFlag.HOVER_TERRAIN_ONLY | + VehicleFlag.HOVER_UP_ONLY | + VehicleFlag.NO_DEFLECTION_UP | + VehicleFlag.LIMIT_MOTOR_UP); + vd.m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | + VehicleFlag.HOVER_GLOBAL_HEIGHT); + break; + } + } + public void SetVehicle(PhysicsActor ph) + { + if (ph == null) + return; + ph.SetVehicle(vd); + } + + public bool CameraDecoupled + { + get + { + if((vd.m_flags & VehicleFlag.CAMERA_DECOUPLED) != 0) + return true; + return false; + } + } + + private XmlTextWriter writer; + + private void XWint(string name, int i) + { + writer.WriteElementString(name, i.ToString()); + } + + private void XWfloat(string name, float f) + { + writer.WriteElementString(name, f.ToString(Culture.FormatProvider)); + } + + private void XWVector(string name, Vector3 vec) + { + writer.WriteStartElement(name); + writer.WriteElementString("X", vec.X.ToString(Culture.FormatProvider)); + writer.WriteElementString("Y", vec.Y.ToString(Culture.FormatProvider)); + writer.WriteElementString("Z", vec.Z.ToString(Culture.FormatProvider)); + writer.WriteEndElement(); + } + + private void XWQuat(string name, Quaternion quat) + { + writer.WriteStartElement(name); + writer.WriteElementString("X", quat.X.ToString(Culture.FormatProvider)); + writer.WriteElementString("Y", quat.Y.ToString(Culture.FormatProvider)); + writer.WriteElementString("Z", quat.Z.ToString(Culture.FormatProvider)); + writer.WriteElementString("W", quat.W.ToString(Culture.FormatProvider)); + writer.WriteEndElement(); + } + + public void ToXml2(XmlTextWriter twriter) + { + writer = twriter; + writer.WriteStartElement("Vehicle"); + + XWint("TYPE", (int)vd.m_type); + XWint("FLAGS", (int)vd.m_flags); + + // Linear properties + XWVector("LMDIR", vd.m_linearMotorDirection); + XWVector("LMFTIME", vd.m_linearFrictionTimescale); + XWfloat("LMDTIME", vd.m_linearMotorDecayTimescale); + XWfloat("LMTIME", vd.m_linearMotorTimescale); + XWVector("LMOFF", vd.m_linearMotorOffset); + + //Angular properties + XWVector("AMDIR", vd.m_angularMotorDirection); + XWfloat("AMTIME", vd.m_angularMotorTimescale); + XWfloat("AMDTIME", vd.m_angularMotorDecayTimescale); + XWVector("AMFTIME", vd.m_angularFrictionTimescale); + + //Deflection properties + XWfloat("ADEFF", vd.m_angularDeflectionEfficiency); + XWfloat("ADTIME", vd.m_angularDeflectionTimescale); + XWfloat("LDEFF", vd.m_linearDeflectionEfficiency); + XWfloat("LDTIME", vd.m_linearDeflectionTimescale); + + //Banking properties + XWfloat("BEFF", vd.m_bankingEfficiency); + XWfloat("BMIX", vd.m_bankingMix); + XWfloat("BTIME", vd.m_bankingTimescale); + + //Hover and Buoyancy properties + XWfloat("HHEI", vd.m_VhoverHeight); + XWfloat("HEFF", vd.m_VhoverEfficiency); + XWfloat("HTIME", vd.m_VhoverTimescale); + XWfloat("VBUO", vd.m_VehicleBuoyancy); + + //Attractor properties + XWfloat("VAEFF", vd.m_verticalAttractionEfficiency); + XWfloat("VATIME", vd.m_verticalAttractionTimescale); + + XWQuat("REF_FRAME", vd.m_referenceFrame); + + writer.WriteEndElement(); + writer = null; + } + + + + XmlReader reader; + + private int XRint() + { + return reader.ReadElementContentAsInt(); + } + + private float XRfloat() + { + return reader.ReadElementContentAsFloat(); + } + + public Vector3 XRvector() + { + Vector3 vec; + reader.ReadStartElement(); + vec.X = reader.ReadElementContentAsFloat(); + vec.Y = reader.ReadElementContentAsFloat(); + vec.Z = reader.ReadElementContentAsFloat(); + reader.ReadEndElement(); + return vec; + } + + public Quaternion XRquat() + { + Quaternion q; + reader.ReadStartElement(); + q.X = reader.ReadElementContentAsFloat(); + q.Y = reader.ReadElementContentAsFloat(); + q.Z = reader.ReadElementContentAsFloat(); + q.W = reader.ReadElementContentAsFloat(); + reader.ReadEndElement(); + return q; + } + + public static bool EReadProcessors( + Dictionary processors, + XmlReader xtr) + { + bool errors = false; + + string nodeName = string.Empty; + while (xtr.NodeType != XmlNodeType.EndElement) + { + nodeName = xtr.Name; + + // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing: {0}", nodeName); + + Action p = null; + if (processors.TryGetValue(xtr.Name, out p)) + { + // m_log.DebugFormat("[ExternalRepresentationUtils]: Found {0} processor, nodeName); + + try + { + p(); + } + catch + { + errors = true; + if (xtr.NodeType == XmlNodeType.EndElement) + xtr.Read(); + } + } + else + { + // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName); + xtr.ReadOuterXml(); // ignore + } + } + + return errors; + } + + + public string ToXml2() + { + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter xwriter = new XmlTextWriter(sw)) + { + ToXml2(xwriter); + } + + return sw.ToString(); + } + } + + public static SOPVehicle FromXml2(string text) + { + if (text == String.Empty) + return null; + + UTF8Encoding enc = new UTF8Encoding(); + MemoryStream ms = new MemoryStream(enc.GetBytes(text)); + XmlTextReader xreader = new XmlTextReader(ms); + xreader.ProhibitDtd = true; + + SOPVehicle v = new SOPVehicle(); + bool error; + + v.FromXml2(xreader, out error); + + xreader.Close(); + + if (error) + { + v = null; + return null; + } + return v; + } + + public static SOPVehicle FromXml2(XmlReader reader) + { + SOPVehicle vehicle = new SOPVehicle(); + + bool errors = false; + + vehicle.FromXml2(reader, out errors); + if (errors) + return null; + + return vehicle; + } + + private void FromXml2(XmlReader _reader, out bool errors) + { + errors = false; + reader = _reader; + + Dictionary m_VehicleXmlProcessors + = new Dictionary(); + + m_VehicleXmlProcessors.Add("TYPE", ProcessXR_type); + m_VehicleXmlProcessors.Add("FLAGS", ProcessXR_flags); + + // Linear properties + m_VehicleXmlProcessors.Add("LMDIR", ProcessXR_linearMotorDirection); + m_VehicleXmlProcessors.Add("LMFTIME", ProcessXR_linearFrictionTimescale); + m_VehicleXmlProcessors.Add("LMDTIME", ProcessXR_linearMotorDecayTimescale); + m_VehicleXmlProcessors.Add("LMTIME", ProcessXR_linearMotorTimescale); + m_VehicleXmlProcessors.Add("LMOFF", ProcessXR_linearMotorOffset); + + //Angular properties + m_VehicleXmlProcessors.Add("AMDIR", ProcessXR_angularMotorDirection); + m_VehicleXmlProcessors.Add("AMTIME", ProcessXR_angularMotorTimescale); + m_VehicleXmlProcessors.Add("AMDTIME", ProcessXR_angularMotorDecayTimescale); + m_VehicleXmlProcessors.Add("AMFTIME", ProcessXR_angularFrictionTimescale); + + //Deflection properties + m_VehicleXmlProcessors.Add("ADEFF", ProcessXR_angularDeflectionEfficiency); + m_VehicleXmlProcessors.Add("ADTIME", ProcessXR_angularDeflectionTimescale); + m_VehicleXmlProcessors.Add("LDEFF", ProcessXR_linearDeflectionEfficiency); + m_VehicleXmlProcessors.Add("LDTIME", ProcessXR_linearDeflectionTimescale); + + //Banking properties + m_VehicleXmlProcessors.Add("BEFF", ProcessXR_bankingEfficiency); + m_VehicleXmlProcessors.Add("BMIX", ProcessXR_bankingMix); + m_VehicleXmlProcessors.Add("BTIME", ProcessXR_bankingTimescale); + + //Hover and Buoyancy properties + m_VehicleXmlProcessors.Add("HHEI", ProcessXR_VhoverHeight); + m_VehicleXmlProcessors.Add("HEFF", ProcessXR_VhoverEfficiency); + m_VehicleXmlProcessors.Add("HTIME", ProcessXR_VhoverTimescale); + + m_VehicleXmlProcessors.Add("VBUO", ProcessXR_VehicleBuoyancy); + + //Attractor properties + m_VehicleXmlProcessors.Add("VAEFF", ProcessXR_verticalAttractionEfficiency); + m_VehicleXmlProcessors.Add("VATIME", ProcessXR_verticalAttractionTimescale); + + m_VehicleXmlProcessors.Add("REF_FRAME", ProcessXR_referenceFrame); + + vd = new VehicleData(); + + reader.ReadStartElement("Vehicle", String.Empty); + + errors = EReadProcessors( + m_VehicleXmlProcessors, + reader); + + reader.ReadEndElement(); + reader = null; + } + + private void ProcessXR_type() + { + vd.m_type = (Vehicle)XRint(); + } + private void ProcessXR_flags() + { + vd.m_flags = (VehicleFlag)XRint(); + } + // Linear properties + private void ProcessXR_linearMotorDirection() + { + vd.m_linearMotorDirection = XRvector(); + } + + private void ProcessXR_linearFrictionTimescale() + { + vd.m_linearFrictionTimescale = XRvector(); + } + + private void ProcessXR_linearMotorDecayTimescale() + { + vd.m_linearMotorDecayTimescale = XRfloat(); + } + private void ProcessXR_linearMotorTimescale() + { + vd.m_linearMotorTimescale = XRfloat(); + } + private void ProcessXR_linearMotorOffset() + { + vd.m_linearMotorOffset = XRvector(); + } + + + //Angular properties + private void ProcessXR_angularMotorDirection() + { + vd.m_angularMotorDirection = XRvector(); + } + private void ProcessXR_angularMotorTimescale() + { + vd.m_angularMotorTimescale = XRfloat(); + } + private void ProcessXR_angularMotorDecayTimescale() + { + vd.m_angularMotorDecayTimescale = XRfloat(); + } + private void ProcessXR_angularFrictionTimescale() + { + vd.m_angularFrictionTimescale = XRvector(); + } + + //Deflection properties + private void ProcessXR_angularDeflectionEfficiency() + { + vd.m_angularDeflectionEfficiency = XRfloat(); + } + private void ProcessXR_angularDeflectionTimescale() + { + vd.m_angularDeflectionTimescale = XRfloat(); + } + private void ProcessXR_linearDeflectionEfficiency() + { + vd.m_linearDeflectionEfficiency = XRfloat(); + } + private void ProcessXR_linearDeflectionTimescale() + { + vd.m_linearDeflectionTimescale = XRfloat(); + } + + //Banking properties + private void ProcessXR_bankingEfficiency() + { + vd.m_bankingEfficiency = XRfloat(); + } + private void ProcessXR_bankingMix() + { + vd.m_bankingMix = XRfloat(); + } + private void ProcessXR_bankingTimescale() + { + vd.m_bankingTimescale = XRfloat(); + } + + //Hover and Buoyancy properties + private void ProcessXR_VhoverHeight() + { + vd.m_VhoverHeight = XRfloat(); + } + private void ProcessXR_VhoverEfficiency() + { + vd.m_VhoverEfficiency = XRfloat(); + } + private void ProcessXR_VhoverTimescale() + { + vd.m_VhoverTimescale = XRfloat(); + } + + private void ProcessXR_VehicleBuoyancy() + { + vd.m_VehicleBuoyancy = XRfloat(); + } + + //Attractor properties + private void ProcessXR_verticalAttractionEfficiency() + { + vd.m_verticalAttractionEfficiency = XRfloat(); + } + private void ProcessXR_verticalAttractionTimescale() + { + vd.m_verticalAttractionTimescale = XRfloat(); + } + + private void ProcessXR_referenceFrame() + { + vd.m_referenceFrame = XRquat(); + } + } +} diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index e384632..b3303a0 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -106,12 +106,12 @@ namespace OpenSim.Region.Framework.Scenes engine.StartProcessing(); } - public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item) + public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item, uint cost) { IMoneyModule money = RequestModuleInterface(); if (money != null) { - money.ApplyUploadCharge(agentID, money.UploadCharge, "Asset upload"); + money.ApplyUploadCharge(agentID, (int)cost, "Asset upload"); } AddInventoryItem(item); @@ -149,7 +149,7 @@ namespace OpenSim.Region.Framework.Scenes userlevel = 1; } if (trigger) - EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel); + EventManager.TriggerOnNewInventoryItemUploadComplete(item, userlevel); return true; } @@ -164,7 +164,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat( "[AGENT INVENTORY]: Found folder {0} type {1} for item {2}", f.Name, (AssetType)f.Type, item.Name); - + item.Folder = f.ID; } else @@ -182,7 +182,7 @@ namespace OpenSim.Region.Framework.Scenes return false; } } - + if (InventoryService.AddItem(item)) { int userlevel = 0; @@ -191,7 +191,7 @@ namespace OpenSim.Region.Framework.Scenes userlevel = 1; } if (trigger) - EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel); + EventManager.TriggerOnNewInventoryItemUploadComplete(item, userlevel); if (originalFolder != UUID.Zero) { @@ -223,8 +223,7 @@ namespace OpenSim.Region.Framework.Scenes if (core.TryGet(out inv)) { - InventoryFolderBase parent = new InventoryFolderBase(f.ParentID, f.Owner); - parent = InventoryService.GetFolder(parent); + InventoryFolderBase parent = InventoryService.GetFolder(f.Owner, f.ParentID); inv.SendRemoveInventoryItems(new UUID[] { item.ID }); inv.SendBulkUpdateInventory(new InventoryFolderBase[0], new InventoryItemBase[] { item }); string message = "The item was placed in folder " + f.Name; @@ -338,9 +337,9 @@ namespace OpenSim.Region.Framework.Scenes // Update item with new asset item.AssetID = asset.FullID; - if (group.UpdateInventoryItem(item)) - remoteClient.SendAlertMessage("Script saved"); - + group.UpdateInventoryItem(item); + group.InvalidateEffectivePerms(); + part.SendPropertiesToClient(remoteClient); // Trigger rerunning of script (use TriggerRezScript event, see RezScript) @@ -350,12 +349,7 @@ namespace OpenSim.Region.Framework.Scenes { // Needs to determine which engine was running it and use that // - part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0); - errors = part.Inventory.GetScriptErrors(item.ItemID); - } - else - { - remoteClient.SendAlertMessage("Script saved"); + errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 1); } // Tell anyone managing scripts that a script has been reloaded/changed @@ -413,14 +407,14 @@ namespace OpenSim.Region.Framework.Scenes // inventory. Rut-Roh. Whatever. Make this secure. Yeah. // // Passing something to another avatar or a an object will already - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = InventoryService.GetItem(item); + InventoryItemBase item = InventoryService.GetItem(remoteClient.AgentId, itemID); if (item != null) { if (item.Owner != remoteClient.AgentId) return; + item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255); item.Name = itemUpd.Name; item.Description = itemUpd.Description; @@ -526,7 +520,7 @@ namespace OpenSim.Region.Framework.Scenes // needs to be found. If inventory item flags are updated // the viewer's notion of the item needs to be refreshed. // - // In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start + // In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start // failing frequently. Possibly this is a race with a separate transaction that uploads the asset. if (sendUpdate) remoteClient.SendBulkUpdateInventory(item); @@ -590,8 +584,7 @@ namespace OpenSim.Region.Framework.Scenes return null; } - InventoryItemBase item = new InventoryItemBase(itemId, senderId); - item = InventoryService.GetItem(item); + InventoryItemBase item = InventoryService.GetItem(senderId, itemId); if (item == null) { @@ -635,6 +628,7 @@ namespace OpenSim.Region.Framework.Scenes itemCopy.AssetType = item.AssetType; itemCopy.InvType = item.InvType; itemCopy.Folder = recipientFolderId; + itemCopy.Flags = item.Flags; if (Permissions.PropagatePermissions() && recipient != senderId) { @@ -651,10 +645,11 @@ namespace OpenSim.Region.Framework.Scenes // // Transfer // Copy - // Modufy + // Modify uint permsMask = ~ ((uint)PermissionMask.Copy | (uint)PermissionMask.Transfer | - (uint)PermissionMask.Modify); + (uint)PermissionMask.Modify | + (uint)PermissionMask.Export); // Now, reduce the next perms to the mask bits // relevant to the operation @@ -684,18 +679,40 @@ namespace OpenSim.Region.Framework.Scenes (uint)PermissionMask.Move; uint ownerPerms = item.CurrentPermissions; + // These will be applied to the root prim at next rez. + // The legacy slam bit (bit 3) and folded permission (bits 0-2) + // are preserved due to the above mangling +// ownerPerms &= nextPerms; + + // Mask the base permissions. This is a conservative + // approach altering only the three main perms +// basePerms &= nextPerms; + + // Mask out the folded portion of the base mask. + // While the owner mask carries the actual folded + // permissions, the base mask carries the original + // base mask, before masking with the folded perms. + // We need this later for rezzing. +// basePerms &= ~(uint)PermissionMask.FoldedMask; +// basePerms |= ((basePerms >> 13) & 7) | (((basePerms & (uint)PermissionMask.Export) != 0) ? (uint)PermissionMask.FoldedExport : 0); + // If this is an object, root prim perms may be more // permissive than folded perms. Use folded perms as // a mask - if (item.InvType == (int)InventoryType.Object) + uint foldedPerms = (item.CurrentPermissions & (uint)PermissionMask.FoldedMask) << (int)PermissionMask.FoldingShift; + if (foldedPerms != 0 && item.InvType == (int)InventoryType.Object) { + foldedPerms |= permsMask; + bool isRootMod = (item.CurrentPermissions & (uint)PermissionMask.Modify) != 0 ? true : false; // Mask the owner perms to the folded perms - PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref ownerPerms); - PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref basePerms); + // Note that this is only to satisfy the viewer. + // The effect of this will be reversed on rez. + ownerPerms &= foldedPerms; + basePerms &= foldedPerms; // If the root was mod, let the mask reflect that // We also need to adjust the base here, because @@ -708,20 +725,20 @@ namespace OpenSim.Region.Framework.Scenes } } - // These will be applied to the root prim at next rez. - // The slam bit (bit 3) and folded permission (bits 0-2) - // are preserved due to the above mangling + // move here so nextperms are mandatory ownerPerms &= nextPerms; - - // Mask the base permissions. This is a conservative - // approach altering only the three main perms basePerms &= nextPerms; - + basePerms &= ~(uint)PermissionMask.FoldedMask; + basePerms |= ((basePerms >> 13) & 7) | (((basePerms & (uint)PermissionMask.Export) != 0) ? (uint)PermissionMask.FoldedExport : 0); // Assign to the actual item. Make sure the slam bit is // set, if it wasn't set before. itemCopy.BasePermissions = basePerms; itemCopy.CurrentPermissions = ownerPerms; itemCopy.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; + // Need to clear the other inventory slam options. + // That is so we can handle the case where the recipient + // changes the bits in inventory before rezzing + itemCopy.Flags &= ~(uint)(InventoryItemFlags.ObjectOverwriteBase | InventoryItemFlags.ObjectOverwriteOwner | InventoryItemFlags.ObjectOverwriteGroup | InventoryItemFlags.ObjectOverwriteEveryone | InventoryItemFlags.ObjectOverwriteNextOwner); itemCopy.NextPermissions = item.NextPermissions; @@ -742,7 +759,7 @@ namespace OpenSim.Region.Framework.Scenes itemCopy.GroupPermissions = item.GroupPermissions & item.NextPermissions; itemCopy.BasePermissions = item.BasePermissions; } - + if (itemCopy.Folder == UUID.Zero) { InventoryFolderBase folder = null; @@ -771,9 +788,8 @@ namespace OpenSim.Region.Framework.Scenes itemCopy.GroupID = UUID.Zero; itemCopy.GroupOwned = false; - itemCopy.Flags = item.Flags; - itemCopy.SalePrice = item.SalePrice; - itemCopy.SaleType = item.SaleType; + itemCopy.SalePrice = 0; //item.SalePrice; + itemCopy.SaleType = 0; //item.SaleType; IInventoryAccessModule invAccess = RequestModuleInterface(); if (invAccess != null) @@ -812,7 +828,7 @@ namespace OpenSim.Region.Framework.Scenes UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId) { //// Retrieve the folder from the sender - InventoryFolderBase folder = InventoryService.GetFolder(new InventoryFolderBase(folderId, senderId)); + InventoryFolderBase folder = InventoryService.GetFolder(senderId, folderId); if (null == folder) { m_log.ErrorFormat( @@ -834,7 +850,7 @@ namespace OpenSim.Region.Framework.Scenes } UUID newFolderId = UUID.Random(); - InventoryFolderBase newFolder + InventoryFolderBase newFolder = new InventoryFolderBase( newFolderId, folder.Name, recipientId, folder.Type, recipientParentFolderId, folder.Version); InventoryService.AddFolder(newFolder); @@ -873,8 +889,7 @@ namespace OpenSim.Region.Framework.Scenes if (item == null) { - item = new InventoryItemBase(oldItemID, remoteClient.AgentId); - item = InventoryService.GetItem(item); + item = InventoryService.GetItem(remoteClient.AgentId, oldItemID); if (item == null) { @@ -889,6 +904,20 @@ namespace OpenSim.Region.Framework.Scenes if (newName == String.Empty) newName = item.Name; + AssetBase asset = AssetService.Get(item.AssetID.ToString()); + + if (asset != null) + { + if (newName != String.Empty) + { + asset.Name = newName; + } + else + { + newName = item.Name; + } + + if (remoteClient.AgentId == oldAgentID || (LibraryService != null && LibraryService.LibraryRootFolder != null @@ -901,7 +930,7 @@ namespace OpenSim.Region.Framework.Scenes item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch(), false); } else - { + { // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item. if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0) && (m_permissions.BypassPermissions() @@ -915,6 +944,13 @@ namespace OpenSim.Region.Framework.Scenes } } } + else + { + m_log.ErrorFormat( + "[AGENT INVENTORY]: Could not copy item {0} since asset {1} could not be found", + item.Name, item.AssetID); + } + } /// /// Create a new asset data structure. @@ -929,6 +965,24 @@ namespace OpenSim.Region.Framework.Scenes } /// + /// Move an item within the agent's inventory, and leave a copy (used in making a new outfit) + /// + public void MoveInventoryItemsLeaveCopy(IClientAPI remoteClient, List items, UUID destfolder) + { + List moveitems = new List(); + foreach (InventoryItemBase b in items) + { + CopyInventoryItem(remoteClient, 0, remoteClient.AgentId, b.ID, b.Folder, null); + InventoryItemBase n = InventoryService.GetItem(b.Owner, b.ID); + n.Folder = destfolder; + moveitems.Add(n); + remoteClient.SendInventoryItemCreateUpdate(n, 0); + } + + MoveInventoryItem(remoteClient, moveitems); + } + + /// /// Move an item within the agent's inventory. /// /// @@ -946,32 +1000,6 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Create a new inventory item. - /// - /// Client creating this inventory item. - /// - /// - /// UUID of folder in which this item should be placed. - /// Item name. - /// Item description. - /// Item flags - /// Generated by the client. - /// Asset to which this item refers. - /// Type of inventory item. - /// Next owner pemrissions mask. - /// Unix timestamp at which this item was created. - public void CreateNewInventoryItem( - IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID, - string name, string description, uint flags, uint callbackID, - UUID assetID, sbyte assetType, sbyte invType, uint nextOwnerMask, int creationDate) - { - CreateNewInventoryItem( - remoteClient, creatorID, creatorData, folderID, name, description, flags, callbackID, assetID, assetType, invType, - (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, 0, nextOwnerMask, 0, - creationDate, true); - } - - /// /// Create a new Inventory Item /// /// Client creating this inventory item. @@ -990,7 +1018,7 @@ namespace OpenSim.Region.Framework.Scenes /// Next owner pemrissions mask. /// Group permissions mask. /// Unix timestamp at which this item was created. - private void CreateNewInventoryItem( + public void CreateNewInventoryItem( IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID, string name, string description, uint flags, uint callbackID, UUID assetID, sbyte assetType, sbyte invType, uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate, @@ -1015,7 +1043,11 @@ namespace OpenSim.Region.Framework.Scenes item.BasePermissions = baseMask; item.CreationDate = creationDate; - if (AddInventoryItem(item, assetUpload)) + // special AnimationSet case + if (item.InvType == (int)CustomInventoryType.AnimationSet) + AnimationSet.enforceItemPermitions(item,true); + + if (AddInventoryItem(item)) { remoteClient.SendInventoryItemCreateUpdate(item, callbackID); } @@ -1177,13 +1209,14 @@ namespace OpenSim.Region.Framework.Scenes if (group.GetInventoryItem(localID, itemID) != null) { - if (item.Type == 10) + if (item.Type == (int)InventoryType.LSL) { part.RemoveScriptEvents(itemID); - EventManager.TriggerRemoveScript(localID, itemID); + part.ParentGroup.AddActiveScriptCount(-1); } group.RemoveInventoryItem(localID, itemID); + group.InvalidateEffectivePerms(); } part.SendPropertiesToClient(remoteClient); @@ -1228,30 +1261,32 @@ namespace OpenSim.Region.Framework.Scenes agentItem.InvType = taskItem.InvType; agentItem.Flags = taskItem.Flags; + // The code below isn't OK. It doesn't account for flags being changed + // in the object inventory, so it will break when you do it. That + // is the previous behaviour, so no matter at this moment. However, there is a lot + // TODO: Fix this after the inventory fixer exists and has beenr run if ((part.OwnerID != destAgent) && Permissions.PropagatePermissions()) { - agentItem.BasePermissions = taskItem.BasePermissions & (taskItem.NextPermissions | (uint)PermissionMask.Move); + uint perms = taskItem.BasePermissions & taskItem.NextPermissions; if (taskItem.InvType == (int)InventoryType.Object) { - // Bake the new base permissions from folded permissions - // The folded perms are in the lowest 3 bits of the current perms - // We use base permissions here to avoid baking the "Locked" status - // into the item as it is passed. - uint perms = taskItem.BasePermissions & taskItem.NextPermissions; - PermissionsUtil.ApplyFoldedPermissions(taskItem.CurrentPermissions, ref perms); - // Avoid the "lock trap" - move must always be enabled but the above may remove it - // Add it back here. - agentItem.BasePermissions = perms | (uint)PermissionMask.Move; - // Newly given items cannot be "locked" on rez. Make sure by - // setting current equal to base. + PermissionsUtil.ApplyFoldedPermissions(taskItem.CurrentPermissions, ref perms ); + perms = PermissionsUtil.FixAndFoldPermissions(perms); } + else + perms &= taskItem.CurrentPermissions; - agentItem.CurrentPermissions = agentItem.BasePermissions; - + // always unlock + perms |= (uint)PermissionMask.Move; + + agentItem.BasePermissions = perms; + agentItem.CurrentPermissions = perms; + agentItem.NextPermissions = perms & taskItem.NextPermissions; + agentItem.EveryOnePermissions = perms & taskItem.EveryonePermissions; + agentItem.GroupPermissions = perms & taskItem.GroupPermissions; + agentItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; - agentItem.NextPermissions = taskItem.NextPermissions; - agentItem.EveryOnePermissions = taskItem.EveryonePermissions & (taskItem.NextPermissions | (uint)PermissionMask.Move); - agentItem.GroupPermissions = taskItem.GroupPermissions & taskItem.NextPermissions; + agentItem.Flags &= ~(uint)(InventoryItemFlags.ObjectOverwriteBase | InventoryItemFlags.ObjectOverwriteOwner | InventoryItemFlags.ObjectOverwriteGroup | InventoryItemFlags.ObjectOverwriteEveryone | InventoryItemFlags.ObjectOverwriteNextOwner); } else { @@ -1282,7 +1317,7 @@ namespace OpenSim.Region.Framework.Scenes if (taskItem.Type == (int)AssetType.LSLText) { part.RemoveScriptEvents(itemId); - EventManager.TriggerRemoveScript(part.LocalId, itemId); + part.ParentGroup.AddActiveScriptCount(-1); } part.Inventory.RemoveInventoryItem(itemId); @@ -1300,9 +1335,9 @@ namespace OpenSim.Region.Framework.Scenes public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId, out string message) { m_log.DebugFormat( - "[PRIM INVENTORY]: Adding item {0} from {1} to folder {2} for {3}", + "[PRIM INVENTORY]: Adding item {0} from {1} to folder {2} for {3}", itemId, part.Name, folderId, remoteClient.Name); - + InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId, out message); if (agentItem == null) return null; @@ -1327,6 +1362,10 @@ namespace OpenSim.Region.Framework.Scenes { SceneObjectPart part = GetSceneObjectPart(primLocalId); + // Can't move a null item + if (itemId == UUID.Zero) + return; + if (null == part) { m_log.WarnFormat( @@ -1348,24 +1387,12 @@ namespace OpenSim.Region.Framework.Scenes return; } - if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0) - { - // If the item to be moved is no copy, we need to be able to - // edit the prim. - if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId)) - return; - } - else - { - // If the item is copiable, then we just need to have perms - // on it. The delete check is a pure rights check - if (!Permissions.CanDeleteObject(part.UUID, remoteClient.AgentId)) - return; - } + if (!Permissions.CanCopyObjectInventory(itemId, part.UUID, remoteClient.AgentId)) + return; string message; InventoryItemBase item = MoveTaskInventoryItem(remoteClient, folderId, part, itemId, out message); - + if (item == null) remoteClient.SendAgentAlertMessage(message, false); } @@ -1437,20 +1464,7 @@ namespace OpenSim.Region.Framework.Scenes return; } - if (part.OwnerID != destPart.OwnerID) - { - // Source must have transfer permissions - if ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0) - return; - - // Object cannot copy items to an object owned by a different owner - // unless llAllowInventoryDrop has been called on the destination - if ((destPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0) - return; - } - - // must have both move and modify permission to put an item in an object - if ((part.OwnerMask & ((uint)PermissionMask.Move | (uint)PermissionMask.Modify)) == 0) + if(!Permissions.CanDoObjectInvToObjectInv(srcTaskItem, part, destPart)) return; TaskInventoryItem destTaskItem = new TaskInventoryItem(); @@ -1493,9 +1507,10 @@ namespace OpenSim.Region.Framework.Scenes destTaskItem.Type = srcTaskItem.Type; destPart.Inventory.AddInventoryItem(destTaskItem, part.OwnerID != destPart.OwnerID); - if ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0) + { part.Inventory.RemoveInventoryItem(itemId); + } ScenePresence avatar; @@ -1507,10 +1522,20 @@ namespace OpenSim.Region.Framework.Scenes public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List items) { + ScenePresence avatar; IClientAPI remoteClient = null; if (TryGetScenePresence(destID, out avatar)) remoteClient = avatar.ControllingClient; +// ???? + SceneObjectPart destPart = GetSceneObjectPart(destID); + if (destPart != null) // Move into a prim + { + foreach(UUID itemID in items) + MoveTaskInventoryItem(destID, host, itemID); + return destID; // Prim folder ID == prim ID + } +// /???? InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID); @@ -1572,8 +1597,7 @@ namespace OpenSim.Region.Framework.Scenes InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID); // Fetch the folder itself to get its current version - InventoryFolderBase containingFolder = new InventoryFolderBase(folder.ID, client.AgentId); - containingFolder = InventoryService.GetFolder(containingFolder); + InventoryFolderBase containingFolder = InventoryService.GetFolder(client.AgentId, folder.ID); // m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}", // contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName); @@ -1587,7 +1611,7 @@ namespace OpenSim.Region.Framework.Scenes { if (item.AssetType == (int)AssetType.Link) { - InventoryItemBase linkedItem = InventoryService.GetItem(new InventoryItemBase(item.AssetID)); + InventoryItemBase linkedItem = InventoryService.GetItem(client.AgentId, item.AssetID); // Take care of genuinely broken links where the target doesn't exist // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, @@ -1624,127 +1648,127 @@ namespace OpenSim.Region.Framework.Scenes uint primLocalID) { UUID itemID = itemInfo.ItemID; + if (itemID == UUID.Zero) + { + m_log.ErrorFormat( + "[PRIM INVENTORY]: UpdateTaskInventory called with item ID Zero on update for {1}!", + remoteClient.Name); + return; + } // Find the prim we're dealing with SceneObjectPart part = GetSceneObjectPart(primLocalID); + if(part == null) + { + m_log.WarnFormat( + "[PRIM INVENTORY]: " + + "Update with item {0} requested of prim {1} for {2} but this prim does not exist", + itemID, primLocalID, remoteClient.Name); + return; + } - if (part != null) + TaskInventoryItem currentItem = part.Inventory.GetInventoryItem(itemID); + + if (currentItem == null) { - TaskInventoryItem currentItem = part.Inventory.GetInventoryItem(itemID); - bool allowInventoryDrop = (part.GetEffectiveObjectFlags() - & (uint)PrimFlags.AllowInventoryDrop) != 0; + InventoryItemBase item = InventoryService.GetItem(remoteClient.AgentId, itemID); - // Explicity allow anyone to add to the inventory if the - // AllowInventoryDrop flag has been set. Don't however let - // them update an item unless they pass the external checks - // - if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId) - && (currentItem != null || !allowInventoryDrop)) - return; + // if not found Try library + if (item == null && LibraryService != null && LibraryService.LibraryRootFolder != null) + item = LibraryService.LibraryRootFolder.FindItem(itemID); - if (currentItem == null) + if(item == null) { - UUID copyID = UUID.Random(); - if (itemID != UUID.Zero) - { - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = InventoryService.GetItem(item); + m_log.ErrorFormat( + "[PRIM INVENTORY]: Could not find inventory item {0} to update for {1}!", + itemID, remoteClient.Name); + return; + } - // Try library - if (null == item && LibraryService != null && LibraryService.LibraryRootFolder != null) - { - item = LibraryService.LibraryRootFolder.FindItem(itemID); - } + if (!Permissions.CanDropInObjectInv(item, remoteClient, part)) + return; - // If we've found the item in the user's inventory or in the library - if (item != null) - { - part.ParentGroup.AddInventoryItem(remoteClient.AgentId, primLocalID, item, copyID); -//// m_log.InfoFormat( -//// "[PRIM INVENTORY]: Update with item {0} requested of prim {1} for {2}", -//// item.Name, primLocalID, remoteClient.Name); - part.SendPropertiesToClient(remoteClient); - if (!Permissions.BypassPermissions()) - { - if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) - { - List uuids = new List(); - uuids.Add(itemID); - RemoveInventoryItem(remoteClient, uuids); - } - } - } - else - { - m_log.ErrorFormat( - "[PRIM INVENTORY]: Could not find inventory item {0} to update for {1}!", - itemID, remoteClient.Name); - } + UUID copyID = UUID.Random(); + bool modrights = Permissions.CanEditObject(part.ParentGroup, remoteClient); + part.ParentGroup.AddInventoryItem(remoteClient.AgentId, primLocalID, item, copyID, modrights); + m_log.InfoFormat( + "[PRIM INVENTORY]: Update with item {0} requested of prim {1} for {2}", + item.Name, primLocalID, remoteClient.Name); + part.SendPropertiesToClient(remoteClient); + if (!Permissions.BypassPermissions()) + { + if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) + { + List uuids = new List(); + uuids.Add(itemID); + RemoveInventoryItem(remoteClient, uuids); } } - else // Updating existing item with new perms etc - { + } + else // Updating existing item with new perms etc + { // m_log.DebugFormat( -// "[PRIM INVENTORY]: Updating item {0} in {1} for UpdateTaskInventory()", +// "[PRIM INVENTORY]: Updating item {0} in {1} for UpdateTaskInventory()", // currentItem.Name, part.Name); - // Only look for an uploaded updated asset if we are passed a transaction ID. This is only the - // case for updates uploded through UDP. Updates uploaded via a capability (e.g. a script update) - // will not pass in a transaction ID in the update message. - if (transactionID != UUID.Zero && AgentTransactionsModule != null) - { - AgentTransactionsModule.HandleTaskItemUpdateFromTransaction( - remoteClient, part, transactionID, currentItem); + if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId)) + return; - if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) - remoteClient.SendAlertMessage("Notecard saved"); - else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) - remoteClient.SendAlertMessage("Script saved"); - else - remoteClient.SendAlertMessage("Item saved"); - } + // Only look for an uploaded updated asset if we are passed a transaction ID. This is only the + // case for updates uploded through UDP. Updates uploaded via a capability (e.g. a script update) + // will not pass in a transaction ID in the update message. + if (transactionID != UUID.Zero && AgentTransactionsModule != null) + { + AgentTransactionsModule.HandleTaskItemUpdateFromTransaction( + remoteClient, part, transactionID, currentItem); + +// if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) +// remoteClient.SendAgentAlertMessage("Notecard saved", false); +// else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) +// remoteClient.SendAgentAlertMessage("Script saved", false); +// else +// remoteClient.SendAgentAlertMessage("Item saved", false); + } - // Base ALWAYS has move - currentItem.BasePermissions |= (uint)PermissionMask.Move; + // Base ALWAYS has move + currentItem.BasePermissions |= (uint)PermissionMask.Move; - itemInfo.Flags = currentItem.Flags; + itemInfo.Flags = currentItem.Flags; - // Check if we're allowed to mess with permissions - if (!Permissions.IsGod(remoteClient.AgentId)) // Not a god + // Check if we're allowed to mess with permissions + if (!Permissions.IsGod(remoteClient.AgentId)) // Not a god + { + bool noChange; + if (remoteClient.AgentId != part.OwnerID) // Not owner { - if (remoteClient.AgentId != part.OwnerID) // Not owner - { - // Friends and group members can't change any perms - itemInfo.BasePermissions = currentItem.BasePermissions; - itemInfo.EveryonePermissions = currentItem.EveryonePermissions; - itemInfo.GroupPermissions = currentItem.GroupPermissions; - itemInfo.NextPermissions = currentItem.NextPermissions; - itemInfo.CurrentPermissions = currentItem.CurrentPermissions; - } - else + noChange = true; + if(itemInfo.OwnerID == UUID.Zero && itemInfo.GroupID != UUID.Zero) { - // Owner can't change base, and can change other - // only up to base - itemInfo.BasePermissions = currentItem.BasePermissions; - if (itemInfo.EveryonePermissions != currentItem.EveryonePermissions) - itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone; - if (itemInfo.GroupPermissions != currentItem.GroupPermissions) - itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup; - if (itemInfo.CurrentPermissions != currentItem.CurrentPermissions) - itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteOwner; - if (itemInfo.NextPermissions != currentItem.NextPermissions) - itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; - itemInfo.EveryonePermissions &= currentItem.BasePermissions; - itemInfo.GroupPermissions &= currentItem.BasePermissions; - itemInfo.CurrentPermissions &= currentItem.BasePermissions; - itemInfo.NextPermissions &= currentItem.BasePermissions; + if(remoteClient.IsGroupMember(itemInfo.GroupID)) + { + ulong powers = remoteClient.GetGroupPowers(itemInfo.GroupID); + if((powers & (ulong)GroupPowers.ObjectManipulate) != 0) + noChange = false; + } } + } + else + noChange = false; + if(noChange) + { + // Friends and group members can't change any perms + itemInfo.BasePermissions = currentItem.BasePermissions; + itemInfo.EveryonePermissions = currentItem.EveryonePermissions; + itemInfo.GroupPermissions = currentItem.GroupPermissions; + itemInfo.NextPermissions = currentItem.NextPermissions; + itemInfo.CurrentPermissions = currentItem.CurrentPermissions; } else { - if (itemInfo.BasePermissions != currentItem.BasePermissions) - itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteBase; + // Owner can't change base, and can change other + // only up to base + itemInfo.BasePermissions = currentItem.BasePermissions; if (itemInfo.EveryonePermissions != currentItem.EveryonePermissions) itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone; if (itemInfo.GroupPermissions != currentItem.GroupPermissions) @@ -1753,24 +1777,34 @@ namespace OpenSim.Region.Framework.Scenes itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteOwner; if (itemInfo.NextPermissions != currentItem.NextPermissions) itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; + itemInfo.EveryonePermissions &= currentItem.BasePermissions; + itemInfo.GroupPermissions &= currentItem.BasePermissions; + itemInfo.CurrentPermissions &= currentItem.BasePermissions; + itemInfo.NextPermissions &= currentItem.BasePermissions; } + } + else + { + if (itemInfo.BasePermissions != currentItem.BasePermissions) + itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteBase; + if (itemInfo.EveryonePermissions != currentItem.EveryonePermissions) + itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone; + if (itemInfo.GroupPermissions != currentItem.GroupPermissions) + itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup; + if (itemInfo.CurrentPermissions != currentItem.CurrentPermissions) + itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteOwner; + if (itemInfo.NextPermissions != currentItem.NextPermissions) + itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner; + } - // Next ALWAYS has move - itemInfo.NextPermissions |= (uint)PermissionMask.Move; + // Next ALWAYS has move + itemInfo.NextPermissions |= (uint)PermissionMask.Move; - if (part.Inventory.UpdateInventoryItem(itemInfo)) - { - part.SendPropertiesToClient(remoteClient); - } + if (part.Inventory.UpdateInventoryItem(itemInfo)) + { + part.SendPropertiesToClient(remoteClient); } } - else - { - m_log.WarnFormat( - "[PRIM INVENTORY]: " + - "Update with item {0} requested of prim {1} for {2} but this prim does not exist", - itemID, primLocalID, remoteClient.Name); - } } /// @@ -1803,8 +1837,7 @@ namespace OpenSim.Region.Framework.Scenes public SceneObjectPart RezScriptFromAgentInventory(UUID agentID, UUID fromItemID, uint localID) { UUID copyID = UUID.Random(); - InventoryItemBase item = new InventoryItemBase(fromItemID, agentID); - item = InventoryService.GetItem(item); + InventoryItemBase item = InventoryService.GetItem(agentID, fromItemID); // Try library // XXX clumsy, possibly should be one call @@ -1898,12 +1931,12 @@ namespace OpenSim.Region.Framework.Scenes return null; } - AssetBase asset + AssetBase asset = CreateAsset( - itemBase.Name, - itemBase.Description, + itemBase.Name, + itemBase.Description, (sbyte)itemBase.AssetType, - Encoding.ASCII.GetBytes(scriptText), + Encoding.ASCII.GetBytes(scriptText), agentID); AssetService.Store(asset); @@ -1934,6 +1967,8 @@ namespace OpenSim.Region.Framework.Scenes part.Inventory.AddInventoryItem(taskItem, false); part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 0); + part.ParentGroup.InvalidateEffectivePerms(); + // tell anyone managing scripts that a new script exists EventManager.TriggerNewScript(agentID, part, taskItem.ItemID); @@ -1982,8 +2017,8 @@ namespace OpenSim.Region.Framework.Scenes if ((destPart.GroupID == UUID.Zero) || (destPart.GroupID != srcPart.GroupID) || ((destPart.GroupMask & (uint)PermissionMask.Modify) == 0)) return; - } - else + } + else { if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0) return; @@ -2069,12 +2104,20 @@ namespace OpenSim.Region.Framework.Scenes /// DeRezAction /// User folder ID to place derezzed object public virtual void DeRezObjects( - IClientAPI remoteClient, List localIDs, UUID groupID, DeRezAction action, UUID destinationID) + IClientAPI remoteClient, List localIDs, UUID groupID, DeRezAction action, UUID destinationID, bool AddToReturns = true) { // First, see of we can perform the requested action and // build a list of eligible objects List deleteIDs = new List(); List deleteGroups = new List(); + List takeGroups = new List(); + List takeDeleteGroups = new List(); + + ScenePresence sp = null; + if(remoteClient != null) + sp = remoteClient.SceneAgent as ScenePresence; + else if(action != DeRezAction.Return) + return; // only Return can be called without a client // Start with true for both, then remove the flags if objects // that we can't derez are part of the selection @@ -2087,20 +2130,27 @@ namespace OpenSim.Region.Framework.Scenes // Invalid id SceneObjectPart part = GetSceneObjectPart(localID); if (part == null) + { + //Client still thinks the object exists, kill it + deleteIDs.Add(localID); continue; + } // Already deleted by someone else if (part.ParentGroup.IsDeleted) + { + //Client still thinks the object exists, kill it + deleteIDs.Add(localID); continue; + } // Can't delete child prims if (part != part.ParentGroup.RootPart) continue; SceneObjectGroup grp = part.ParentGroup; - - deleteIDs.Add(localID); - deleteGroups.Add(grp); + if (grp.IsAttachment) + continue; // If child prims have invalid perms, fix them grp.AdjustChildPrimPermissions(false); @@ -2112,7 +2162,7 @@ namespace OpenSim.Region.Framework.Scenes if (action != DeRezAction.Return) { m_log.WarnFormat( - "[AGENT INVENTORY]: Ignoring attempt to {0} {1} {2} without a client", + "[AGENT INVENTORY]: Ignoring attempt to {0} {1} {2} without a client", action, grp.Name, grp.UUID); return; } @@ -2121,87 +2171,190 @@ namespace OpenSim.Region.Framework.Scenes } else { - if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId)) + if (action == DeRezAction.TakeCopy) + { + if (!Permissions.CanTakeCopyObject(grp, sp)) + permissionToTakeCopy = false; + } + else + { permissionToTakeCopy = false; - - if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId)) + } + if (!Permissions.CanTakeObject(grp, sp)) permissionToTake = false; - - if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId)) + + if (!Permissions.CanDeleteObject(grp, remoteClient)) permissionToDelete = false; } - } - // Handle god perms - if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) - { - permissionToTake = true; - permissionToTakeCopy = true; - permissionToDelete = true; - } - - // If we're re-saving, we don't even want to delete - if (action == DeRezAction.SaveToExistingUserInventoryItem) - permissionToDelete = false; - - // if we want to take a copy, we also don't want to delete - // Note: after this point, the permissionToTakeCopy flag - // becomes irrelevant. It already includes the permissionToTake - // permission and after excluding no copy items here, we can - // just use that. - if (action == DeRezAction.TakeCopy) - { - // If we don't have permission, stop right here - if (!permissionToTakeCopy) + // Handle god perms + if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) { - remoteClient.SendAlertMessage("You don't have permission to take the object"); - return; + permissionToTake = true; + permissionToTakeCopy = true; + permissionToDelete = true; } - permissionToTake = true; - // Don't delete - permissionToDelete = false; - } + // If we're re-saving, we don't even want to delete + if (action == DeRezAction.SaveToExistingUserInventoryItem) + permissionToDelete = false; - if (action == DeRezAction.Return) - { - if (remoteClient != null) + // if we want to take a copy, we also don't want to delete + // Note: after this point, the permissionToTakeCopy flag + // becomes irrelevant. It already includes the permissionToTake + // permission and after excluding no copy items here, we can + // just use that. + if (action == DeRezAction.TakeCopy) { - if (Permissions.CanReturnObjects( - null, - remoteClient.AgentId, - deleteGroups)) + // If we don't have permission, stop right here + if (!permissionToTakeCopy) { - permissionToTake = true; - permissionToDelete = true; + remoteClient.SendAlertMessage("You don't have permission to take the object"); + return; + } + + permissionToTake = true; + // Don't delete + permissionToDelete = false; + } - foreach (SceneObjectGroup g in deleteGroups) + if (action == DeRezAction.Return) + { + if (remoteClient != null) + { + if (Permissions.CanReturnObjects( + null, + remoteClient, + new List() {grp})) { - AddReturn(g.OwnerID == g.GroupID ? g.LastOwnerID : g.OwnerID, g.Name, g.AbsolutePosition, "parcel owner return"); + permissionToTake = true; + permissionToDelete = true; + if(AddToReturns) + AddReturn(grp.OwnerID == grp.GroupID ? grp.LastOwnerID : grp.OwnerID, grp.Name, grp.AbsolutePosition, + "parcel owner return"); } } + else // Auto return passes through here with null agent + { + permissionToTake = true; + permissionToDelete = true; + } } - else // Auto return passes through here with null agent + + if (permissionToDelete) { - permissionToTake = true; - permissionToDelete = true; + if (permissionToTake) + takeDeleteGroups.Add(grp); + else + deleteGroups.Add(grp); + deleteIDs.Add(grp.LocalId); } + else if(permissionToTake) + takeGroups.Add(grp); } - // OK, we're done with permissions. Let's check if any part of the code prevents the objects from being deleted - bool canDelete = EventManager.TriggerDeRezRequested(remoteClient, deleteGroups, action); + SendKillObject(deleteIDs); - if (permissionToTake && (action != DeRezAction.Delete || this.m_useTrashOnDelete)) + if (takeDeleteGroups.Count > 0) + { + m_asyncSceneObjectDeleter.DeleteToInventory( + action, destinationID, takeDeleteGroups, remoteClient, + true); + } + if (takeGroups.Count > 0) { m_asyncSceneObjectDeleter.DeleteToInventory( - action, destinationID, deleteGroups, remoteClient, - permissionToDelete && canDelete); + action, destinationID, takeGroups, remoteClient, + false); } - else if (permissionToDelete && canDelete) + if (deleteGroups.Count > 0) { foreach (SceneObjectGroup g in deleteGroups) - DeleteSceneObject(g, false); + DeleteSceneObject(g, true); + } + } + + public UUID attachObjectAssetStore(IClientAPI remoteClient, SceneObjectGroup grp, UUID AgentId, out UUID itemID) + { + itemID = UUID.Zero; + if (grp != null) + { + Vector3 inventoryStoredPosition = new Vector3( + Math.Min(grp.AbsolutePosition.X, RegionInfo.RegionSizeX - 6), + Math.Min(grp.AbsolutePosition.Y, RegionInfo.RegionSizeY - 6), + grp.AbsolutePosition.Z); + + Vector3 originalPosition = grp.AbsolutePosition; + + grp.AbsolutePosition = inventoryStoredPosition; + + string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); + + grp.AbsolutePosition = originalPosition; + + AssetBase asset = CreateAsset( + grp.GetPartName(grp.LocalId), + grp.GetPartDescription(grp.LocalId), + (sbyte)AssetType.Object, + Utils.StringToBytes(sceneObjectXml), + remoteClient.AgentId); + AssetService.Store(asset); + + InventoryItemBase item = new InventoryItemBase(); + item.CreatorId = grp.RootPart.CreatorID.ToString(); + item.CreatorData = grp.RootPart.CreatorData; + item.Owner = remoteClient.AgentId; + item.ID = UUID.Random(); + item.AssetID = asset.FullID; + item.Description = asset.Description; + item.Name = asset.Name; + item.AssetType = asset.Type; + item.InvType = (int)InventoryType.Object; + + InventoryFolderBase folder = InventoryService.GetFolderForType(remoteClient.AgentId, FolderType.Object); + if (folder != null) + item.Folder = folder.ID; + else // oopsies + item.Folder = UUID.Zero; + + // Set up base perms properly + uint permsBase = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify); + permsBase &= grp.RootPart.BaseMask; + permsBase |= (uint)PermissionMask.Move; + + // Make sure we don't lock it + grp.RootPart.NextOwnerMask |= (uint)PermissionMask.Move; + + if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions()) + { + item.BasePermissions = permsBase & grp.RootPart.NextOwnerMask; + item.CurrentPermissions = permsBase & grp.RootPart.NextOwnerMask; + item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask; + item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; + item.GroupPermissions = permsBase & grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; + } + else + { + item.BasePermissions = permsBase; + item.CurrentPermissions = permsBase & grp.RootPart.OwnerMask; + item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask; + item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask; + item.GroupPermissions = permsBase & grp.RootPart.GroupMask; + } + item.CreationDate = Util.UnixTimeSinceEpoch(); + + // sets itemID so client can show item as 'attached' in inventory + grp.FromItemID = item.ID; + + if (AddInventoryItem(item)) + remoteClient.SendInventoryItemCreateUpdate(item, 0); + else + m_dialogModule.SendAlertToUser(remoteClient, "Operation failed"); + + itemID = item.ID; + return item.AssetID; } + return UUID.Zero; } /// @@ -2236,7 +2389,7 @@ namespace OpenSim.Region.Framework.Scenes { using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null)) { - using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment })) + using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment, ProhibitDtd = true })) { reader.Read(); bool isSingleObject = reader.Name != "CoalescedObject"; @@ -2254,7 +2407,7 @@ namespace OpenSim.Region.Framework.Scenes Util.LogFailedXML("[AGENT INVENTORY]:", xmlData); g = null; } - + if (g != null) { objlist.Add(g); @@ -2265,8 +2418,9 @@ namespace OpenSim.Region.Framework.Scenes return true; } else - { + { XmlDocument doc = new XmlDocument(); + doc.XmlResolver=null; doc.LoadXml(xmlData); XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); XmlElement coll = (XmlElement)e; @@ -2316,6 +2470,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// + /// /// /// /// @@ -2326,55 +2481,55 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public virtual void RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, + public virtual void RezObject(IClientAPI remoteClient, UUID itemID, UUID rezGroupID, + Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID) { // m_log.DebugFormat( -// "[PRIM INVENTORY]: RezObject from {0} for item {1} from task id {2}", +// "[PRIM INVENTORY]: RezObject from {0} for item {1} from task id {2}", // remoteClient.Name, itemID, fromTaskID); - + if (fromTaskID == UUID.Zero) { IInventoryAccessModule invAccess = RequestModuleInterface(); if (invAccess != null) invAccess.RezObject( - remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, + remoteClient, itemID, rezGroupID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, RezSelected, RemoveItem, fromTaskID, false); } else - { + { SceneObjectPart part = GetSceneObjectPart(fromTaskID); if (part == null) { - m_log.ErrorFormat( - "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such scene object", + m_log.ErrorFormat( + "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such scene object", remoteClient.Name, itemID, fromTaskID); - + return; } - + TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID); if (item == null) { - m_log.ErrorFormat( - "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such item", + m_log.ErrorFormat( + "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such item", remoteClient.Name, itemID, fromTaskID); - + return; - } - + } + byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); - Vector3 pos - = GetNewRezLocation( + Vector3 pos = GetNewRezLocation( RayStart, RayEnd, RayTargetID, Quaternion.Identity, - BypassRayCast, bRayEndIsIntersection, true, scale, false); - - RezObject(part, item, pos, null, Vector3.Zero, 0); + BypassRayCast, bRayEndIsIntersection, true, scale, false); + + RezObject(part, item, pos, null, Vector3.Zero, 0, false); } } - + /// /// Rez an object into the scene from a prim's inventory. /// @@ -2387,15 +2542,18 @@ namespace OpenSim.Region.Framework.Scenes /// /// The SceneObjectGroup(s) rezzed, or null if rez was unsuccessful public virtual List RezObject( - SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param) + SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param, bool atRoot) { if (null == item) return null; List objlist; List veclist; - - bool success = sourcePart.Inventory.GetRezReadySceneObjects(item, out objlist, out veclist); + Vector3 bbox; + float offsetHeight; + + bool success = sourcePart.Inventory.GetRezReadySceneObjects(item, out objlist, out veclist,out bbox, out offsetHeight); + if (!success) return null; @@ -2412,10 +2570,69 @@ namespace OpenSim.Region.Framework.Scenes sourcePart.Inventory.RemoveInventoryItem(item.ItemID); } + SceneObjectGroup sog; + + bool fixrot = false; + Quaternion netRot = Quaternion.Identity; + + // position adjust + if (totalPrims > 1) // nothing to do on a single prim + { + if (objlist.Count == 1) + { + // current object position is root position + if(!atRoot) + { + sog = objlist[0]; + Quaternion orot; + if (rot == null) + orot = sog.RootPart.GetWorldRotation(); + else + orot = rot.Value; + // possible should be bbox, but geometric center looks better + Vector3 off = sog.GetGeometricCenter(); +// Vector3 off = bbox * 0.5f; + off *= orot; + pos -= off; + } + } + else + { + //veclist[] are relative to bbox corner with min X,Y and Z + // rez at root, and rot will be referenced to first object in list + if (rot == null) + { + // use original rotations + if (atRoot) + pos -= veclist[0]; + else + pos -= bbox / 2; + } + else + { + fixrot = true; + sog = objlist[0]; + netRot = Quaternion.Conjugate(sog.RootPart.GetWorldRotation()); + netRot = netRot * rot.Value; + Vector3 off; + if (atRoot) + off = veclist[0]; + else + off = bbox / 2; + off *= netRot; + pos -= off; + } + } + } + for (int i = 0; i < objlist.Count; i++) { SceneObjectGroup group = objlist[i]; - Vector3 curpos = pos + veclist[i]; + Vector3 curpos; + if(fixrot) + curpos = pos + veclist[i] * netRot; + else + curpos = pos + veclist[i]; if (group.IsAttachment == false && group.RootPart.Shape.State != 0) { @@ -2423,11 +2640,23 @@ namespace OpenSim.Region.Framework.Scenes group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; } - group.FromPartID = sourcePart.UUID; - AddNewSceneObject(group, true, curpos, rot, vel); + group.RezzerID = sourcePart.UUID; + + if( i == 0) + AddNewSceneObject(group, true, curpos, rot, vel); + else + { + Quaternion crot = objlist[i].RootPart.GetWorldRotation(); + if (fixrot) + { + crot *= netRot; + } + AddNewSceneObject(group, true, curpos, crot, vel); + } // We can only call this after adding the scene object, since the scene object references the scene // to find out if scripts should be activated at all. + group.InvalidateEffectivePerms(); group.CreateScriptInstances(param, true, DefaultScriptEngine, 3); group.ScheduleGroupForFullUpdate(); @@ -2437,7 +2666,7 @@ namespace OpenSim.Region.Framework.Scenes } public virtual bool returnObjects(SceneObjectGroup[] returnobjects, - UUID AgentId) + IClientAPI client) { List localIDs = new List(); @@ -2447,14 +2676,17 @@ namespace OpenSim.Region.Framework.Scenes "parcel owner return"); localIDs.Add(grp.RootPart.LocalId); } - DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, - UUID.Zero); + DeRezObjects(client, localIDs, UUID.Zero, DeRezAction.Return, + UUID.Zero, false); return true; } public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running) { + if (!Permissions.CanEditScript(itemID, objectID, controllingClient.AgentId)) + return; + SceneObjectPart part = GetSceneObjectPart(objectID); if (part == null) return; @@ -2476,9 +2708,6 @@ namespace OpenSim.Region.Framework.Scenes { if (ownerID != UUID.Zero) return; - - if (!Permissions.CanDeedObject(remoteClient.AgentId, groupID)) - return; } List groups = new List(); @@ -2486,8 +2715,8 @@ namespace OpenSim.Region.Framework.Scenes foreach (uint localID in localIDs) { SceneObjectPart part = GetSceneObjectPart(localID); - if (part == null) - continue; + if (part == null) + continue; if (!groups.Contains(part.ParentGroup)) groups.Add(part.ParentGroup); @@ -2502,40 +2731,46 @@ namespace OpenSim.Region.Framework.Scenes sog.ScheduleGroupForFullUpdate(); SceneObjectPart[] partList = sog.Parts; - + foreach (SceneObjectPart child in partList) { child.Inventory.ChangeInventoryOwner(ownerID); child.TriggerScriptChangedEvent(Changed.OWNER); } } - else + else // The object deeded to the group { - if (!Permissions.CanEditObject(sog.UUID, remoteClient.AgentId)) + if (!Permissions.CanDeedObject(remoteClient, sog, groupID)) continue; - if (sog.GroupID != groupID) - continue; - - SceneObjectPart[] partList = sog.Parts; + sog.SetOwnerId(groupID); + + // this is wrong, GroupMask is used for group sharing, still possible to set + // this whould give owner rights to users that are member of group but don't have role powers to edit +// sog.RootPart.GroupMask = sog.RootPart.OwnerMask; + + // we should keep all permissions on deed to group + // and with this comented code, if user does not set next permissions on the object + // and on ALL contents of ALL prims, he may loose rights, making the object useless + sog.ApplyNextOwnerPermissions(); + sog.InvalidateEffectivePerms(); + + sog.ScheduleGroupForFullUpdate(); + SceneObjectPart[] partList = sog.Parts; foreach (SceneObjectPart child in partList) { - child.LastOwnerID = child.OwnerID; child.Inventory.ChangeInventoryOwner(groupID); child.TriggerScriptChangedEvent(Changed.OWNER); } - - sog.SetOwnerId(groupID); - sog.ApplyNextOwnerPermissions(); } } foreach (uint localID in localIDs) { SceneObjectPart part = GetSceneObjectPart(localID); - if (part == null) - continue; + if (part == null) + continue; part.SendPropertiesToClient(remoteClient); } } @@ -2622,7 +2857,18 @@ namespace OpenSim.Region.Framework.Scenes return; } + bool oldUsePhysics = (root.Flags & PrimFlags.Physics) != 0; m_sceneGraph.LinkObjects(root, children); + + ScenePresence sp; + if (TryGetScenePresence(agentId, out sp)) + { + root.SendPropertiesToClient(sp.ControllingClient); + if (oldUsePhysics && (root.Flags & PrimFlags.Physics) == 0) + { + sp.ControllingClient.SendAlertMessage("Object physics cancelled"); + } + } } private string PermissionString(uint permissions) diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 8ebcd92..84bad25 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -49,7 +49,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName, + public void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName, UUID fromID, UUID targetID, bool fromAgent, bool broadcast) { OSChatMessage args = new OSChatMessage(); @@ -60,6 +60,7 @@ namespace OpenSim.Region.Framework.Scenes args.Position = fromPos; args.SenderUUID = fromID; args.Scene = this; + args.Destination = targetID; if (fromAgent) { @@ -74,7 +75,7 @@ namespace OpenSim.Region.Framework.Scenes } args.From = fromName; - args.TargetUUID = targetID; + //args. // m_log.DebugFormat( // "[SCENE]: Sending message {0} on channel {1}, type {2} from {3}, broadcast {4}", @@ -129,19 +130,6 @@ namespace OpenSim.Region.Framework.Scenes { SimChat(message, type, channel, fromPos, fromName, fromID, fromAgent, true); } - /// - /// - /// - /// - /// - /// - /// - /// - /// - public void SimChatToAgent(UUID targetID, byte[] message, Vector3 fromPos, string fromName, UUID fromID, bool fromAgent) - { - SimChat(message, ChatTypeEnum.Say, 0, fromPos, fromName, fromID, targetID, fromAgent, false); - } /// /// @@ -176,29 +164,34 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public void SelectPrim(uint primLocalID, IClientAPI remoteClient) + public void SelectPrim(List primIDs, IClientAPI remoteClient) { - SceneObjectPart part = GetSceneObjectPart(primLocalID); + foreach(uint primLocalID in primIDs) + { + SceneObjectPart part = GetSceneObjectPart(primLocalID); - if (null == part) - return; + if (part == null) + continue; - if (part.IsRoot) - { SceneObjectGroup sog = part.ParentGroup; - sog.SendPropertiesToClient(remoteClient); - sog.IsSelected = true; + if (sog == null) + continue; + + // waste of time because properties do not send prim flags as they should + // if a friend got or lost edit rights after login, a full update is needed + if(sog.OwnerID != remoteClient.AgentId) + part.SendFullUpdate(remoteClient); // A prim is only tainted if it's allowed to be edited by the person clicking it. - if (Permissions.CanEditObject(sog.UUID, remoteClient.AgentId) - || Permissions.CanMoveObject(sog.UUID, remoteClient.AgentId)) + if (Permissions.CanChangeSelectedState(part, (ScenePresence)remoteClient.SceneAgent)) { - EventManager.TriggerParcelPrimCountTainted(); + bool oldsel = part.IsSelected; + part.IsSelected = true; + if(!oldsel) + EventManager.TriggerParcelPrimCountTainted(); } - } - else - { - part.SendPropertiesToClient(remoteClient); + + part.SendPropertiesToClient(remoteClient); } } @@ -220,13 +213,13 @@ namespace OpenSim.Region.Framework.Scenes if (groupID != UUID.Zero) { GroupMembershipData gmd = m_groupsModule.GetMembershipData(groupID, remoteClient.AgentId); - + if (gmd == null) { // m_log.WarnFormat( // "[GROUPS]: User {0} is not a member of group {1} so they can't update {2} to this group", // remoteClient.Name, GroupID, objectLocalID); - + return; } } @@ -237,6 +230,7 @@ namespace OpenSim.Region.Framework.Scenes if (so.OwnerID == remoteClient.AgentId) { so.SetGroup(groupID, remoteClient); + EventManager.TriggerParcelPrimCountTainted(); } } } @@ -251,40 +245,29 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = GetSceneObjectPart(primLocalID); if (part == null) return; - - // A deselect packet contains all the local prims being deselected. However, since selection is still - // group based we only want the root prim to trigger a full update - otherwise on objects with many prims - // we end up sending many duplicate ObjectUpdates - if (part.ParentGroup.RootPart.LocalId != part.LocalId) - return; + + bool oldgprSelect = part.ParentGroup.IsSelected; // This is wrong, wrong, wrong. Selection should not be // handled by group, but by prim. Legacy cruft. // TODO: Make selection flagging per prim! // - part.ParentGroup.IsSelected = false; - - part.ParentGroup.ScheduleGroupForFullUpdate(); - - // If it's not an attachment, and we are allowed to move it, - // then we might have done so. If we moved across a parcel - // boundary, we will need to recount prims on the parcels. - // For attachments, that makes no sense. - // - if (!part.ParentGroup.IsAttachment) + if (Permissions.CanChangeSelectedState(part, (ScenePresence)remoteClient.SceneAgent)) { - if (Permissions.CanEditObject( - part.UUID, remoteClient.AgentId) - || Permissions.CanMoveObject( - part.UUID, remoteClient.AgentId)) + part.IsSelected = false; + if (!part.ParentGroup.IsAttachment && oldgprSelect != part.ParentGroup.IsSelected) EventManager.TriggerParcelPrimCountTainted(); + + // restore targetOmega + if (part.AngularVelocity != Vector3.Zero) + part.ScheduleTerseUpdate(); } } - public virtual void ProcessMoneyTransferRequest(UUID source, UUID destination, int amount, + public virtual void ProcessMoneyTransferRequest(UUID source, UUID destination, int amount, int transactiontype, string description) { - EventManager.MoneyTransferArgs args = new EventManager.MoneyTransferArgs(source, destination, amount, + EventManager.MoneyTransferArgs args = new EventManager.MoneyTransferArgs(source, destination, amount, transactiontype, description); EventManager.TriggerMoneyTransfer(this, args); @@ -293,8 +276,8 @@ namespace OpenSim.Region.Framework.Scenes public virtual void ProcessParcelBuy(UUID agentId, UUID groupId, bool final, bool groupOwned, bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated) { - EventManager.LandBuyArgs args = new EventManager.LandBuyArgs(agentId, groupId, final, groupOwned, - removeContribution, parcelLocalID, parcelArea, + EventManager.LandBuyArgs args = new EventManager.LandBuyArgs(agentId, groupId, final, groupOwned, + removeContribution, parcelLocalID, parcelArea, parcelPrice, authenticated); // First, allow all validators a stab at it @@ -307,7 +290,7 @@ namespace OpenSim.Region.Framework.Scenes public virtual void ProcessObjectGrab(uint localID, Vector3 offsetPos, IClientAPI remoteClient, List surfaceArgs) { SceneObjectPart part = GetSceneObjectPart(localID); - + if (part == null) return; @@ -320,19 +303,17 @@ namespace OpenSim.Region.Framework.Scenes // Currently only grab/touch for the single prim // the client handles rez correctly obj.ObjectGrabHandler(localID, offsetPos, remoteClient); - + // If the touched prim handles touches, deliver it - // If not, deliver to root prim if ((part.ScriptEvents & scriptEvents.touch_start) != 0) - EventManager.TriggerObjectGrab(part.LocalId, 0, part.OffsetPosition, remoteClient, surfaceArg); + EventManager.TriggerObjectGrab(part.LocalId, 0, offsetPos, remoteClient, surfaceArg); // Deliver to the root prim if the touched prim doesn't handle touches - // or if we're meant to pass on touches anyway. Don't send to root prim - // if prim touched is the root prim as we just did it + // or if we're meant to pass on touches anyway. if (((part.ScriptEvents & scriptEvents.touch_start) == 0) || - (part.PassTouches && (part.LocalId != obj.RootPart.LocalId))) + (part.PassTouches && (part.LocalId != obj.RootPart.LocalId))) { - EventManager.TriggerObjectGrab(obj.RootPart.LocalId, part.LocalId, part.OffsetPosition, remoteClient, surfaceArg); + EventManager.TriggerObjectGrab(obj.RootPart.LocalId, part.LocalId, offsetPos, remoteClient, surfaceArg); } } @@ -343,23 +324,37 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) return; - SceneObjectGroup obj = part.ParentGroup; + SceneObjectGroup group = part.ParentGroup; + if(group == null || group.IsDeleted) + return; + + if (Permissions.CanMoveObject(group, remoteClient))// && PermissionsMngr.) + { + group.GrabMovement(objectID, offset, pos, remoteClient); + } + + // This is outside the above permissions condition + // so that if the object is locked the client moving the object + // get's it's position on the simulator even if it was the same as before + // This keeps the moving user's client in sync with the rest of the world. + group.SendGroupTerseUpdate(); SurfaceTouchEventArgs surfaceArg = null; if (surfaceArgs != null && surfaceArgs.Count > 0) surfaceArg = surfaceArgs[0]; + Vector3 grabOffset = pos - part.AbsolutePosition; // If the touched prim handles touches, deliver it - // If not, deliver to root prim if ((part.ScriptEvents & scriptEvents.touch) != 0) - EventManager.TriggerObjectGrabbing(part.LocalId, 0, part.OffsetPosition, remoteClient, surfaceArg); +// EventManager.TriggerObjectGrabbing(part.LocalId, 0, part.OffsetPosition, remoteClient, surfaceArg); + EventManager.TriggerObjectGrabbing(part.LocalId, 0, grabOffset, remoteClient, surfaceArg); // Deliver to the root prim if the touched prim doesn't handle touches - // or if we're meant to pass on touches anyway. Don't send to root prim - // if prim touched is the root prim as we just did it + // or if we're meant to pass on touches anyway. if (((part.ScriptEvents & scriptEvents.touch) == 0) || - (part.PassTouches && (part.LocalId != obj.RootPart.LocalId))) + (part.PassTouches && (part.LocalId != group.RootPart.LocalId))) { - EventManager.TriggerObjectGrabbing(obj.RootPart.LocalId, part.LocalId, part.OffsetPosition, remoteClient, surfaceArg); +// EventManager.TriggerObjectGrabbing(group.RootPart.LocalId, part.LocalId, part.OffsetPosition, remoteClient, surfaceArg); + EventManager.TriggerObjectGrabbing(group.RootPart.LocalId, part.LocalId, grabOffset, remoteClient, surfaceArg); } } @@ -369,18 +364,77 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) return; - SceneObjectGroup obj = part.ParentGroup; + SceneObjectGroup grp = part.ParentGroup; SurfaceTouchEventArgs surfaceArg = null; if (surfaceArgs != null && surfaceArgs.Count > 0) surfaceArg = surfaceArgs[0]; // If the touched prim handles touches, deliver it - // If not, deliver to root prim if ((part.ScriptEvents & scriptEvents.touch_end) != 0) EventManager.TriggerObjectDeGrab(part.LocalId, 0, remoteClient, surfaceArg); - else - EventManager.TriggerObjectDeGrab(obj.RootPart.LocalId, part.LocalId, remoteClient, surfaceArg); + // if not or PassTouchs, send it also to root. + if (((part.ScriptEvents & scriptEvents.touch_end) == 0) || + (part.PassTouches && (part.LocalId != grp.RootPart.LocalId))) + { + EventManager.TriggerObjectDeGrab(grp.RootPart.LocalId, part.LocalId, remoteClient, surfaceArg); + } + } + + /// + /// Start spinning the given object + /// + /// + /// + /// + public virtual void ProcessSpinStart(UUID objectID, IClientAPI remoteClient) + { + SceneObjectGroup group = GetGroupByPrim(objectID); + if (group != null) + { + if (Permissions.CanMoveObject(group, remoteClient))// && PermissionsMngr.) + { + group.SpinStart(remoteClient); + } + } + } + + /// + /// Spin the given object + /// + /// + /// + /// + public virtual void ProcessSpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient) + { + SceneObjectGroup group = GetGroupByPrim(objectID); + if (group != null) + { + if (Permissions.CanMoveObject(group, remoteClient))// && PermissionsMngr.) + { + group.SpinMovement(rotation, remoteClient); + } + // This is outside the above permissions condition + // so that if the object is locked the client moving the object + // get's it's position on the simulator even if it was the same as before + // This keeps the moving user's client in sync with the rest of the world. + group.SendGroupTerseUpdate(); + } + } + + public virtual void ProcessSpinObjectStop(UUID objectID, IClientAPI remoteClient) + { +/* no op for now + SceneObjectGroup group = GetGroupByPrim(objectID); + if (group != null) + { + if (Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.) + { +// group.SpinMovement(rotation, remoteClient); + } + group.SendGroupTerseUpdate(); + } +*/ } public void ProcessScriptReset(IClientAPI remoteClient, UUID objectID, @@ -439,6 +493,20 @@ namespace OpenSim.Region.Framework.Scenes return Vector3.Distance(other.CameraPosition, thisClient.SceneAgent.AbsolutePosition) < 10; } + private class DescendentsRequestData + { + public IClientAPI RemoteClient; + public UUID FolderID; + public UUID OwnerID; + public bool FetchFolders; + public bool FetchItems; + public int SortOrder; + } + + private Queue m_descendentsRequestQueue = new Queue(); + private Object m_descendentsRequestLock = new Object(); + private bool m_descendentsRequestProcessing = false; + /// /// Tell the client about the various child items and folders contained in the requested folder. /// @@ -475,11 +543,31 @@ namespace OpenSim.Region.Framework.Scenes } } - // We're going to send the reply async, because there may be - // an enormous quantity of packets -- basically the entire inventory! - // We don't want to block the client thread while all that is happening. - SendInventoryDelegate d = SendInventoryAsync; - d.BeginInvoke(remoteClient, folderID, ownerID, fetchFolders, fetchItems, sortOrder, SendInventoryComplete, d); + lock (m_descendentsRequestLock) + { + if (!m_descendentsRequestProcessing) + { + m_descendentsRequestProcessing = true; + + // We're going to send the reply async, because there may be + // an enormous quantity of packets -- basically the entire inventory! + // We don't want to block the client thread while all that is happening. + SendInventoryDelegate d = SendInventoryAsync; + d.BeginInvoke(remoteClient, folderID, ownerID, fetchFolders, fetchItems, sortOrder, SendInventoryComplete, d); + + return; + } + + DescendentsRequestData req = new DescendentsRequestData(); + req.RemoteClient = remoteClient; + req.FolderID = folderID; + req.OwnerID = ownerID; + req.FetchFolders = fetchFolders; + req.FetchItems = fetchItems; + req.SortOrder = sortOrder; + + m_descendentsRequestQueue.Enqueue(req); + } } delegate void SendInventoryDelegate(IClientAPI remoteClient, UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems, int sortOrder); @@ -494,16 +582,32 @@ namespace OpenSim.Region.Framework.Scenes { m_log.Error( string.Format( - "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e)); + "[AGENT INVENTORY]: Error in SendInventoryAsync() for {0} with folder ID {1}. Exception ", e, folderID)); } + Thread.Sleep(20); } void SendInventoryComplete(IAsyncResult iar) { SendInventoryDelegate d = (SendInventoryDelegate)iar.AsyncState; d.EndInvoke(iar); + + lock (m_descendentsRequestLock) + { + if (m_descendentsRequestQueue.Count > 0) + { + DescendentsRequestData req = m_descendentsRequestQueue.Dequeue(); + + d = SendInventoryAsync; + d.BeginInvoke(req.RemoteClient, req.FolderID, req.OwnerID, req.FetchFolders, req.FetchItems, req.SortOrder, SendInventoryComplete, d); + + return; + } + + m_descendentsRequestProcessing = false; + } } - + /// /// Handle an inventory folder creation request from the client. /// @@ -543,8 +647,7 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[AGENT INVENTORY]: Updating inventory folder {0} {1} for {2} {3}", folderID, name, remoteClient.Name, remoteClient.AgentId); - InventoryFolderBase folder = new InventoryFolderBase(folderID, remoteClient.AgentId); - folder = InventoryService.GetFolder(folder); + InventoryFolderBase folder = InventoryService.GetFolder(remoteClient.AgentId, folderID); if (folder != null) { folder.Name = name; @@ -558,11 +661,10 @@ namespace OpenSim.Region.Framework.Scenes } } } - + public void HandleMoveInventoryFolder(IClientAPI remoteClient, UUID folderID, UUID parentID) { - InventoryFolderBase folder = new InventoryFolderBase(folderID, remoteClient.AgentId); - folder = InventoryService.GetFolder(folder); + InventoryFolderBase folder = InventoryService.GetFolder(remoteClient.AgentId, folderID); if (folder != null) { folder.ParentID = parentID; @@ -601,10 +703,17 @@ namespace OpenSim.Region.Framework.Scenes { InventoryFolderBase folder = new InventoryFolderBase(folderID, userID); - if (InventoryService.PurgeFolder(folder)) - m_log.DebugFormat("[AGENT INVENTORY]: folder {0} purged successfully", folderID); - else - m_log.WarnFormat("[AGENT INVENTORY]: could not purge folder {0}", folderID); + try + { + if (InventoryService.PurgeFolder(folder)) + m_log.DebugFormat("[AGENT INVENTORY]: folder {0} purged successfully", folderID); + else + m_log.WarnFormat("[AGENT INVENTORY]: could not purge folder {0}", folderID); + } + catch (Exception e) + { + m_log.WarnFormat("[AGENT INVENTORY]: Exception on async purge folder for user {0}: {1}", userID, e.Message); + } } private void PurgeFolderCompleted(IAsyncResult iar) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs index 535d87a..a75671e 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs @@ -35,52 +35,63 @@ using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; namespace OpenSim.Region.Framework.Scenes -{ +{ #region Delegates - public delegate uint GenerateClientFlagsHandler(UUID userID, UUID objectID); + public delegate uint GenerateClientFlagsHandler(SceneObjectPart part, ScenePresence sp, uint curEffectivePerms); public delegate void SetBypassPermissionsHandler(bool value); public delegate bool BypassPermissionsHandler(); public delegate bool PropagatePermissionsHandler(); - public delegate bool RezObjectHandler(int objectCount, UUID owner, Vector3 objectPosition, Scene scene); - public delegate bool DeleteObjectHandler(UUID objectID, UUID deleter, Scene scene); - public delegate bool TransferObjectHandler(UUID objectID, UUID recipient, Scene scene); - public delegate bool TakeObjectHandler(UUID objectID, UUID stealer, Scene scene); - public delegate bool TakeCopyObjectHandler(UUID objectID, UUID userID, Scene inScene); - public delegate bool DuplicateObjectHandler(int objectCount, UUID objectID, UUID owner, Scene scene, Vector3 objectPosition); - public delegate bool EditObjectHandler(UUID objectID, UUID editorID, Scene scene); - public delegate bool EditObjectInventoryHandler(UUID objectID, UUID editorID, Scene scene); - public delegate bool MoveObjectHandler(UUID objectID, UUID moverID, Scene scene); - public delegate bool ObjectEntryHandler(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene); - public delegate bool ReturnObjectsHandler(ILandObject land, UUID user, List objects, Scene scene); - public delegate bool InstantMessageHandler(UUID user, UUID target, Scene startScene); - public delegate bool InventoryTransferHandler(UUID user, UUID target, Scene startScene); - public delegate bool ViewScriptHandler(UUID script, UUID objectID, UUID user, Scene scene); - public delegate bool ViewNotecardHandler(UUID script, UUID objectID, UUID user, Scene scene); - public delegate bool EditScriptHandler(UUID script, UUID objectID, UUID user, Scene scene); - public delegate bool EditNotecardHandler(UUID notecard, UUID objectID, UUID user, Scene scene); - public delegate bool RunScriptHandler(UUID script, UUID objectID, UUID user, Scene scene); - public delegate bool CompileScriptHandler(UUID ownerUUID, int scriptType, Scene scene); - public delegate bool StartScriptHandler(UUID script, UUID user, Scene scene); - public delegate bool StopScriptHandler(UUID script, UUID user, Scene scene); - public delegate bool ResetScriptHandler(UUID prim, UUID script, UUID user, Scene scene); - public delegate bool TerraformLandHandler(UUID user, Vector3 position, Scene requestFromScene); - public delegate bool RunConsoleCommandHandler(UUID user, Scene requestFromScene); - public delegate bool IssueEstateCommandHandler(UUID user, Scene requestFromScene, bool ownerCommand); - public delegate bool IsGodHandler(UUID user, Scene requestFromScene); - public delegate bool IsGridGodHandler(UUID user, Scene requestFromScene); + public delegate bool RezObjectHandler(int objectCount, UUID owner, Vector3 objectPosition); + public delegate bool DeleteObjectHandlerByIDs(UUID objectID, UUID deleter); + public delegate bool DeleteObjectHandler(SceneObjectGroup sog, ScenePresence sp); + public delegate bool TransferObjectHandler(UUID objectID, UUID recipient); + public delegate bool TakeObjectHandler(SceneObjectGroup sog, ScenePresence sp); + public delegate bool SellGroupObjectHandler(UUID userID, UUID groupID); + public delegate bool SellObjectHandlerByUserID(SceneObjectGroup sog, UUID userID, byte saleType); + public delegate bool SellObjectHandler(SceneObjectGroup sog, ScenePresence sp, byte saleType); + public delegate bool TakeCopyObjectHandler(SceneObjectGroup sog, ScenePresence sp); + public delegate bool DuplicateObjectHandler(SceneObjectGroup sog, ScenePresence sp); + public delegate bool EditObjectByIDsHandler(UUID objectID, UUID editorID); + public delegate bool EditObjectHandler(SceneObjectGroup sog, ScenePresence sp); + public delegate bool EditObjectPermsHandler(SceneObjectGroup sog, UUID editorID); + public delegate bool EditObjectInventoryHandler(UUID objectID, UUID editorID); + public delegate bool MoveObjectHandler(SceneObjectGroup sog, ScenePresence sp); + public delegate bool ObjectEntryHandler(SceneObjectGroup sog, bool enteringRegion, Vector3 newPoint); + public delegate bool ObjectEnterWithScriptsHandler(SceneObjectGroup sog, ILandObject land); + public delegate bool ReturnObjectsHandler(ILandObject land, ScenePresence sp, List objects); + public delegate bool InstantMessageHandler(UUID user, UUID target); + public delegate bool InventoryTransferHandler(UUID user, UUID target); + public delegate bool ViewScriptHandler(UUID script, UUID objectID, UUID user); + public delegate bool ViewNotecardHandler(UUID script, UUID objectID, UUID user); + public delegate bool EditScriptHandler(UUID script, UUID objectID, UUID user); + public delegate bool EditNotecardHandler(UUID notecard, UUID objectID, UUID user); + public delegate bool RunScriptHandlerByIDs(UUID script, UUID objectID, UUID user); + public delegate bool RunScriptHandler(TaskInventoryItem item, SceneObjectPart part); + public delegate bool CompileScriptHandler(UUID ownerUUID, int scriptType); + public delegate bool StartScriptHandler(UUID script, UUID user); + public delegate bool StopScriptHandler(UUID script, UUID user); + public delegate bool ResetScriptHandler(UUID prim, UUID script, UUID user); + public delegate bool TerraformLandHandler(UUID user, Vector3 position); + public delegate bool RunConsoleCommandHandler(UUID user); + public delegate bool IssueEstateCommandHandler(UUID user, bool ownerCommand); + public delegate bool IsGodHandler(UUID user); + public delegate bool IsGridGodHandler(UUID user); public delegate bool IsAdministratorHandler(UUID user); - public delegate bool EditParcelHandler(UUID user, ILandObject parcel, Scene scene); - public delegate bool EditParcelPropertiesHandler(UUID user, ILandObject parcel, GroupPowers p, Scene scene); - public delegate bool SellParcelHandler(UUID user, ILandObject parcel, Scene scene); - public delegate bool AbandonParcelHandler(UUID user, ILandObject parcel, Scene scene); - public delegate bool ReclaimParcelHandler(UUID user, ILandObject parcel, Scene scene); - public delegate bool DeedParcelHandler(UUID user, ILandObject parcel, Scene scene); - public delegate bool DeedObjectHandler(UUID user, UUID group, Scene scene); - public delegate bool BuyLandHandler(UUID user, ILandObject parcel, Scene scene); + public delegate bool IsEstateManagerHandler(UUID user); + public delegate bool EditParcelHandler(UUID user, ILandObject parcel); + public delegate bool EditParcelPropertiesHandler(UUID user, ILandObject parcel, GroupPowers p, bool allowManager); + public delegate bool SellParcelHandler(UUID user, ILandObject parcel); + public delegate bool AbandonParcelHandler(UUID user, ILandObject parcel); + public delegate bool ReclaimParcelHandler(UUID user, ILandObject parcel); + public delegate bool DeedParcelHandler(UUID user, ILandObject parcel); + public delegate bool DeedObjectHandler(ScenePresence sp, SceneObjectGroup sog, UUID targetGroupID); + public delegate bool BuyLandHandler(UUID user, ILandObject parcel); public delegate bool LinkObjectHandler(UUID user, UUID objectID); public delegate bool DelinkObjectHandler(UUID user, UUID objectID); public delegate bool CreateObjectInventoryHandler(int invType, UUID objectID, UUID userID); public delegate bool CopyObjectInventoryHandler(UUID itemID, UUID objectID, UUID userID); + public delegate bool DoObjectInvToObjectInv(TaskInventoryItem item, SceneObjectPart sourcePart, SceneObjectPart destPart); + public delegate bool DoDropInObjectInv(InventoryItemBase item, ScenePresence sp, SceneObjectPart destPart); public delegate bool DeleteObjectInventoryHandler(UUID itemID, UUID objectID, UUID userID); public delegate bool TransferObjectInventoryHandler(UUID itemID, UUID objectID, UUID userID); public delegate bool CreateUserInventoryHandler(int invType, UUID userID); @@ -96,7 +107,7 @@ namespace OpenSim.Region.Framework.Scenes public class ScenePermissions { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private Scene m_scene; public ScenePermissions(Scene scene) @@ -110,15 +121,24 @@ namespace OpenSim.Region.Framework.Scenes public event BypassPermissionsHandler OnBypassPermissions; public event PropagatePermissionsHandler OnPropagatePermissions; public event RezObjectHandler OnRezObject; + public event DeleteObjectHandlerByIDs OnDeleteObjectByIDs; public event DeleteObjectHandler OnDeleteObject; public event TransferObjectHandler OnTransferObject; public event TakeObjectHandler OnTakeObject; + + public event SellGroupObjectHandler OnSellGroupObject; + public event SellObjectHandlerByUserID OnSellObjectByUserID; + public event SellObjectHandler OnSellObject; + public event TakeCopyObjectHandler OnTakeCopyObject; public event DuplicateObjectHandler OnDuplicateObject; + public event EditObjectByIDsHandler OnEditObjectByIDs; public event EditObjectHandler OnEditObject; + public event EditObjectPermsHandler OnEditObjectPerms; public event EditObjectInventoryHandler OnEditObjectInventory; public event MoveObjectHandler OnMoveObject; public event ObjectEntryHandler OnObjectEntry; + public event ObjectEnterWithScriptsHandler OnObjectEnterWithScripts; public event ReturnObjectsHandler OnReturnObjects; public event InstantMessageHandler OnInstantMessage; public event InventoryTransferHandler OnInventoryTransfer; @@ -126,6 +146,7 @@ namespace OpenSim.Region.Framework.Scenes public event ViewNotecardHandler OnViewNotecard; public event EditScriptHandler OnEditScript; public event EditNotecardHandler OnEditNotecard; + public event RunScriptHandlerByIDs OnRunScriptByIDs; public event RunScriptHandler OnRunScript; public event CompileScriptHandler OnCompileScript; public event StartScriptHandler OnStartScript; @@ -134,9 +155,9 @@ namespace OpenSim.Region.Framework.Scenes public event TerraformLandHandler OnTerraformLand; public event RunConsoleCommandHandler OnRunConsoleCommand; public event IssueEstateCommandHandler OnIssueEstateCommand; - public event IsGodHandler OnIsGod; public event IsGridGodHandler OnIsGridGod; public event IsAdministratorHandler OnIsAdministrator; + public event IsEstateManagerHandler OnIsEstateManager; // public event EditParcelHandler OnEditParcel; public event EditParcelPropertiesHandler OnEditParcelProperties; public event SellParcelHandler OnSellParcel; @@ -149,6 +170,8 @@ namespace OpenSim.Region.Framework.Scenes public event DelinkObjectHandler OnDelinkObject; public event CreateObjectInventoryHandler OnCreateObjectInventory; public event CopyObjectInventoryHandler OnCopyObjectInventory; + public event DoObjectInvToObjectInv OnDoObjectInvToObjectInv; + public event DoDropInObjectInv OnDropInObjectInv; public event DeleteObjectInventoryHandler OnDeleteObjectInventory; public event TransferObjectInventoryHandler OnTransferObjectInventory; public event CreateUserInventoryHandler OnCreateUserInventory; @@ -163,7 +186,7 @@ namespace OpenSim.Region.Framework.Scenes #region Object Permission Checks - public uint GenerateClientFlags(UUID userID, UUID objectID) + public uint GenerateClientFlags( SceneObjectPart part, ScenePresence sp) { // libomv will moan about PrimFlags.ObjectYouOfficer being // obsolete... @@ -175,12 +198,9 @@ namespace OpenSim.Region.Framework.Scenes PrimFlags.ObjectTransfer | PrimFlags.ObjectYouOwner | PrimFlags.ObjectAnyOwner | - PrimFlags.ObjectOwnerModify | - PrimFlags.ObjectYouOfficer; + PrimFlags.ObjectOwnerModify; #pragma warning restore 0612 - SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); - if (part == null) return 0; @@ -192,7 +212,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handlerGenerateClientFlags.GetInvocationList(); foreach (GenerateClientFlagsHandler check in list) { - perms &= check(userID, objectID); + perms &= check(part, sp, perms); } } return perms; @@ -244,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (RezObjectHandler h in list) { - if (h(objectCount, owner,objectPosition, m_scene) == false) + if (h(objectCount, owner,objectPosition) == false) return false; } } @@ -257,113 +277,184 @@ namespace OpenSim.Region.Framework.Scenes public bool CanDeleteObject(UUID objectID, UUID deleter) { bool result = true; - - DeleteObjectHandler handler = OnDeleteObject; + + DeleteObjectHandlerByIDs handler = OnDeleteObjectByIDs; if (handler != null) { Delegate[] list = handler.GetInvocationList(); - foreach (DeleteObjectHandler h in list) + foreach (DeleteObjectHandlerByIDs h in list) { - if (h(objectID, deleter, m_scene) == false) + if (h(objectID, deleter) == false) { result = false; break; } } } - return result; } + public bool CanDeleteObject(SceneObjectGroup sog, IClientAPI client) + { + DeleteObjectHandler handler = OnDeleteObject; + if (handler != null) + { + if(sog == null || client == null || client.SceneAgent == null) + return false; + + ScenePresence sp = client.SceneAgent as ScenePresence; + + Delegate[] list = handler.GetInvocationList(); + foreach (DeleteObjectHandler h in list) + { + if (h(sog, sp) == false) + return false; + } + } + + return true; + } + public bool CanTransferObject(UUID objectID, UUID recipient) { - bool result = true; - TransferObjectHandler handler = OnTransferObject; if (handler != null) { Delegate[] list = handler.GetInvocationList(); foreach (TransferObjectHandler h in list) { - if (h(objectID, recipient, m_scene) == false) - { - result = false; - break; - } + if (h(objectID, recipient) == false) + return false; } } - - return result; + return true; } #endregion #region TAKE OBJECT - public bool CanTakeObject(UUID objectID, UUID AvatarTakingUUID) + public bool CanTakeObject(SceneObjectGroup sog, ScenePresence sp) { - bool result = true; - TakeObjectHandler handler = OnTakeObject; if (handler != null) { + if(sog == null || sp == null) + return false; + Delegate[] list = handler.GetInvocationList(); foreach (TakeObjectHandler h in list) { - if (h(objectID, AvatarTakingUUID, m_scene) == false) - { - result = false; - break; - } + if (h(sog, sp) == false) + return false; } } - // m_log.DebugFormat( -// "[SCENE PERMISSIONS]: CanTakeObject() fired for object {0}, taker {1}, result {2}", +// "[SCENE PERMISSIONS]: CanTakeObject() fired for object {0}, taker {1}, result {2}", // objectID, AvatarTakingUUID, result); - - return result; + return true; } #endregion + #region SELL GROUP OBJECT + public bool CanSellGroupObject(UUID userID, UUID groupID) + { + SellGroupObjectHandler handler = OnSellGroupObject; + if (handler != null) + { + Delegate[] list = handler.GetInvocationList(); + foreach (SellGroupObjectHandler h in list) + { + if (h(userID, groupID) == false) + return false; + } + } + //m_log.DebugFormat( + // "[SCENE PERMISSIONS]: CanSellGroupObject() fired for user {0}, group {1}, result {2}", + // userID, groupID, result); + return true; + } + + #endregion + + #region SELL OBJECT + public bool CanSellObject(IClientAPI client, SceneObjectGroup sog, byte saleType) + { + SellObjectHandler handler = OnSellObject; + if (handler != null) + { + if(sog == null || client == null || client.SceneAgent == null) + return false; + + ScenePresence sp = client.SceneAgent as ScenePresence; + Delegate[] list = handler.GetInvocationList(); + foreach (SellObjectHandler h in list) + { + if (h(sog, sp, saleType) == false) + return false; + } + } + return true; + } + + public bool CanSellObject(UUID userID, SceneObjectGroup sog, byte saleType) + { + SellObjectHandlerByUserID handler = OnSellObjectByUserID; + if (handler != null) + { + if(sog == null) + return false; + Delegate[] list = handler.GetInvocationList(); + foreach (SellObjectHandlerByUserID h in list) + { + if (h(sog, userID, saleType) == false) + return false; + } + } + return true; + } + + #endregion + + #region TAKE COPY OBJECT - public bool CanTakeCopyObject(UUID objectID, UUID userID) + public bool CanTakeCopyObject(SceneObjectGroup sog, ScenePresence sp) { - bool result = true; - TakeCopyObjectHandler handler = OnTakeCopyObject; if (handler != null) { + if(sog == null || sp == null) + return false; Delegate[] list = handler.GetInvocationList(); foreach (TakeCopyObjectHandler h in list) { - if (h(objectID, userID, m_scene) == false) - { - result = false; - break; - } + if (h(sog, sp) == false) + return false; } } - // m_log.DebugFormat( -// "[SCENE PERMISSIONS]: CanTakeCopyObject() fired for object {0}, user {1}, result {2}", +// "[SCENE PERMISSIONS]: CanTakeCopyObject() fired for object {0}, user {1}, result {2}", // objectID, userID, result); - - return result; + return true; } #endregion #region DUPLICATE OBJECT - public bool CanDuplicateObject(int objectCount, UUID objectID, UUID owner, Vector3 objectPosition) + public bool CanDuplicateObject(SceneObjectGroup sog, UUID agentID) { DuplicateObjectHandler handler = OnDuplicateObject; if (handler != null) { + if(sog == null || sog.IsDeleted) + return false; + ScenePresence sp = m_scene.GetScenePresence(agentID); + if(sp == null || sp.IsDeleted) + return false; Delegate[] list = handler.GetInvocationList(); foreach (DuplicateObjectHandler h in list) { - if (h(objectCount, objectID, owner, m_scene, objectPosition) == false) + if (h(sog, sp) == false) return false; } } @@ -372,22 +463,74 @@ namespace OpenSim.Region.Framework.Scenes #endregion + #region persence EDIT or MOVE OBJECT + private const uint CANSELECTMASK = (uint)( + PrimFlags.ObjectMove | + PrimFlags.ObjectModify | + PrimFlags.ObjectOwnerModify + ); + + public bool CanChangeSelectedState(SceneObjectPart part, ScenePresence sp) + { + uint perms = GenerateClientFlags(part, sp); + return (perms & CANSELECTMASK) != 0; + } + + #endregion #region EDIT OBJECT public bool CanEditObject(UUID objectID, UUID editorID) { + EditObjectByIDsHandler handler = OnEditObjectByIDs; + if (handler != null) + { + Delegate[] list = handler.GetInvocationList(); + foreach (EditObjectByIDsHandler h in list) + { + if (h(objectID, editorID) == false) + return false; + } + } + return true; + } + + public bool CanEditObject(SceneObjectGroup sog, IClientAPI client) + { EditObjectHandler handler = OnEditObject; if (handler != null) { + if(sog == null || client == null || client.SceneAgent == null) + return false; + + ScenePresence sp = client.SceneAgent as ScenePresence; + Delegate[] list = handler.GetInvocationList(); foreach (EditObjectHandler h in list) { - if (h(objectID, editorID, m_scene) == false) + if (h(sog, sp) == false) + return false; + } + } + return true; + } + + public bool CanEditObjectPermissions(SceneObjectGroup sog, UUID editorID) + { + EditObjectPermsHandler handler = OnEditObjectPerms; + if (handler != null) + { + if(sog == null) + return false; + Delegate[] list = handler.GetInvocationList(); + foreach (EditObjectPermsHandler h in list) + { + if (h(sog, editorID) == false) return false; } } return true; } + public bool CanEditObjectInventory(UUID objectID, UUID editorID) { EditObjectInventoryHandler handler = OnEditObjectInventory; @@ -396,7 +539,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (EditObjectInventoryHandler h in list) { - if (h(objectID, editorID, m_scene) == false) + if (h(objectID, editorID) == false) return false; } } @@ -406,15 +549,20 @@ namespace OpenSim.Region.Framework.Scenes #endregion #region MOVE OBJECT - public bool CanMoveObject(UUID objectID, UUID moverID) + public bool CanMoveObject(SceneObjectGroup sog, IClientAPI client) { MoveObjectHandler handler = OnMoveObject; if (handler != null) { + if(sog == null || client == null || client.SceneAgent == null) + return false; + + ScenePresence sp = client.SceneAgent as ScenePresence; + Delegate[] list = handler.GetInvocationList(); foreach (MoveObjectHandler h in list) { - if (h(objectID, moverID, m_scene) == false) + if (h(sog, sp) == false) return false; } } @@ -424,7 +572,7 @@ namespace OpenSim.Region.Framework.Scenes #endregion #region OBJECT ENTRY - public bool CanObjectEntry(UUID objectID, bool enteringRegion, Vector3 newPoint) + public bool CanObjectEntry(SceneObjectGroup sog, bool enteringRegion, Vector3 newPoint) { ObjectEntryHandler handler = OnObjectEntry; if (handler != null) @@ -432,7 +580,22 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (ObjectEntryHandler h in list) { - if (h(objectID, enteringRegion, newPoint, m_scene) == false) + if (h(sog, enteringRegion, newPoint) == false) + return false; + } + } + return true; + } + + public bool CanObjectEnterWithScripts(SceneObjectGroup sog, ILandObject land) + { + ObjectEnterWithScriptsHandler handler = OnObjectEnterWithScripts; + if (handler != null) + { + Delegate[] list = handler.GetInvocationList(); + foreach (ObjectEnterWithScriptsHandler h in list) + { + if (h(sog, land) == false) return false; } } @@ -442,29 +605,30 @@ namespace OpenSim.Region.Framework.Scenes #endregion #region RETURN OBJECT - public bool CanReturnObjects(ILandObject land, UUID user, List objects) + public bool CanReturnObjects(ILandObject land, IClientAPI client, List objects) { - bool result = true; - ReturnObjectsHandler handler = OnReturnObjects; if (handler != null) { + if(objects == null) + return false; + + ScenePresence sp = null; + if(client != null && client.SceneAgent != null) + sp = client.SceneAgent as ScenePresence; + Delegate[] list = handler.GetInvocationList(); foreach (ReturnObjectsHandler h in list) { - if (h(land, user, objects, m_scene) == false) - { - result = false; - break; - } + if (h(land, sp, objects) == false) + return false; } } - // m_log.DebugFormat( -// "[SCENE PERMISSIONS]: CanReturnObjects() fired for user {0} for {1} objects on {2}, result {3}", +// "[SCENE PERMISSIONS]: CanReturnObjects() fired for user {0} for {1} objects on {2}, result {3}", // user, objects.Count, land.LandData.Name, result); - - return result; + + return true; } #endregion @@ -478,7 +642,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (InstantMessageHandler h in list) { - if (h(user, target, m_scene) == false) + if (h(user, target) == false) return false; } } @@ -496,7 +660,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (InventoryTransferHandler h in list) { - if (h(user, target, m_scene) == false) + if (h(user, target) == false) return false; } } @@ -514,7 +678,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (ViewScriptHandler h in list) { - if (h(script, objectID, user, m_scene) == false) + if (h(script, objectID, user) == false) return false; } } @@ -529,7 +693,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (ViewNotecardHandler h in list) { - if (h(script, objectID, user, m_scene) == false) + if (h(script, objectID, user) == false) return false; } } @@ -547,7 +711,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (EditScriptHandler h in list) { - if (h(script, objectID, user, m_scene) == false) + if (h(script, objectID, user) == false) return false; } } @@ -562,7 +726,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (EditNotecardHandler h in list) { - if (h(script, objectID, user, m_scene) == false) + if (h(script, objectID, user) == false) return false; } } @@ -574,19 +738,37 @@ namespace OpenSim.Region.Framework.Scenes #region RUN SCRIPT (When Script Placed in Object) public bool CanRunScript(UUID script, UUID objectID, UUID user) { + RunScriptHandlerByIDs handler = OnRunScriptByIDs; + if (handler != null) + { + Delegate[] list = handler.GetInvocationList(); + foreach (RunScriptHandlerByIDs h in list) + { + if (h(script, objectID, user) == false) + return false; + } + } + return true; + } + + public bool CanRunScript(TaskInventoryItem item, SceneObjectPart part) + { RunScriptHandler handler = OnRunScript; if (handler != null) { + if(item == null || part == null) + return false; Delegate[] list = handler.GetInvocationList(); foreach (RunScriptHandler h in list) { - if (h(script, objectID, user, m_scene) == false) + if (h(item, part) == false) return false; } } return true; } + #endregion #region COMPILE SCRIPT (When Script needs to get (re)compiled) @@ -598,7 +780,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (CompileScriptHandler h in list) { - if (h(ownerUUID, scriptType, m_scene) == false) + if (h(ownerUUID, scriptType) == false) return false; } } @@ -616,7 +798,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (StartScriptHandler h in list) { - if (h(script, user, m_scene) == false) + if (h(script, user) == false) return false; } } @@ -634,7 +816,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (StopScriptHandler h in list) { - if (h(script, user, m_scene) == false) + if (h(script, user) == false) return false; } } @@ -652,7 +834,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (ResetScriptHandler h in list) { - if (h(prim, script, user, m_scene) == false) + if (h(prim, script, user) == false) return false; } } @@ -670,7 +852,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (TerraformLandHandler h in list) { - if (h(user, pos, m_scene) == false) + if (h(user, pos) == false) return false; } } @@ -688,7 +870,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (RunConsoleCommandHandler h in list) { - if (h(user, m_scene) == false) + if (h(user) == false) return false; } } @@ -706,7 +888,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (IssueEstateCommandHandler h in list) { - if (h(user, m_scene, ownerCommand) == false) + if (h(user, ownerCommand) == false) return false; } } @@ -717,13 +899,13 @@ namespace OpenSim.Region.Framework.Scenes #region CAN BE GODLIKE public bool IsGod(UUID user) { - IsGodHandler handler = OnIsGod; + IsAdministratorHandler handler = OnIsAdministrator; if (handler != null) { Delegate[] list = handler.GetInvocationList(); - foreach (IsGodHandler h in list) + foreach (IsAdministratorHandler h in list) { - if (h(user, m_scene) == false) + if (h(user) == false) return false; } } @@ -738,7 +920,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (IsGridGodHandler h in list) { - if (h(user, m_scene) == false) + if (h(user) == false) return false; } } @@ -761,9 +943,24 @@ namespace OpenSim.Region.Framework.Scenes } #endregion + public bool IsEstateManager(UUID user) + { + IsEstateManagerHandler handler = OnIsEstateManager; + if (handler != null) + { + Delegate[] list = handler.GetInvocationList(); + foreach (IsEstateManagerHandler h in list) + { + if (h(user) == false) + return false; + } + } + return true; + } + #region EDIT PARCEL - public bool CanEditParcelProperties(UUID user, ILandObject parcel, GroupPowers p) + public bool CanEditParcelProperties(UUID user, ILandObject parcel, GroupPowers p, bool allowManager) { EditParcelPropertiesHandler handler = OnEditParcelProperties; if (handler != null) @@ -771,7 +968,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (EditParcelPropertiesHandler h in list) { - if (h(user, parcel, p, m_scene) == false) + if (h(user, parcel, p, allowManager) == false) return false; } } @@ -788,7 +985,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (SellParcelHandler h in list) { - if (h(user, parcel, m_scene) == false) + if (h(user, parcel) == false) return false; } } @@ -805,7 +1002,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (AbandonParcelHandler h in list) { - if (h(user, parcel, m_scene) == false) + if (h(user, parcel) == false) return false; } } @@ -821,7 +1018,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (ReclaimParcelHandler h in list) { - if (h(user, parcel, m_scene) == false) + if (h(user, parcel) == false) return false; } } @@ -836,22 +1033,27 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (DeedParcelHandler h in list) { - if (h(user, parcel, m_scene) == false) + if (h(user, parcel) == false) return false; } } return true; } - public bool CanDeedObject(UUID user, UUID group) + public bool CanDeedObject(IClientAPI client, SceneObjectGroup sog, UUID targetGroupID) { DeedObjectHandler handler = OnDeedObject; if (handler != null) { + if(sog == null || client == null || client.SceneAgent == null || targetGroupID == UUID.Zero) + return false; + + ScenePresence sp = client.SceneAgent as ScenePresence; + Delegate[] list = handler.GetInvocationList(); foreach (DeedObjectHandler h in list) { - if (h(user, group, m_scene) == false) + if (h(sp, sog, targetGroupID) == false) return false; } } @@ -866,7 +1068,7 @@ namespace OpenSim.Region.Framework.Scenes Delegate[] list = handler.GetInvocationList(); foreach (BuyLandHandler h in list) { - if (h(user, parcel, m_scene) == false) + if (h(user, parcel) == false) return false; } } @@ -942,6 +1144,45 @@ namespace OpenSim.Region.Framework.Scenes return true; } + public bool CanDoObjectInvToObjectInv(TaskInventoryItem item, SceneObjectPart sourcePart, SceneObjectPart destPart) + { + DoObjectInvToObjectInv handler = OnDoObjectInvToObjectInv; + if (handler != null) + { + if (sourcePart == null || destPart == null || item == null) + return false; + Delegate[] list = handler.GetInvocationList(); + foreach (DoObjectInvToObjectInv h in list) + { + if (h(item, sourcePart, destPart) == false) + return false; + } + } + return true; + } + + public bool CanDropInObjectInv(InventoryItemBase item, IClientAPI client, SceneObjectPart destPart) + { + DoDropInObjectInv handler = OnDropInObjectInv; + if (handler != null) + { + if (client == null || client.SceneAgent == null|| destPart == null || item == null) + return false; + + ScenePresence sp = client.SceneAgent as ScenePresence; + if(sp == null || sp.IsDeleted) + return false; + + Delegate[] list = handler.GetInvocationList(); + foreach (DoDropInObjectInv h in list) + { + if (h(item, sp, destPart) == false) + return false; + } + } + return true; + } + public bool CanDeleteObjectInventory(UUID itemID, UUID objectID, UUID userID) { DeleteObjectInventoryHandler handler = OnDeleteObjectInventory; @@ -956,7 +1197,7 @@ namespace OpenSim.Region.Framework.Scenes } return true; } - + public bool CanTransferObjectInventory(UUID itemID, UUID objectID, UUID userID) { TransferObjectInventoryHandler handler = OnTransferObjectInventory; @@ -971,7 +1212,7 @@ namespace OpenSim.Region.Framework.Scenes } return true; } - + /// /// Check whether the specified user is allowed to create the given inventory type in their inventory. /// @@ -991,8 +1232,8 @@ namespace OpenSim.Region.Framework.Scenes } } return true; - } - + } + /// /// Check whether the specified user is allowed to edit the given inventory item within their own inventory. /// @@ -1013,7 +1254,7 @@ namespace OpenSim.Region.Framework.Scenes } return true; } - + /// /// Check whether the specified user is allowed to copy the given inventory item from their own inventory. /// @@ -1034,7 +1275,7 @@ namespace OpenSim.Region.Framework.Scenes } return true; } - + /// /// Check whether the specified user is allowed to edit the given inventory item within their own inventory. /// @@ -1055,7 +1296,7 @@ namespace OpenSim.Region.Framework.Scenes } return true; } - + public bool CanTransferUserInventory(UUID itemID, UUID userID, UUID recipientID) { TransferUserInventoryHandler handler = OnTransferUserInventory; @@ -1070,7 +1311,7 @@ namespace OpenSim.Region.Framework.Scenes } return true; } - + public bool CanTeleport(UUID userID) { TeleportHandler handler = OnTeleport; @@ -1085,7 +1326,7 @@ namespace OpenSim.Region.Framework.Scenes } return true; } - + public bool CanControlPrimMedia(UUID userID, UUID primID, int face) { ControlPrimMediaHandler handler = OnControlPrimMedia; @@ -1099,8 +1340,8 @@ namespace OpenSim.Region.Framework.Scenes } } return true; - } - + } + public bool CanInteractWithPrimMedia(UUID userID, UUID primID, int face) { InteractWithPrimMediaHandler handler = OnInteractWithPrimMedia; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs old mode 100644 new mode 100755 index 2fe6e22..15a0493 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -61,15 +61,12 @@ namespace OpenSim.Region.Framework.Scenes { private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L; private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L; - - public const int m_defaultNumberFramesStored = 10; + public delegate void SynchronizeSceneHandler(Scene scene); #region Fields - public bool EmergencyMonitoring = false; - /// /// Show debug information about animations. /// @@ -91,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// Even if false, the scene will still be saved on clean shutdown. - /// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels. + /// FIXME: Currently, setting this to false will mean that objects are not periodically returned from parcels. /// This needs to be fixed. /// public bool PeriodicBackup { get; set; } @@ -105,6 +102,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// If false then physical objects are disabled, though collisions will continue as normal. /// + public bool PhysicsEnabled { get @@ -174,6 +172,13 @@ namespace OpenSim.Region.Framework.Scenes public SynchronizeSceneHandler SynchronizeScene; + public bool ClampNegativeZ + { + get { return m_clampNegativeZ; } + } + + private bool m_clampNegativeZ = false; + /// /// Used to prevent simultaneous calls to code that adds and removes agents. /// @@ -216,7 +221,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Maximum value of the size of a physical prim in each axis /// - public float m_maxPhys = 64; + public float m_maxPhys = 10; /// /// Max prims an object will hold @@ -228,57 +233,48 @@ namespace OpenSim.Region.Framework.Scenes public bool m_allowScriptCrossings = true; /// - /// Can avatars cross from and to this region? - /// - public bool AllowAvatarCrossing { get; set; } - - public bool m_useFlySlow; - public bool m_useTrashOnDelete = true; - - /// - /// Temporarily setting to trigger appearance resends at 60 second intervals. + /// use legacy sittarget offsets to avoid contents breaks + /// to compensate for SL bug /// - public bool SendPeriodicAppearanceUpdates { get; set; } + public bool LegacySitOffsets = true; /// - /// How much a root agent has to change position before updates are sent to viewers. - /// - public float RootPositionUpdateTolerance { get; set; } - - /// - /// How much a root agent has to rotate before updates are sent to viewers. + /// Can avatars cross from and to this region? /// - public float RootRotationUpdateTolerance { get; set; } + public bool AllowAvatarCrossing { get; set; } - /// - /// How much a root agent has to change velocity before updates are sent to viewers. + /// Max prims an Physical object will hold /// - public float RootVelocityUpdateTolerance { get; set; } + /// + public int m_linksetPhysCapacity = 0; /// - /// If greater than 1, we only send terse updates to other root agents on every n updates. + /// When placed outside the region's border, do we transfer the objects or + /// do we keep simulating them here? /// - public int RootTerseUpdatePeriod { get; set; } + public bool DisableObjectTransfer { get; set; } - /// - /// If greater than 1, we only send terse updates to child agents on every n updates. - /// - public int ChildTerseUpdatePeriod { get; set; } + public bool m_useFlySlow; + public bool m_useTrashOnDelete = true; - protected float m_defaultDrawDistance = 255.0f; + protected float m_defaultDrawDistance = 255f; + protected float m_defaultCullingDrawDistance = 16f; public float DefaultDrawDistance { - // get { return m_defaultDrawDistance; } - get - { - if (RegionInfo != null) - { - float largestDimension = Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY); - m_defaultDrawDistance = Math.Max(m_defaultDrawDistance, largestDimension); + get { return ObjectsCullingByDistance?m_defaultCullingDrawDistance:m_defaultDrawDistance; } + } - } - return m_defaultDrawDistance; - } + protected float m_maxDrawDistance = 512.0f; +// protected float m_maxDrawDistance = 256.0f; + public float MaxDrawDistance + { + get { return m_maxDrawDistance; } + } + + protected float m_maxRegionViewDistance = 255f; + public float MaxRegionViewDistance + { + get { return m_maxRegionViewDistance; } } private List m_AllowedViewers = new List(); @@ -287,8 +283,8 @@ namespace OpenSim.Region.Framework.Scenes // TODO: need to figure out how allow client agents but deny // root agents when ACL denies access to root agent public bool m_strictAccessControl = true; - - public int MaxUndoCount { get; set; } + public bool m_seeIntoBannedRegion = false; + public int MaxUndoCount = 5; public bool SeeIntoRegion { get; set; } @@ -306,11 +302,13 @@ namespace OpenSim.Region.Framework.Scenes protected int m_splitRegionID; protected Timer m_restartWaitTimer = new Timer(); + protected Timer m_timerWatchdog = new Timer(); protected List m_regionRestartNotifyList = new List(); protected List m_neighbours = new List(); protected string m_simulatorVersion = "OpenSimulator Server"; protected AgentCircuitManager m_authenticateHandler; protected SceneCommunicationService m_sceneGridService; + protected ISnmpModule m_snmpService = null; protected ISimulationDataService m_SimulationDataService; protected IEstateDataService m_EstateDataService; @@ -339,17 +337,6 @@ namespace OpenSim.Region.Framework.Scenes private Dictionary m_extraSettings; /// - /// If true then the next time the scene loop is activated, updates will be performed by firing of a timer - /// rather than on a single thread that sleeps. - /// - public bool UpdateOnTimer { get; set; } - - /// - /// Only used if we are updating scene on a timer rather than sleeping a thread. - /// - private Timer m_sceneUpdateTimer; - - /// /// Current scene frame number /// public uint Frame @@ -359,87 +346,38 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Current maintenance run number - /// - public uint MaintenanceRun { get; private set; } - - /// - /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we - /// will sleep for the remaining period. - /// - /// - /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations - /// occur too quickly (viewer 1) or with even more slide (viewer 2). + /// Frame time /// - public int MinFrameTicks - { - get { return m_minFrameTicks; } - private set - { - m_minFrameTicks = value; - MinFrameSeconds = (float)m_minFrameTicks / 1000; - } - } - private int m_minFrameTicks; - - public int FrameTimeWarnPercent { get; private set; } - public int FrameTimeCritPercent { get; private set; } + public float FrameTime { get; private set; } + public int FrameTimeWarnPercent { get; private set; } + public int FrameTimeCritPercent { get; private set; } // Normalize the frame related stats to nominal 55fps for viewer and scripts option // see SimStatsReporter.cs public bool Normalized55FPS { get; private set; } - /// - /// The minimum length of time in seconds that will be taken for a scene frame. - /// - /// - /// Always derived from MinFrameTicks. - /// - public float MinFrameSeconds { get; private set; } - - /// - /// The minimum length of time in milliseconds that will be taken for a scene frame. If the frame takes less time then we - /// will sleep for the remaining period. - /// - /// - /// One can tweak this number to experiment. One current effect of reducing it is to make avatar animations - /// occur too quickly (viewer 1) or with even more slide (viewer 2). - /// - public int MinMaintenanceTicks { get; set; } - private int m_update_physics = 1; private int m_update_entitymovement = 1; private int m_update_objects = 1; private int m_update_presences = 1; // Update scene presence movements private int m_update_events = 1; private int m_update_backup = 200; - private int m_update_terrain = 50; - // private int m_update_land = 1; - private int m_update_coarse_locations = 50; + + private int m_update_terrain = 1000; + + private int m_update_coarse_locations = 5; private int m_update_temp_cleaning = 180; - private int agentMS; - private int frameMS; - private int physicsMS2; - private int physicsMS; - private int otherMS; - private int tempOnRezMS; - private int eventMS; - private int backupMS; - private int terrainMS; - private int landMS; - private int spareMS; - - // A temporary configuration flag to enable using FireAndForget to process - // collisions from the physics engine. There is a problem with collisions - // stopping sometimes and MB's suspicion is some race condition passing - // collisions from the physics engine callback to the script engine. - // This causes the collision events to be passed with a FireAndForget - // call which should eliminate that linkage. Testers can turn this on - // and see if collisions stop. If they don't, the problem is somewhere else. - // This feature defaults to 'off' so, by default, the simulator operation - // is not changed. - public bool ShouldUseFireAndForgetForCollisions = false; + private float agentMS; + private float frameMS; + private float physicsMS2; + private float physicsMS; + private float otherMS; + private float tempOnRezMS; + private float eventMS; + private float backupMS; + private float terrainMS; + private float landMS; /// /// Tick at which the last frame was processed. @@ -447,11 +385,6 @@ namespace OpenSim.Region.Framework.Scenes private int m_lastFrameTick; /// - /// Tick at which the last maintenance run occurred. - /// - private int m_lastMaintenanceTick; - - /// /// Total script execution time (in Stopwatch Ticks) since the last frame /// private long m_scriptExecutionTime = 0; @@ -461,23 +394,19 @@ namespace OpenSim.Region.Framework.Scenes /// asynchronously from the update loop. /// private bool m_cleaningTemps = false; + private bool m_sendingCoarseLocations = false; // same for async course locations sending /// /// Used to control main scene thread looping time when not updating via timer. /// private ManualResetEvent m_updateWaitEvent = new ManualResetEvent(false); - /// - /// Used to control maintenance thread runs. - /// - private ManualResetEvent m_maintenanceWaitEvent = new ManualResetEvent(false); - // TODO: Possibly stop other classes being able to manipulate this directly. private SceneGraph m_sceneGraph; private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing private volatile bool m_backingup; private Dictionary m_returns = new Dictionary(); - private Dictionary m_groupsWithTargets = new Dictionary(); + private Dictionary m_groupsWithTargets = new Dictionary(); private string m_defaultScriptEngine; @@ -492,6 +421,11 @@ namespace OpenSim.Region.Framework.Scenes /// private int m_LastLogin; + private int m_lastIncoming; + private int m_lastOutgoing; + private int m_hbRestarts = 0; + + /// /// Thread that runs the scene loop. /// @@ -510,7 +444,7 @@ namespace OpenSim.Region.Framework.Scenes /// Is the scene active? /// /// - /// If false, maintenance and update loops are not being run, though after setting to false update may still + /// If false, update loop is not being run, though after setting to false update may still /// be active for a period (and IsRunning will still be true). Updates can still be triggered manually if /// the scene is not active. /// @@ -540,9 +474,21 @@ namespace OpenSim.Region.Framework.Scenes public bool IsRunning { get { return m_isRunning; } } private volatile bool m_isRunning; + private bool m_firstHeartbeat = true; + +// private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time; +// private bool m_reprioritizationEnabled = true; +// private double m_reprioritizationInterval = 5000.0; +// private double m_rootReprioritizationDistance = 10.0; +// private double m_childReprioritizationDistance = 20.0; + + private Timer m_mapGenerationTimer = new Timer(); private bool m_generateMaptiles; + protected int m_lastHealth = -1; + protected int m_lastUsers = -1; + #endregion Fields #region Properties @@ -571,6 +517,19 @@ namespace OpenSim.Region.Framework.Scenes get { return m_sceneGridService; } } + public ISnmpModule SnmpService + { + get + { + if (m_snmpService == null) + { + m_snmpService = RequestModuleInterface(); + } + + return m_snmpService; + } + } + public ISimulationDataService SimulationDataService { get @@ -777,22 +736,25 @@ namespace OpenSim.Region.Framework.Scenes get { return m_capsModule; } } - public int MonitorFrameTime { get { return frameMS; } } - public int MonitorPhysicsUpdateTime { get { return physicsMS; } } - public int MonitorPhysicsSyncTime { get { return physicsMS2; } } - public int MonitorOtherTime { get { return otherMS; } } - public int MonitorTempOnRezTime { get { return tempOnRezMS; } } - public int MonitorEventTime { get { return eventMS; } } // This may need to be divided into each event? - public int MonitorBackupTime { get { return backupMS; } } - public int MonitorTerrainTime { get { return terrainMS; } } - public int MonitorLandTime { get { return landMS; } } + public int MonitorFrameTime { get { return (int)frameMS; } } + public int MonitorPhysicsUpdateTime { get { return (int)physicsMS; } } + public int MonitorPhysicsSyncTime { get { return (int)physicsMS2; } } + public int MonitorOtherTime { get { return (int)otherMS; } } + public int MonitorTempOnRezTime { get { return (int)tempOnRezMS; } } + public int MonitorEventTime { get { return (int)eventMS; } } // This may need to be divided into each event? + public int MonitorBackupTime { get { return (int)backupMS; } } + public int MonitorTerrainTime { get { return (int)terrainMS; } } + public int MonitorLandTime { get { return (int)landMS; } } public int MonitorLastFrameTick { get { return m_lastFrameTick; } } public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get; set; } public bool IsReprioritizationEnabled { get; set; } - public double ReprioritizationInterval { get; set; } - public double RootReprioritizationDistance { get; set; } - public double ChildReprioritizationDistance { get; set; } + public float ReprioritizationInterval { get; set; } + public float ReprioritizationDistance { get; set; } + private float m_minReprioritizationDistance = 32f; + public bool ObjectsCullingByDistance = false; + + private ExpiringCache TeleportTargetsCoolDown = new ExpiringCache(); public AgentCircuitManager AuthenticateHandler { @@ -857,17 +819,16 @@ namespace OpenSim.Region.Framework.Scenes #region Constructors - public Scene(RegionInfo regInfo, AgentCircuitManager authen, + public Scene(RegionInfo regInfo, AgentCircuitManager authen, ISimulationDataService simDataService, IEstateDataService estateDataService, IConfigSource config, string simulatorVersion) : this(regInfo) { m_config = config; - MinFrameTicks = 89; + FrameTime = 0.0908f; FrameTimeWarnPercent = 60; FrameTimeCritPercent = 40; - Normalized55FPS = true; - MinMaintenanceTicks = 1000; + Normalized55FPS = true; SeeIntoRegion = true; Random random = new Random(); @@ -878,6 +839,9 @@ namespace OpenSim.Region.Framework.Scenes m_SimulationDataService = simDataService; m_EstateDataService = estateDataService; + m_lastIncoming = 0; + m_lastOutgoing = 0; + m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); m_asyncSceneObjectDeleter.Enabled = true; @@ -935,9 +899,9 @@ namespace OpenSim.Region.Framework.Scenes EventManager.OnLandObjectRemoved += new EventManager.LandObjectRemoved(simDataService.RemoveLandObject); - RegisterDefaultSceneEvents(); + RegisterDefaultSceneEvents(); - // XXX: Don't set the public property since we don't want to activate here. This needs to be handled + // XXX: Don't set the public property since we don't want to activate here. This needs to be handled // better in the future. m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts; @@ -956,6 +920,18 @@ namespace OpenSim.Region.Framework.Scenes StartDisabled = startupConfig.GetBoolean("StartDisabled", false); m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance", m_defaultDrawDistance); + m_maxDrawDistance = startupConfig.GetFloat("MaxDrawDistance", m_maxDrawDistance); + m_maxRegionViewDistance = startupConfig.GetFloat("MaxRegionsViewDistance", m_maxRegionViewDistance); + + // old versions compatibility + LegacySitOffsets = startupConfig.GetBoolean("LegacySitOffsets", LegacySitOffsets); + + if (m_defaultDrawDistance > m_maxDrawDistance) + m_defaultDrawDistance = m_maxDrawDistance; + + if (m_maxRegionViewDistance > m_maxDrawDistance) + m_maxRegionViewDistance = m_maxDrawDistance; + UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup); if (!UseBackup) m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName); @@ -967,9 +943,8 @@ namespace OpenSim.Region.Framework.Scenes MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20); - PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims); - CollidablePrims = startupConfig.GetBoolean("collidable_prim", CollidablePrims); - + PhysicalPrims = startupConfig.GetBoolean("physical_prim", true); + CollidablePrims = startupConfig.GetBoolean("collidable_prim", true); m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys); if (RegionInfo.NonphysPrimMin > 0) { @@ -989,11 +964,24 @@ namespace OpenSim.Region.Framework.Scenes } m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", m_maxPhys); + if (RegionInfo.PhysPrimMax > 0) { m_maxPhys = RegionInfo.PhysPrimMax; } + m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity); + if (RegionInfo.LinksetCapacity > 0) + { + m_linksetCapacity = RegionInfo.LinksetCapacity; + } + + m_linksetPhysCapacity = startupConfig.GetInt("LinksetPhysPrims", m_linksetPhysCapacity); + + + SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest"); + TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false); + // Here, if clamping is requested in either global or // local config, it will be used // @@ -1003,13 +991,9 @@ namespace OpenSim.Region.Framework.Scenes m_clampPrimSize = true; } - m_linksetCapacity = startupConfig.GetInt("LinksetPrims", m_linksetCapacity); - if (RegionInfo.LinksetCapacity > 0) - { - m_linksetCapacity = RegionInfo.LinksetCapacity; - } + m_clampNegativeZ = startupConfig.GetBoolean("ClampNegativeZ", m_clampNegativeZ); - m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete", m_useTrashOnDelete); + m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete); m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); m_dontPersistBefore = @@ -1020,11 +1004,10 @@ namespace OpenSim.Region.Framework.Scenes m_persistAfter *= 10000000; m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); - - SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest"); - TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false); + m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine); m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); + m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion); string[] possibleMapConfigSections = new string[] { "Map", "Startup" }; @@ -1070,7 +1053,7 @@ namespace OpenSim.Region.Framework.Scenes if (grant.Length > 0) { - foreach (string viewer in grant.Split('|')) + foreach (string viewer in grant.Split(',')) { m_AllowedViewers.Add(viewer.Trim().ToLower()); } @@ -1086,17 +1069,16 @@ namespace OpenSim.Region.Framework.Scenes if (grant.Length > 0) { - foreach (string viewer in grant.Split('|')) + foreach (string viewer in grant.Split(',')) { m_BannedViewers.Add(viewer.Trim().ToLower()); } } - if (startupConfig.Contains("MinFrameTime")) - MinFrameTicks = (int)(startupConfig.GetFloat("MinFrameTime") * 1000); + FrameTime = startupConfig.GetFloat( "FrameTime", FrameTime); FrameTimeWarnPercent = startupConfig.GetInt( "FrameTimeWarnPercent", FrameTimeWarnPercent); FrameTimeCritPercent = startupConfig.GetInt( "FrameTimeCritPercent", FrameTimeCritPercent); - Normalized55FPS = startupConfig.GetBoolean( "Normalized55FPS", Normalized55FPS); + Normalized55FPS = startupConfig.GetBoolean( "Normalized55FPS", Normalized55FPS); m_update_backup = startupConfig.GetInt("UpdateStorageEveryNFrames", m_update_backup); m_update_coarse_locations = startupConfig.GetInt("UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations); @@ -1108,21 +1090,6 @@ namespace OpenSim.Region.Framework.Scenes m_update_terrain = startupConfig.GetInt("UpdateTerrainEveryNFrames", m_update_terrain); m_update_temp_cleaning = startupConfig.GetInt("UpdateTempCleaningEveryNSeconds", m_update_temp_cleaning); - if (startupConfig.Contains("ShouldUseFireAndForgetForCollisions")) - { - ShouldUseFireAndForgetForCollisions = startupConfig.GetBoolean("ShouldUseFireAndForgetForCollisions", false); - } - } - - - // FIXME: Ultimately this should be in a module. - SendPeriodicAppearanceUpdates = false; - - IConfig appearanceConfig = m_config.Configs["Appearance"]; - if (appearanceConfig != null) - { - SendPeriodicAppearanceUpdates - = appearanceConfig.GetBoolean("ResendAppearanceUpdates", SendPeriodicAppearanceUpdates); } #endregion Region Config @@ -1131,6 +1098,7 @@ namespace OpenSim.Region.Framework.Scenes if (entityTransferConfig != null) { AllowAvatarCrossing = entityTransferConfig.GetBoolean("AllowAvatarCrossing", AllowAvatarCrossing); + DisableObjectTransfer = entityTransferConfig.GetBoolean("DisableObjectTransfer", false); } #region Interest Management @@ -1153,60 +1121,51 @@ namespace OpenSim.Region.Framework.Scenes IsReprioritizationEnabled = interestConfig.GetBoolean("ReprioritizationEnabled", IsReprioritizationEnabled); ReprioritizationInterval - = interestConfig.GetDouble("ReprioritizationInterval", ReprioritizationInterval); - RootReprioritizationDistance - = interestConfig.GetDouble("RootReprioritizationDistance", RootReprioritizationDistance); - ChildReprioritizationDistance - = interestConfig.GetDouble("ChildReprioritizationDistance", ChildReprioritizationDistance); + = interestConfig.GetFloat("ReprioritizationInterval", ReprioritizationInterval); + ReprioritizationDistance + = interestConfig.GetFloat("RootReprioritizationDistance", ReprioritizationDistance); - RootTerseUpdatePeriod = interestConfig.GetInt("RootTerseUpdatePeriod", RootTerseUpdatePeriod); - ChildTerseUpdatePeriod = interestConfig.GetInt("ChildTerseUpdatePeriod", ChildTerseUpdatePeriod); + if(ReprioritizationDistance < m_minReprioritizationDistance) + ReprioritizationDistance = m_minReprioritizationDistance; + + ObjectsCullingByDistance + = interestConfig.GetBoolean("ObjectsCullingByDistance", ObjectsCullingByDistance); - RootPositionUpdateTolerance - = interestConfig.GetFloat("RootPositionUpdateTolerance", RootPositionUpdateTolerance); - RootRotationUpdateTolerance - = interestConfig.GetFloat("RootRotationUpdateTolerance", RootRotationUpdateTolerance); - RootVelocityUpdateTolerance - = interestConfig.GetFloat("RootVelocityUpdateTolerance", RootVelocityUpdateTolerance); } m_log.DebugFormat("[SCENE]: Using the {0} prioritization scheme", UpdatePrioritizationScheme); #endregion Interest Management - // The timer used by the Stopwatch class depends on the system hardware and operating system; inform - // if the timer is based on a high-resolution performance counter or based on the system timer; - // the performance counter will provide a more precise time than the system timer - if (Stopwatch.IsHighResolution) - m_log.InfoFormat("[SCENE]: Using high-resolution performance counter for statistics."); - else - m_log.InfoFormat("[SCENE]: Using system timer for statistics."); + StatsReporter = new SimStatsReporter(this); - // Acquire the statistics section of the OpenSim.ini file located - // in the bin directory - IConfig statisticsConfig = m_config.Configs["Statistics"]; + StatsReporter.OnSendStatsResult += SendSimStatsPackets; + StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats; - // Confirm that the statistics section existed in the configuration - // file - if (statisticsConfig != null) - { - // Create the StatsReporter using the number of frames to store - // for the frame time statistics, or 10 frames if the config - // file doesn't contain a value - StatsReporter = new SimStatsReporter(this, - statisticsConfig.GetInt("NumberOfFrames", - m_defaultNumberFramesStored)); - } - else + IConfig restartConfig = config.Configs["RestartModule"]; + if (restartConfig != null) { - // Create a StatsReporter with the current scene and a default - // 10 frames stored for the frame time statistics - StatsReporter = new SimStatsReporter(this); - } + string markerPath = restartConfig.GetString("MarkerPath", String.Empty); - StatsReporter.OnSendStatsResult += SendSimStatsPackets; - StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats; + if (markerPath != String.Empty) + { + string path = Path.Combine(markerPath, RegionInfo.RegionID.ToString() + ".started"); + try + { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + } + catch (Exception) + { + } + } + } + StartTimerWatchdog(); } public Scene(RegionInfo regInfo) @@ -1240,15 +1199,12 @@ namespace OpenSim.Region.Framework.Scenes UpdatePrioritizationScheme = UpdatePrioritizationSchemes.Time; ReprioritizationInterval = 5000; - RootRotationUpdateTolerance = 0.1f; - RootVelocityUpdateTolerance = 0.001f; - RootPositionUpdateTolerance = 0.05f; - RootReprioritizationDistance = 10.0; - ChildReprioritizationDistance = 20.0; + ReprioritizationDistance = m_minReprioritizationDistance; m_eventManager = new EventManager(); m_permissions = new ScenePermissions(this); + } #endregion @@ -1285,7 +1241,6 @@ namespace OpenSim.Region.Framework.Scenes if (!fm.TryGetFeature("OpenSimExtras", out openSimExtras)) openSimExtras = new OSDMap(); - float FrameTime = MinFrameTicks / 1000.0f; float statisticsFPSfactor = 1.0f; if(Normalized55FPS) statisticsFPSfactor = 55.0f * FrameTime; @@ -1302,7 +1257,7 @@ namespace OpenSim.Region.Framework.Scenes protected virtual void RegisterDefaultSceneEvents() { - m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; +// m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; } public override string GetSimulatorVersion() @@ -1325,20 +1280,8 @@ namespace OpenSim.Region.Framework.Scenes { if (RegionInfo.RegionHandle != otherRegion.RegionHandle) { - //// If these are cast to INT because long + negative values + abs returns invalid data - //int resultX = Math.Abs((int)xcell - (int)RegionInfo.RegionLocX); - //int resultY = Math.Abs((int)ycell - (int)RegionInfo.RegionLocY); - //if (resultX <= 1 && resultY <= 1) - float dist = (float)Math.Max(DefaultDrawDistance, - (float)Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY)); - uint newRegionX, newRegionY, thisRegionX, thisRegionY; - Util.RegionHandleToRegionLoc(otherRegion.RegionHandle, out newRegionX, out newRegionY); - Util.RegionHandleToRegionLoc(RegionInfo.RegionHandle, out thisRegionX, out thisRegionY); - - //m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}", - // RegionInfo.RegionName, otherRegion.RegionName, newRegionX, newRegionY); - if (!Util.IsOutsideView(dist, thisRegionX, newRegionX, thisRegionY, newRegionY)) + if (isNeighborRegion(otherRegion)) { // Let the grid service module know, so this can be cached m_eventManager.TriggerOnRegionUp(otherRegion); @@ -1373,6 +1316,21 @@ namespace OpenSim.Region.Framework.Scenes } } + public bool isNeighborRegion(GridRegion otherRegion) + { + int tmp = otherRegion.RegionLocX - (int)RegionInfo.WorldLocX; ; + + if (tmp < -otherRegion.RegionSizeX && tmp > RegionInfo.RegionSizeX) + return false; + + tmp = otherRegion.RegionLocY - (int)RegionInfo.WorldLocY; + + if (tmp < -otherRegion.RegionSizeY && tmp > RegionInfo.RegionSizeY) + return false; + + return true; + } + public void AddNeighborRegion(RegionInfo region) { lock (m_neighbours) @@ -1475,13 +1433,24 @@ namespace OpenSim.Region.Framework.Scenes return; } + IEtcdModule etcd = RequestModuleInterface(); + if (etcd != null) + { + etcd.Delete("Health"); + etcd.Delete("HealthFlags"); + etcd.Delete("RootAgents"); + } + m_log.InfoFormat("[SCENE]: Closing down the single simulator: {0}", RegionInfo.RegionName); - StatsReporter.Close(); + StatsReporter.Close(); m_restartTimer.Stop(); m_restartTimer.Close(); + if (!GridService.DeregisterRegion(RegionInfo.RegionID)) + m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name); + // Kick all ROOT agents with the message, 'The simulator is going down' ForEachScenePresence(delegate(ScenePresence avatar) { @@ -1504,13 +1473,15 @@ namespace OpenSim.Region.Framework.Scenes // Stop all client threads. ForEachScenePresence(delegate(ScenePresence avatar) { CloseAgent(avatar.UUID, false); }); - m_log.Debug("[SCENE]: Persisting changed objects"); + m_log.Debug("[SCENE]: TriggerSceneShuttingDown"); EventManager.TriggerSceneShuttingDown(this); - Backup(false); - m_sceneGraph.Close(); - if (!GridService.DeregisterRegion(RegionInfo.RegionID)) - m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name); + m_log.Debug("[SCENE]: Persisting changed objects"); + Backup(true); + + m_log.Debug("[SCENE]: Closing scene"); + + m_sceneGraph.Close(); base.Close(); @@ -1519,6 +1490,7 @@ namespace OpenSim.Region.Framework.Scenes // attempt to reference a null or disposed physics scene. if (PhysicsScene != null) { + m_log.Debug("[SCENE]: Dispose Physics"); PhysicsScene phys = PhysicsScene; // remove the physics engine from both Scene and SceneGraph PhysicsScene = null; @@ -1537,7 +1509,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// Start the scripts within the scene. - /// + /// public void Start(bool startScripts) { if (IsRunning) @@ -1550,10 +1522,31 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[SCENE]: Starting Heartbeat timer for {0}", RegionInfo.RegionName); if (m_heartbeatThread != null) { + m_hbRestarts++; + if(m_hbRestarts > 10) + Environment.Exit(1); + m_log.ErrorFormat("[SCENE]: Restarting heartbeat thread because it hasn't reported in in region {0}", RegionInfo.RegionName); + +//int pid = System.Diagnostics.Process.GetCurrentProcess().Id; +//System.Diagnostics.Process proc = new System.Diagnostics.Process(); +//proc.EnableRaisingEvents=false; +//proc.StartInfo.FileName = "/bin/kill"; +//proc.StartInfo.Arguments = "-QUIT " + pid.ToString(); +//proc.Start(); +//proc.WaitForExit(); +//Thread.Sleep(1000); +//Environment.Exit(1); m_heartbeatThread.Abort(); + Watchdog.AbortThread(m_heartbeatThread.ManagedThreadId); m_heartbeatThread = null; } + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + // tell physics to finish building actor + m_sceneGraph.ProcessPhysicsPreSimulation(); + m_heartbeatThread = WorkManager.StartThread( Heartbeat, string.Format("Heartbeat-({0})", RegionInfo.RegionName.Replace(" ", "_")), ThreadPriority.Normal, false, false); @@ -1596,136 +1589,13 @@ namespace OpenSim.Region.Framework.Scenes // alarms for scenes with many objects. Update(1); - WorkManager.StartThread( - Maintenance, string.Format("Maintenance ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, true); - Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true; m_lastFrameTick = Util.EnvironmentTickCount(); - - if (UpdateOnTimer) - { - m_sceneUpdateTimer = new Timer(MinFrameTicks); - m_sceneUpdateTimer.AutoReset = true; - m_sceneUpdateTimer.Elapsed += Update; - m_sceneUpdateTimer.Start(); - } - else - { - Thread.CurrentThread.Priority = ThreadPriority.Highest; - Update(-1); - Watchdog.RemoveThread(); - m_isRunning = false; - } - } - - private volatile bool m_isTimerUpdateRunning; - - private void Update(object sender, ElapsedEventArgs e) - { - if (m_isTimerUpdateRunning) - return; - - m_isTimerUpdateRunning = true; - - // If the last frame did not complete on time, then immediately start the next update on the same thread - // and ignore further timed updates until we have a frame that had spare time. - while (!Update(1) && Active) { } - - if (!Active || m_shuttingDown) - { - m_sceneUpdateTimer.Stop(); - m_sceneUpdateTimer = null; - m_isRunning = false; - } - - m_isTimerUpdateRunning = false; - } - - private void Maintenance() - { - DoMaintenance(-1); - + Update(-1); Watchdog.RemoveThread(); } - public void DoMaintenance(int runs) - { - long? endRun = null; - int runtc, tmpMS; - int previousMaintenanceTick; - - if (runs >= 0) - endRun = MaintenanceRun + runs; - - List coarseLocations; - List avatarUUIDs; - - while (!m_shuttingDown && ((endRun == null && Active) || MaintenanceRun < endRun)) - { - runtc = Util.EnvironmentTickCount(); - ++MaintenanceRun; - - // m_log.DebugFormat("[SCENE]: Maintenance run {0} in {1}", MaintenanceRun, Name); - - // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client) - if (MaintenanceRun % (m_update_coarse_locations / 10) == 0) - { - SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60); - // Send coarse locations to clients - ForEachScenePresence(delegate(ScenePresence presence) - { - presence.SendCoarseLocations(coarseLocations, avatarUUIDs); - }); - } - - if (SendPeriodicAppearanceUpdates && MaintenanceRun % 60 == 0) - { - // m_log.DebugFormat("[SCENE]: Sending periodic appearance updates"); - - if (AvatarFactory != null) - { - ForEachRootScenePresence(sp => AvatarFactory.SendAppearance(sp.UUID)); - } - } - - // Delete temp-on-rez stuff - if (MaintenanceRun % m_update_temp_cleaning == 0 && !m_cleaningTemps) - { - // m_log.DebugFormat("[SCENE]: Running temp-on-rez cleaning in {0}", Name); - tmpMS = Util.EnvironmentTickCount(); - m_cleaningTemps = true; - - WorkManager.RunInThread( - delegate { CleanTempObjects(); m_cleaningTemps = false; }, - null, - string.Format("CleanTempObjects ({0})", Name)); - - tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS); - } - - Watchdog.UpdateThread(); - - previousMaintenanceTick = m_lastMaintenanceTick; - m_lastMaintenanceTick = Util.EnvironmentTickCount(); - runtc = Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, runtc); - runtc = MinMaintenanceTicks - runtc; - - if (runtc > 0) - m_maintenanceWaitEvent.WaitOne(runtc); - - // Optionally warn if a frame takes double the amount of time that it should. - if (DebugUpdates - && Util.EnvironmentTickCountSubtract( - m_lastMaintenanceTick, previousMaintenanceTick) > MinMaintenanceTicks * 2) - m_log.WarnFormat( - "[SCENE]: Maintenance took {0} ms (desired max {1} ms) in {2}", - Util.EnvironmentTickCountSubtract(m_lastMaintenanceTick, previousMaintenanceTick), - MinMaintenanceTicks, - RegionInfo.RegionName); - } - } - - public override bool Update(int frames) + public override void Update(int frames) { long? endFrame = null; @@ -1733,119 +1603,97 @@ namespace OpenSim.Region.Framework.Scenes endFrame = Frame + frames; float physicsFPS = 0f; - int previousFrameTick, tmpMS; - - // These variables will be used to save the precise frame time using the - // Stopwatch class of Microsoft SDK; the times are recorded at the start - // and end of a particular section of code, and then used to calculate - // the frame times, which are the sums of the sections for each given name - double preciseTotalFrameTime = 0.0; - double preciseSimFrameTime = 0.0; - double precisePhysicsFrameTime = 0.0; - Stopwatch totalFrameStopwatch = new Stopwatch(); - Stopwatch simFrameStopwatch = new Stopwatch(); - Stopwatch physicsFrameStopwatch = new Stopwatch(); - - // Begin the stopwatch to keep track of the time that the frame - // started running to determine how long the frame took to complete - totalFrameStopwatch.Start(); + float frameTimeMS = FrameTime * 1000.0f; + + int previousFrameTick; + + double tmpMS; + double tmpMS2; + double framestart; + float sleepMS; + float sleepError = 0; while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame)) { + framestart = Util.GetTimeStampMS(); ++Frame; // m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName); - agentMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0; + agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = 0f; try { EventManager.TriggerRegionHeartbeatStart(this); // Apply taints in terrain module to terrain in physics scene + + tmpMS = Util.GetTimeStampMS(); + + if (Frame % 4 == 0) + { + CheckTerrainUpdates(); + } + if (Frame % m_update_terrain == 0) { - // At several points inside the code there was a need to - // create a more precise measurement of time elapsed. - // This led to the addition of variables that have a - // similar function and thus remain tightly connected to - // their original counterparts. However, the original - // code is not receiving comments from our group because - // we don't feel right modifying the code to that degree - // at this point in time, the precise values all begin - // with the keyword precise - tmpMS = Util.EnvironmentTickCount(); - simFrameStopwatch.Start(); UpdateTerrain(); - - // Get the simulation frame time that the avatar force - // input took - simFrameStopwatch.Stop(); - preciseSimFrameTime = - simFrameStopwatch.Elapsed.TotalMilliseconds; - terrainMS = Util.EnvironmentTickCountSubtract(tmpMS); } - // At several points inside the code there was a need to - // create a more precise measurement of time elapsed. This - // led to the addition of variables that have a similar - // function and thus remain tightly connected to their - // original counterparts. However, the original code is - // not receiving comments from our group because we don't - // feel right modifying the code to that degree at this - // point in time, the precise values all begin with the - // keyword precise + tmpMS2 = Util.GetTimeStampMS(); + terrainMS = (float)(tmpMS2 - tmpMS); + tmpMS = tmpMS2; - tmpMS = Util.EnvironmentTickCount(); - - // Begin the stopwatch to track the time to prepare physics - physicsFrameStopwatch.Start(); if (PhysicsEnabled && Frame % m_update_physics == 0) m_sceneGraph.UpdatePreparePhysics(); - // Get the time it took to prepare the physics, this - // would report the most precise time that physics was - // running on the machine and should the physics not be - // enabled will report the time it took to check if physics - // was enabled - physicsFrameStopwatch.Stop(); - precisePhysicsFrameTime = physicsFrameStopwatch.Elapsed.TotalMilliseconds; - physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS); + tmpMS2 = Util.GetTimeStampMS(); + physicsMS2 = (float)(tmpMS2 - tmpMS); + tmpMS = tmpMS2; +/* // Apply any pending avatar force input to the avatar's velocity - tmpMS = Util.EnvironmentTickCount(); - simFrameStopwatch.Restart(); if (Frame % m_update_entitymovement == 0) m_sceneGraph.UpdateScenePresenceMovement(); +*/ + if (Frame % (m_update_coarse_locations) == 0 && !m_sendingCoarseLocations) + { + m_sendingCoarseLocations = true; + WorkManager.RunInThreadPool( + delegate + { + List coarseLocations; + List avatarUUIDs; + SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60); + // Send coarse locations to clients + ForEachScenePresence(delegate(ScenePresence presence) + { + presence.SendCoarseLocations(coarseLocations, avatarUUIDs); + }); + m_sendingCoarseLocations = false; + }, null, string.Format("SendCoarseLocations ({0})", Name)); + } - // Get the simulation frame time that the avatar force input + // Get the simulation frame time that the avatar force input // took - simFrameStopwatch.Stop(); - preciseSimFrameTime += - simFrameStopwatch.Elapsed.TotalMilliseconds; - agentMS = Util.EnvironmentTickCountSubtract(tmpMS); + tmpMS2 = Util.GetTimeStampMS(); + agentMS = (float)(tmpMS2 - tmpMS); + tmpMS = tmpMS2; // Perform the main physics update. This will do the actual work of moving objects and avatars according to their // velocity - tmpMS = Util.EnvironmentTickCount(); - physicsFrameStopwatch.Restart(); if (Frame % m_update_physics == 0) { if (PhysicsEnabled) - physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameSeconds); + physicsFPS = m_sceneGraph.UpdatePhysics(FrameTime); if (SynchronizeScene != null) SynchronizeScene(this); } - // Add the main physics update time to the prepare physics time - physicsFrameStopwatch.Stop(); - precisePhysicsFrameTime += physicsFrameStopwatch.Elapsed.TotalMilliseconds; - physicsMS = Util.EnvironmentTickCountSubtract(tmpMS); - - // Start the stopwatch for the remainder of the simulation - simFrameStopwatch.Restart(); - tmpMS = Util.EnvironmentTickCount(); + tmpMS2 = Util.GetTimeStampMS(); + physicsMS = (float)(tmpMS2 - tmpMS); + tmpMS = tmpMS2; // Check if any objects have reached their targets CheckAtTargets(); @@ -1860,20 +1708,37 @@ namespace OpenSim.Region.Framework.Scenes if (Frame % m_update_presences == 0) m_sceneGraph.UpdatePresences(); - agentMS += Util.EnvironmentTickCountSubtract(tmpMS); + tmpMS2 = Util.GetTimeStampMS(); + agentMS += (float)(tmpMS2 - tmpMS); + tmpMS = tmpMS2; + + // Delete temp-on-rez stuff + if (Frame % m_update_temp_cleaning == 0 && !m_cleaningTemps) + { + m_cleaningTemps = true; + WorkManager.RunInThreadPool( + delegate { CleanTempObjects(); m_cleaningTemps = false; }, null, string.Format("CleanTempObjects ({0})", Name)); + tmpMS2 = Util.GetTimeStampMS(); + tempOnRezMS = (float)(tmpMS2 - tmpMS); // bad.. counts the FireAndForget, not CleanTempObjects + tmpMS = tmpMS2; + } if (Frame % m_update_events == 0) { - tmpMS = Util.EnvironmentTickCount(); UpdateEvents(); - eventMS = Util.EnvironmentTickCountSubtract(tmpMS); + + tmpMS2 = Util.GetTimeStampMS(); + eventMS = (float)(tmpMS2 - tmpMS); + tmpMS = tmpMS2; } if (PeriodicBackup && Frame % m_update_backup == 0) { - tmpMS = Util.EnvironmentTickCount(); UpdateStorageBackup(); - backupMS = Util.EnvironmentTickCountSubtract(tmpMS); + + tmpMS2 = Util.GetTimeStampMS(); + backupMS = (float)(tmpMS2 - tmpMS); + tmpMS = tmpMS2; } //if (Frame % m_update_land == 0) @@ -1885,13 +1750,9 @@ namespace OpenSim.Region.Framework.Scenes if (!LoginsEnabled && Frame == 20) { - // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock); - - // In 99.9% of cases it is a bad idea to manually force garbage collection. However, - // this is a rare case where we know we have just went through a long cycle of heap - // allocations, and there is no more work to be done until someone logs in GC.Collect(); - + GC.WaitForPendingFinalizers(); + GC.Collect(); if (!LoginLock) { if (!StartDisabled) @@ -1916,6 +1777,7 @@ namespace OpenSim.Region.Framework.Scenes // LoginLock can currently only be set by a region module implementation. // If somehow this hasn't been done then the quickest way to bugfix is to see the // NullReferenceException + IRegionReadyModule rrm = RequestModuleInterface(); rrm.TriggerRegionReady(this); } @@ -1930,79 +1792,64 @@ namespace OpenSim.Region.Framework.Scenes } EventManager.TriggerRegionHeartbeatEnd(this); - otherMS = eventMS + backupMS + terrainMS + landMS; + m_firstHeartbeat = false; + Watchdog.UpdateThread(); - // Get the elapsed time for the simulation frame - simFrameStopwatch.Stop(); - preciseSimFrameTime += - simFrameStopwatch.Elapsed.TotalMilliseconds; + otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; - if (!UpdateOnTimer) - { - Watchdog.UpdateThread(); + tmpMS = Util.GetTimeStampMS(); - spareMS = MinFrameTicks - Util.EnvironmentTickCountSubtract(m_lastFrameTick); + previousFrameTick = m_lastFrameTick; + m_lastFrameTick = (int)(tmpMS + 0.5); - if (spareMS > 0) - m_updateWaitEvent.WaitOne(spareMS); - else - spareMS = 0; - } + // estimate sleep time + tmpMS2 = tmpMS - framestart; + tmpMS2 = (double)frameTimeMS - tmpMS2 - sleepError; + + // reuse frameMS as temporary + frameMS = (float)tmpMS2; + + // sleep if we can + if (tmpMS2 > 0) + { + Thread.Sleep((int)(tmpMS2 + 0.5)); + + tmpMS2 = Util.GetTimeStampMS(); + sleepMS = (float)(tmpMS2 - tmpMS); + sleepError = sleepMS - frameMS; + Util.Clamp(sleepError, 0.0f, 20f); + frameMS = (float)(tmpMS2 - framestart); + } else - { - spareMS = Math.Max(0, MinFrameTicks - physicsMS2 - agentMS - physicsMS - otherMS); - } + { + tmpMS2 = Util.GetTimeStampMS(); + frameMS = (float)(tmpMS2 - framestart); + sleepMS = 0.0f; + sleepError = 0.0f; + } - // Get the total frame time - totalFrameStopwatch.Stop(); - preciseTotalFrameTime = - totalFrameStopwatch.Elapsed.TotalMilliseconds; + // script time is not scene frame time, but is displayed per frame + float scriptTimeMS = GetAndResetScriptExecutionTime(); + StatsReporter.AddFrameStats(TimeDilation, physicsFPS, agentMS, + physicsMS + physicsMS2, otherMS , sleepMS, frameMS, scriptTimeMS); - // Restart the stopwatch for the total time of the next frame - totalFrameStopwatch.Restart(); - previousFrameTick = m_lastFrameTick; - frameMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick); - m_lastFrameTick = Util.EnvironmentTickCount(); // if (Frame%m_update_avatars == 0) // UpdateInWorldTime(); - StatsReporter.AddPhysicsFPS(physicsFPS); - StatsReporter.AddTimeDilation(TimeDilation); - StatsReporter.AddFPS(1); - - StatsReporter.addFrameMS(frameMS); - StatsReporter.addAgentMS(agentMS); - StatsReporter.addPhysicsMS(physicsMS + physicsMS2); - StatsReporter.addOtherMS(otherMS); - StatsReporter.AddSpareMS(spareMS); - StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); - StatsReporter.AddScriptMS((int) GetAndResetScriptExecutionTime()); - - // Send the correct time values to the stats reporter for the - // frame times - StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime, - preciseSimFrameTime, precisePhysicsFrameTime, 0.0); - - // Send the correct number of frames that the physics library - // has processed to the stats reporter - StatsReporter.addPhysicsFrame(1); - - // Optionally warn if a frame takes double the amount of time that it should. + + // Optionally warn if a frame takes double the amount of time that it should. if (DebugUpdates && Util.EnvironmentTickCountSubtract( - m_lastFrameTick, previousFrameTick) > MinFrameTicks * 2) + m_lastFrameTick, previousFrameTick) > (int)(FrameTime * 1000 * 2)) + m_log.WarnFormat( "[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}", Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick), - MinFrameTicks, + FrameTime * 1000, + RegionInfo.RegionName); } - - // Finished updating scene frame, so stop the total frame's Stopwatch - totalFrameStopwatch.Stop(); - - return spareMS >= 0; } /// @@ -2011,24 +1858,28 @@ namespace OpenSim.Region.Framework.Scenes /// Elapsed Stopwatch ticks public void AddScriptExecutionTime(long ticks) { + StatsReporter.addScriptEvents(1); Interlocked.Add(ref m_scriptExecutionTime, ticks); } /// - /// Returns the total execution time of all the scripts in the region since the last frame - /// (in milliseconds), and clears the value in preparation for the next frame. + /// Returns the total execution time of all the scripts in the region since the last call + /// (in milliseconds), and clears the value in preparation for the next call. /// /// Time in milliseconds - private long GetAndResetScriptExecutionTime() + + // Warning: this is now called from StatsReporter, and can't be shared + + public long GetAndResetScriptExecutionTime() { long ticks = Interlocked.Exchange(ref m_scriptExecutionTime, 0); - return (ticks * 1000) / Stopwatch.Frequency; + return (ticks * 1000L) / Stopwatch.Frequency; } public void AddGroupTarget(SceneObjectGroup grp) { lock (m_groupsWithTargets) - m_groupsWithTargets[grp.UUID] = grp; + m_groupsWithTargets[grp.UUID] = 0; } public void RemoveGroupTarget(SceneObjectGroup grp) @@ -2039,18 +1890,24 @@ namespace OpenSim.Region.Framework.Scenes private void CheckAtTargets() { - List objs = null; + List objs = null; lock (m_groupsWithTargets) { if (m_groupsWithTargets.Count != 0) - objs = new List(m_groupsWithTargets.Values); + objs = new List(m_groupsWithTargets.Keys); } if (objs != null) { - foreach (SceneObjectGroup entry in objs) - entry.checkAtTargets(); + foreach (UUID entry in objs) + { + SceneObjectGroup grp = GetSceneObjectGroup(entry); + if (grp == null) + m_groupsWithTargets.Remove(entry); + else + grp.checkAtTargets(); + } } } @@ -2074,6 +1931,11 @@ namespace OpenSim.Region.Framework.Scenes EventManager.TriggerTerrainTick(); } + private void CheckTerrainUpdates() + { + EventManager.TriggerTerrainCheckUpdates(); + } + /// /// Back up queued up changes /// @@ -2081,8 +1943,7 @@ namespace OpenSim.Region.Framework.Scenes { if (!m_backingup) { - m_backingup = true; - WorkManager.RunInThread(o => Backup(false), null, string.Format("BackupWaitCallback ({0})", Name)); + WorkManager.RunInThreadPool(o => Backup(false), null, string.Format("BackupWorker ({0}", Name), false); } } @@ -2110,38 +1971,58 @@ namespace OpenSim.Region.Framework.Scenes { lock (m_returns) { - EventManager.TriggerOnBackup(SimulationDataService, forced); - m_backingup = false; + if(m_backingup) + { + m_log.WarnFormat("[Scene] Backup of {0} already running. New call skipped", RegionInfo.RegionName); + return; + } - foreach (KeyValuePair ret in m_returns) + m_backingup = true; + try { - UUID transaction = UUID.Random(); - - GridInstantMessage msg = new GridInstantMessage(); - msg.fromAgentID = new Guid(UUID.Zero.ToString()); // From server - msg.toAgentID = new Guid(ret.Key.ToString()); - msg.imSessionID = new Guid(transaction.ToString()); - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - msg.fromAgentName = "Server"; - msg.dialog = (byte)19; // Object msg - msg.fromGroup = false; - msg.offline = (byte)0; - msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID; - msg.Position = Vector3.Zero; - msg.RegionID = RegionInfo.RegionID.Guid; - - // We must fill in a null-terminated 'empty' string here since bytes[0] will crash viewer 3. - msg.binaryBucket = Util.StringToBytes256("\0"); - if (ret.Value.count > 1) - msg.message = string.Format("Your {0} objects were returned from {1} in region {2} due to {3}", ret.Value.count, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason); - else - msg.message = string.Format("Your object {0} was returned from {1} in region {2} due to {3}", ret.Value.objectName, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason); + EventManager.TriggerOnBackup(SimulationDataService, forced); + + if(m_returns.Count == 0) + return; IMessageTransferModule tr = RequestModuleInterface(); - if (tr != null) + if (tr == null) + return; + + uint unixtime = (uint)Util.UnixTimeSinceEpoch(); + uint estateid = RegionInfo.EstateSettings.ParentEstateID; + Guid regionguid = RegionInfo.RegionID.Guid; + + foreach (KeyValuePair ret in m_returns) + { + GridInstantMessage msg = new GridInstantMessage(); + msg.fromAgentID = Guid.Empty; // From server + msg.toAgentID = ret.Key.Guid; + msg.imSessionID = Guid.NewGuid(); + msg.timestamp = unixtime; + msg.fromAgentName = "Server"; + msg.dialog = 19; // Object msg + msg.fromGroup = false; + msg.offline = 1; + msg.ParentEstateID = estateid; + msg.Position = Vector3.Zero; + msg.RegionID = regionguid; + + // We must fill in a null-terminated 'empty' string here since bytes[0] will crash viewer 3. + msg.binaryBucket = new Byte[1] {0}; + if (ret.Value.count > 1) + msg.message = string.Format("Your {0} objects were returned from {1} in region {2} due to {3}", ret.Value.count, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason); + else + msg.message = string.Format("Your object {0} was returned from {1} in region {2} due to {3}", ret.Value.objectName, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason); + tr.SendInstantMessage(msg, delegate(bool success) { }); + } + m_returns.Clear(); + } + finally + { + m_backingup = false; } - m_returns.Clear(); } } @@ -2159,7 +2040,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Tell an agent that their object has been returned. + /// Tell an agent that their object has been returned. /// /// /// The actual return is handled by the caller. @@ -2199,7 +2080,16 @@ namespace OpenSim.Region.Framework.Scenes /// public void SaveTerrain() { - SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); + SimulationDataService.StoreTerrain(Heightmap.GetTerrainData(), RegionInfo.RegionID); + } + + /// + /// Store the terrain in the persistant data store + /// + public void SaveBakedTerrain() + { + if(Bakedmap != null) + SimulationDataService.StoreBakedTerrain(Bakedmap.GetTerrainData(), RegionInfo.RegionID); } public void StoreWindlightProfile(RegionLightShareData wl) @@ -2222,20 +2112,44 @@ namespace OpenSim.Region.Framework.Scenes { try { + Bakedmap = null; + TerrainData map = SimulationDataService.LoadBakedTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); + if (map != null) + { + Bakedmap = new TerrainChannel(map); + } + } + catch (Exception e) + { + m_log.WarnFormat( + "[TERRAIN]: Scene.cs: LoadWorldMap() baked terrain - Failed with exception {0}{1}", e.Message, e.StackTrace); + } + + try + { TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); if (map == null) { - // This should be in the Terrain module, but it isn't because - // the heightmap is needed _way_ before the modules are initialized... - IConfig terrainConfig = m_config.Configs["Terrain"]; - String m_InitialTerrain = "pinhead-island"; - if (terrainConfig != null) - m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); + if(Bakedmap != null) + { + m_log.Warn("[TERRAIN]: terrain not found. Used stored baked terrain."); + Heightmap = Bakedmap.MakeCopy(); + SimulationDataService.StoreTerrain(Heightmap.GetTerrainData(), RegionInfo.RegionID); + } + else + { + // This should be in the Terrain module, but it isn't because + // the heightmap is needed _way_ before the modules are initialized... + IConfig terrainConfig = m_config.Configs["Terrain"]; + String m_InitialTerrain = "pinhead-island"; + if (terrainConfig != null) + m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); - m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); - Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); + m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); + Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ); - SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); + SimulationDataService.StoreTerrain(Heightmap.GetTerrainData(), RegionInfo.RegionID); + } } else { @@ -2248,13 +2162,12 @@ namespace OpenSim.Region.Framework.Scenes "[TERRAIN]: Scene.cs: LoadWorldMap() - Regenerating as failed with exception {0}{1}", e.Message, e.StackTrace); - // Non standard region size. If there's an old terrain in the database, it might read past the buffer #pragma warning disable 0162 if ((int)Constants.RegionSize != 256) { Heightmap = new TerrainChannel(); - SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); + SimulationDataService.StoreTerrain(Heightmap.GetTerrainData(), RegionInfo.RegionID); } } catch (Exception e) @@ -2262,6 +2175,12 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[TERRAIN]: Scene.cs: LoadWorldMap() - Failed with exception {0}{1}", e.Message, e.StackTrace); } + + if(Bakedmap == null && Heightmap != null) + { + Bakedmap = Heightmap.MakeCopy(); + SimulationDataService.StoreBakedTerrain(Bakedmap.GetTerrainData(), RegionInfo.RegionID); + } } /// @@ -2277,12 +2196,12 @@ namespace OpenSim.Region.Framework.Scenes //// stored in the GridService, because that's what the world map module uses //// to send the map image UUIDs (of other regions) to the viewer... if (m_generateMaptiles) - RegenerateMaptile(); + RegenerateMaptile(); GridRegion region = new GridRegion(RegionInfo); string error = GridService.RegisterRegion(RegionInfo.ScopeID, region); // m_log.DebugFormat("[SCENE]: RegisterRegionWithGrid. name={0},id={1},loc=<{2},{3}>,size=<{4},{5}>", - // m_regionName, + // m_regionName, // RegionInfo.RegionID, // RegionInfo.RegionLocX, RegionInfo.RegionLocY, // RegionInfo.RegionSizeX, RegionInfo.RegionSizeY); @@ -2344,7 +2263,9 @@ namespace OpenSim.Region.Framework.Scenes EventManager.TriggerOnSceneObjectLoaded(group); SceneObjectPart rootPart = group.GetPart(group.UUID); rootPart.Flags &= ~PrimFlags.Scripted; + rootPart.TrimPermissions(); + group.InvalidateDeepEffectivePerms(); // Don't do this here - it will get done later on when sculpt data is loaded. // group.CheckSculptAndLoad(); @@ -2383,93 +2304,166 @@ namespace OpenSim.Region.Framework.Scenes /// public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) { - Vector3 pos = Vector3.Zero; - if (RayEndIsIntersection == (byte)1) - { - pos = RayEnd; - return pos; - } - if (RayTargetID != UUID.Zero) + Vector3 dir = RayEnd - RayStart; + + float wheight = (float)RegionInfo.RegionSettings.WaterHeight; + Vector3 wpos = Vector3.Zero; + // Check for water surface intersection from above + if ((RayStart.Z > wheight) && (RayEnd.Z < wheight)) { - SceneObjectPart target = GetSceneObjectPart(RayTargetID); + float ratio = (wheight - RayStart.Z) / dir.Z; + wpos.X = RayStart.X + (ratio * dir.X); + wpos.Y = RayStart.Y + (ratio * dir.Y); + wpos.Z = wheight; + } - Vector3 direction = Vector3.Normalize(RayEnd - RayStart); - Vector3 AXOrigin = RayStart; - Vector3 AXdirection = direction; + Vector3 pos = Vector3.Zero; - if (target != null) + if (RayEndIsIntersection != (byte)1) + { + float dist = dir.Length(); + if (dist != 0) { - pos = target.AbsolutePosition; - //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); + Vector3 direction = dir * (1 / dist); - // TODO: Raytrace better here + dist += 1.0f; - //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection)); - Ray NewRay = new Ray(AXOrigin, AXdirection); + if (SupportsRayCastFiltered()) + { + RayFilterFlags rayfilter = RayFilterFlags.BackFaceCull; + rayfilter |= RayFilterFlags.land; + rayfilter |= RayFilterFlags.physical; + rayfilter |= RayFilterFlags.nonphysical; + rayfilter |= RayFilterFlags.LSLPhantom; // ubODE will only see volume detectors + + // get some more contacts ??? + int physcount = 4; + + List physresults = + (List)RayCastFiltered(RayStart, direction, dist, physcount, rayfilter); + if (physresults != null && physresults.Count > 0) + { + // look for terrain ? + if(RayTargetID == UUID.Zero) + { + foreach (ContactResult r in physresults) + { + if (r.ConsumerID == 0) + { + pos = r.Normal * scale; + pos *= 0.5f; + pos = r.Pos + pos; + + if (wpos.Z > pos.Z) pos = wpos; + return pos; + } + } + } + else + { + foreach (ContactResult r in physresults) + { + SceneObjectPart part = GetSceneObjectPart(r.ConsumerID); + if (part == null) + continue; + if (part.UUID == RayTargetID) + { + pos = r.Normal * scale; + pos *= 0.5f; + pos = r.Pos + pos; + + if (wpos.Z > pos.Z) pos = wpos; + return pos; + } + } + } + // else the first we got + pos = physresults[0].Normal * scale; + pos *= 0.5f; + pos = physresults[0].Pos + pos; + + if (wpos.Z > pos.Z) + pos = wpos; + return pos; + } - // Ray Trace against target here - EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); + } + if (RayTargetID != UUID.Zero) + { + SceneObjectPart target = GetSceneObjectPart(RayTargetID); - // Un-comment out the following line to Get Raytrace results printed to the console. - // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); - float ScaleOffset = 0.5f; + Ray NewRay = new Ray(RayStart, direction); - // If we hit something - if (ei.HitTF) - { - Vector3 scaleComponent = ei.AAfaceNormal; - if (scaleComponent.X != 0) ScaleOffset = scale.X; - if (scaleComponent.Y != 0) ScaleOffset = scale.Y; - if (scaleComponent.Z != 0) ScaleOffset = scale.Z; - ScaleOffset = Math.Abs(ScaleOffset); - Vector3 intersectionpoint = ei.ipoint; - Vector3 normal = ei.normal; - // Set the position to the intersection point - Vector3 offset = (normal * (ScaleOffset / 2f)); - pos = (intersectionpoint + offset); - - //Seems to make no sense to do this as this call is used for rezzing from inventory as well, and with inventory items their size is not always 0.5f - //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method - // Un-offset the prim (it gets offset later by the consumer method) - //pos.Z -= 0.25F; + if (target != null) + { + pos = target.AbsolutePosition; - } + // Ray Trace against target here + EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); - return pos; - } - else - { - // We don't have a target here, so we're going to raytrace all the objects in the scene. + // Un-comment out the following line to Get Raytrace results printed to the console. + // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); + float ScaleOffset = 0.5f; - EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); + // If we hit something + if (ei.HitTF) + { + Vector3 scaleComponent = ei.AAfaceNormal; + if (scaleComponent.X != 0) ScaleOffset = scale.X; + if (scaleComponent.Y != 0) ScaleOffset = scale.Y; + if (scaleComponent.Z != 0) ScaleOffset = scale.Z; + ScaleOffset = Math.Abs(ScaleOffset); + Vector3 intersectionpoint = ei.ipoint; + Vector3 normal = ei.normal; + // Set the position to the intersection point + Vector3 offset = (normal * (ScaleOffset / 2f)); + pos = (intersectionpoint + offset); + + //Seems to make no sense to do this as this call is used for rezzing from inventory as well, and with inventory items their size is not always 0.5f + //And in cases when we weren't rezzing from inventory we were re-adding the 0.25 straight after calling this method + // Un-offset the prim (it gets offset later by the consumer method) + //pos.Z -= 0.25F; + + if (wpos.Z > pos.Z) pos = wpos; + return pos; + } + } + else + { + // We don't have a target here, so we're going to raytrace all the objects in the scene. + EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(NewRay, true, false); - // Un-comment the following line to print the raytrace results to the console. - //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); + // Un-comment the following line to print the raytrace results to the console. + //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); - if (ei.HitTF) - { - pos = ei.ipoint; - } - else - { - // fall back to our stupid functionality - pos = RayEnd; - } + if (ei.HitTF) + { + pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); + } + else + { + // fall back to our stupid functionality + pos = RayEnd; + } - return pos; + if (wpos.Z > pos.Z) pos = wpos; + return pos; + } + } } } - else - { - // fall back to our stupid functionality - pos = RayEnd; - //increase height so its above the ground. - //should be getting the normal of the ground at the rez point and using that? - pos.Z += scale.Z / 2f; - return pos; - } + // fall back to our stupid functionality + pos = RayEnd; + + //increase height so its above the ground. + //should be getting the normal of the ground at the rez point and using that? + pos.Z += scale.Z / 2f; + // return pos; + // check against posible water intercept + if (wpos.Z > pos.Z) pos = wpos; + return pos; } @@ -2523,13 +2517,26 @@ namespace OpenSim.Region.Framework.Scenes { // Otherwise, use this default creation code; sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape); - AddNewSceneObject(sceneObject, true); sceneObject.SetGroup(groupID, null); + AddNewSceneObject(sceneObject, true); + + if (AgentPreferencesService != null) // This will override the brave new full perm world! + { + AgentPrefs prefs = AgentPreferencesService.GetAgentPreferences(ownerID); + // Only apply user selected prefs if the user set them + if (prefs != null && prefs.PermNextOwner != 0) + { + sceneObject.RootPart.GroupMask = (uint)prefs.PermGroup; + sceneObject.RootPart.EveryoneMask = (uint)prefs.PermEveryone; + sceneObject.RootPart.NextOwnerMask = (uint)prefs.PermNextOwner; + } + } } if (UserManagementModule != null) sceneObject.RootPart.CreatorIdentification = UserManagementModule.GetUserUUI(ownerID); + sceneObject.InvalidateDeepEffectivePerms();; sceneObject.ScheduleGroupForFullUpdate(); return sceneObject; @@ -2560,12 +2567,12 @@ namespace OpenSim.Region.Framework.Scenes { if (m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates)) { + sceneObject.IsDeleted = false; EventManager.TriggerObjectAddedToScene(sceneObject); return true; } return false; - } /// @@ -2657,6 +2664,15 @@ namespace OpenSim.Region.Framework.Scenes /// public void DeleteAllSceneObjects() { + DeleteAllSceneObjects(false); + } + + /// + /// Delete every object from the scene. This does not include attachments worn by avatars. + /// + public void DeleteAllSceneObjects(bool exceptNoCopy) + { + List toReturn = new List(); lock (Entities) { EntityBase[] entities = Entities.GetEntities(); @@ -2665,11 +2681,24 @@ namespace OpenSim.Region.Framework.Scenes if (e is SceneObjectGroup) { SceneObjectGroup sog = (SceneObjectGroup)e; - if (!sog.IsAttachment) - DeleteSceneObject((SceneObjectGroup)e, false); + if (sog != null && !sog.IsAttachment) + { + if (!exceptNoCopy || ((sog.EffectiveOwnerPerms & (uint)PermissionMask.Copy) != 0)) + { + DeleteSceneObject((SceneObjectGroup)e, false); + } + else + { + toReturn.Add((SceneObjectGroup)e); + } + } } } } + if (toReturn.Count > 0) + { + returnObjects(toReturn.ToArray(), null); + } } /// @@ -2728,7 +2757,11 @@ namespace OpenSim.Region.Framework.Scenes group.DeleteGroupFromScene(silent); - // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); + // use this to mean also full delete + if (removeScripts) + group.Clear(); + partList = null; + // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); } /// @@ -2763,6 +2796,13 @@ namespace OpenSim.Region.Framework.Scenes return false; } + + public void updateScenePartGroup(SceneObjectPart part, SceneObjectGroup grp) + { + m_sceneGraph.updateScenePartGroup(part, grp); + } + +/* not in use, outdate by async method /// /// Move the given scene object into a new region depending on which region its absolute position has moved /// into. @@ -2811,6 +2851,7 @@ namespace OpenSim.Region.Framework.Scenes if (EntityTransferModule != null) EntityTransferModule.Cross(grp, attemptedPosition, silent); } +*/ // Simple test to see if a position is in the current region. // This test is mostly used to see if a region crossing is necessary. @@ -2818,27 +2859,15 @@ namespace OpenSim.Region.Framework.Scenes // Return 'true' if position inside region. public bool PositionIsInCurrentRegion(Vector3 pos) { - bool ret = false; - int xx = (int)Math.Floor(pos.X); - int yy = (int)Math.Floor(pos.Y); - if (xx < 0 || yy < 0) + float t = pos.X; + if (t < 0 || t >= RegionInfo.RegionSizeX) return false; - IRegionCombinerModule regionCombinerModule = RequestModuleInterface(); - if (regionCombinerModule == null) - { - // Regular region. Just check for region size - if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY) - ret = true; - } - else - { - // We're in a mega-region so see if we are still in that larger region - ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy); - } - - return ret; + t = pos.Y; + if (t < 0 || t >= RegionInfo.RegionSizeY) + return false; + return true; } /// @@ -2880,6 +2909,23 @@ namespace OpenSim.Region.Framework.Scenes /// True if the SceneObjectGroup was added, False if it was not public bool AddSceneObject(SceneObjectGroup sceneObject) { + if (sceneObject.OwnerID == UUID.Zero) + { + m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero", sceneObject.UUID); + return false; + } + + // If the user is banned, we won't let any of their objects + // enter. Period. + // + int flags = GetUserFlags(sceneObject.OwnerID); + if (RegionInfo.EstateSettings.IsBanned(sceneObject.OwnerID, flags)) + { + m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", sceneObject.OwnerID); + + return false; + } + // Force allocation of new LocalId // SceneObjectPart[] parts = sceneObject.Parts; @@ -2889,9 +2935,9 @@ namespace OpenSim.Region.Framework.Scenes if (sceneObject.IsAttachmentCheckFull()) // Attachment { sceneObject.RootPart.AddFlag(PrimFlags.TemporaryOnRez); - sceneObject.RootPart.AddFlag(PrimFlags.Phantom); +// sceneObject.RootPart.AddFlag(PrimFlags.Phantom); - // Don't sent a full update here because this will cause full updates to be sent twice for + // Don't sent a full update here because this will cause full updates to be sent twice for // attachments on region crossings, resulting in viewer glitches. AddRestoredSceneObject(sceneObject, false, false, false); @@ -2912,7 +2958,7 @@ namespace OpenSim.Region.Framework.Scenes RootPrim.RemFlag(PrimFlags.TemporaryOnRez); - // We must currently not resume scripts at this stage since AttachmentsModule does not have the + // We must currently not resume scripts at this stage since AttachmentsModule does not have the // information that this is due to a teleport/border cross rather than an ordinary attachment. // We currently do this in Scene.MakeRootAgent() instead. if (AttachmentsModule != null) @@ -2920,18 +2966,60 @@ namespace OpenSim.Region.Framework.Scenes } else { - RootPrim.RemFlag(PrimFlags.TemporaryOnRez); - RootPrim.AddFlag(PrimFlags.TemporaryOnRez); + m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was not found, setting to temp", sceneObject.UUID); +// RootPrim.RemFlag(PrimFlags.TemporaryOnRez); +// RootPrim.AddFlag(PrimFlags.TemporaryOnRez); + } + if (sceneObject.OwnerID == UUID.Zero) + { + m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero after attachment processing. BUG!", sceneObject.UUID); + return false; } } else { + if (sceneObject.OwnerID == UUID.Zero) + { + m_log.ErrorFormat("[SCENE]: Owner ID for non-attachment {0} was zero", sceneObject.UUID); + return false; + } AddRestoredSceneObject(sceneObject, true, false); } return true; } + private int GetStateSource(SceneObjectGroup sog) + { + if(!sog.IsAttachmentCheckFull()) + return 2; // StateSource.PrimCrossing + + ScenePresence sp = GetScenePresence(sog.OwnerID); + if (sp != null) + return sp.GetStateSource(); + + return 2; // StateSource.PrimCrossing + } + + public int GetUserFlags(UUID user) + { + //Unfortunately the SP approach means that the value is cached until region is restarted + /* + ScenePresence sp; + if (TryGetScenePresence(user, out sp)) + { + return sp.UserFlags; + } + else + { + */ + UserAccount uac = UserAccountService.GetUserAccount(RegionInfo.ScopeID, user); + if (uac == null) + return 0; + return uac.UserFlags; + //} + } + #endregion #region Add/Remove Avatar Methods @@ -2968,47 +3056,34 @@ namespace OpenSim.Region.Framework.Scenes = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; - // CheckHeartbeat(); + CheckHeartbeat(); sp = GetScenePresence(client.AgentId); - // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this - // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause - // other problems, and possibly the code calling AddNewAgent() should ensure that no client is already - // connected. if (sp == null) { m_log.DebugFormat( - "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", - client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); - - sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); - - // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the - // client is for a root or child agent. - // We must also set this before adding the client to the client manager so that an exception later on - // does not leave a client manager entry without the scene agent set, which will cause other code - // to fail since any entry in the client manager should have a ScenePresence - // - // XXX: This may be better set for a new client before that client is added to the client manager. - // But need to know what happens in the case where a ScenePresence is already present (and if this - // actually occurs). - client.SceneAgent = sp; + "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}, tpflags: {4}", + client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos, + ((TPFlags)aCircuit.teleportFlags).ToString()); m_clientManager.Add(client); SubscribeToClientEvents(client); - m_eventManager.TriggerOnNewPresence(sp); + + sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; + + m_eventManager.TriggerOnNewPresence(sp); } else { // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the // client is for a root or child agent. // XXX: This may be better set for a new client before that client is added to the client manager. - // But need to know what happens in the case where a ScenePresence is already present (and if this + // But need to know what happens in the case where a ScenePresence is already present (and if this // actually occurs). - client.SceneAgent = sp; + m_log.WarnFormat( "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", @@ -3016,8 +3091,9 @@ namespace OpenSim.Region.Framework.Scenes reallyNew = false; } + client.SceneAgent = sp; - // This is currently also being done earlier in NewUserConnection for real users to see if this + // This is currently also being done earlier in NewUserConnection for real users to see if this // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other // places. However, we still need to do it here for NPCs. CacheUserName(sp, aCircuit); @@ -3063,7 +3139,7 @@ namespace OpenSim.Region.Framework.Scenes if (sp != null && sp.PresenceType == PresenceType.Npc) { - UserManagementModule.AddUser(aCircuit.AgentID, first, last); + UserManagementModule.AddUser(aCircuit.AgentID, first, last, true); } else { @@ -3134,19 +3210,15 @@ namespace OpenSim.Region.Framework.Scenes // and the scene presence and the client, if they exist try { - // We need to wait for the client to make UDP contact first. - // It's the UDP contact that creates the scene presence ScenePresence sp = WaitGetScenePresence(agentID); + if (sp != null) { PresenceService.LogoutAgent(sp.ControllingClient.SessionId); CloseAgent(sp.UUID, false); } - else - { - m_log.WarnFormat("[SCENE]: Could not find scene presence for {0}", agentID); - } + // BANG! SLASH! m_authenticateHandler.RemoveCircuit(agentID); @@ -3183,7 +3255,7 @@ namespace OpenSim.Region.Framework.Scenes public virtual void SubscribeToClientTerrainEvents(IClientAPI client) { - client.OnRegionHandShakeReply += SendLayerData; +// client.OnRegionHandShakeReply += SendLayerData; } public virtual void SubscribeToClientPrimEvents(IClientAPI client) @@ -3191,6 +3263,8 @@ namespace OpenSim.Region.Framework.Scenes client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimGroupPosition; client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition; + client.onClientChangeObject += m_sceneGraph.ClientChangeObject; + client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation; @@ -3204,9 +3278,6 @@ namespace OpenSim.Region.Framework.Scenes client.OnObjectRequest += RequestPrim; client.OnObjectSelect += SelectPrim; client.OnObjectDeselect += DeselectPrim; - client.OnGrabUpdate += m_sceneGraph.MoveObject; - client.OnSpinStart += m_sceneGraph.SpinStart; - client.OnSpinUpdate += m_sceneGraph.SpinObject; client.OnDeRezObject += DeRezObjects; client.OnObjectName += m_sceneGraph.PrimName; @@ -3222,6 +3293,9 @@ namespace OpenSim.Region.Framework.Scenes client.OnGrabObject += ProcessObjectGrab; client.OnGrabUpdate += ProcessObjectGrabUpdate; client.OnDeGrabObject += ProcessObjectDeGrab; + client.OnSpinStart += ProcessSpinStart; + client.OnSpinUpdate += ProcessSpinObject; + client.OnSpinStop += ProcessSpinObjectStop; client.OnUndo += m_sceneGraph.HandleUndo; client.OnRedo += m_sceneGraph.HandleRedo; client.OnObjectDescription += m_sceneGraph.PrimDescription; @@ -3247,6 +3321,7 @@ namespace OpenSim.Region.Framework.Scenes client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory; client.OnUpdateInventoryItem += UpdateInventoryItemAsset; client.OnCopyInventoryItem += CopyInventoryItem; + client.OnMoveItemsAndLeaveCopy += MoveInventoryItemsLeaveCopy; client.OnMoveInventoryItem += MoveInventoryItem; client.OnRemoveInventoryItem += RemoveInventoryItem; client.OnRemoveInventoryFolder += RemoveInventoryFolder; @@ -3308,7 +3383,7 @@ namespace OpenSim.Region.Framework.Scenes public virtual void UnSubscribeToClientTerrainEvents(IClientAPI client) { - client.OnRegionHandShakeReply -= SendLayerData; +// client.OnRegionHandShakeReply -= SendLayerData; } public virtual void UnSubscribeToClientPrimEvents(IClientAPI client) @@ -3316,6 +3391,8 @@ namespace OpenSim.Region.Framework.Scenes client.OnUpdatePrimGroupPosition -= m_sceneGraph.UpdatePrimGroupPosition; client.OnUpdatePrimSinglePosition -= m_sceneGraph.UpdatePrimSinglePosition; + client.onClientChangeObject -= m_sceneGraph.ClientChangeObject; + client.OnUpdatePrimGroupRotation -= m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimGroupMouseRotation -= m_sceneGraph.UpdatePrimGroupRotation; client.OnUpdatePrimSingleRotation -= m_sceneGraph.UpdatePrimSingleRotation; @@ -3329,9 +3406,6 @@ namespace OpenSim.Region.Framework.Scenes client.OnObjectRequest -= RequestPrim; client.OnObjectSelect -= SelectPrim; client.OnObjectDeselect -= DeselectPrim; - client.OnGrabUpdate -= m_sceneGraph.MoveObject; - client.OnSpinStart -= m_sceneGraph.SpinStart; - client.OnSpinUpdate -= m_sceneGraph.SpinObject; client.OnDeRezObject -= DeRezObjects; client.OnObjectName -= m_sceneGraph.PrimName; client.OnObjectClickAction -= m_sceneGraph.PrimClickAction; @@ -3344,7 +3418,11 @@ namespace OpenSim.Region.Framework.Scenes client.OnRequestObjectPropertiesFamily -= m_sceneGraph.RequestObjectPropertiesFamily; client.OnObjectPermissions -= HandleObjectPermissionsUpdate; client.OnGrabObject -= ProcessObjectGrab; + client.OnGrabUpdate -= ProcessObjectGrabUpdate; client.OnDeGrabObject -= ProcessObjectDeGrab; + client.OnSpinStart -= ProcessSpinStart; + client.OnSpinUpdate -= ProcessSpinObject; + client.OnSpinStop -= ProcessSpinObjectStop; client.OnUndo -= m_sceneGraph.HandleUndo; client.OnRedo -= m_sceneGraph.HandleRedo; client.OnObjectDescription -= m_sceneGraph.PrimDescription; @@ -3440,13 +3518,15 @@ namespace OpenSim.Region.Framework.Scenes /// Group of new object public void DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID) { - SceneObjectGroup copy = SceneGraph.DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Identity); + bool createSelected = (flags & (uint)PrimFlags.CreateSelected) != 0; + SceneObjectGroup copy = SceneGraph.DuplicateObject(originalPrim, offset, AgentID, + GroupID, Quaternion.Identity, createSelected); if (copy != null) EventManager.TriggerObjectAddedToScene(copy); } /// - /// Duplicates object specified by localID at position raycasted against RayTargetObject using + /// Duplicates object specified by localID at position raycasted against RayTargetObject using /// RayEnd and RayStart to determine what the angle of the ray is /// /// ID of object to duplicate @@ -3470,11 +3550,11 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart target = GetSceneObjectPart(localID); SceneObjectPart target2 = GetSceneObjectPart(RayTargetObj); + bool createSelected = (dupeFlags & (uint)PrimFlags.CreateSelected) != 0; + if (target != null && target2 != null) { Vector3 direction = Vector3.Normalize(RayEnd - RayStart); - Vector3 AXOrigin = RayStart; - Vector3 AXdirection = direction; pos = target2.AbsolutePosition; //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString()); @@ -3482,7 +3562,7 @@ namespace OpenSim.Region.Framework.Scenes // TODO: Raytrace better here //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection)); - Ray NewRay = new Ray(AXOrigin, AXdirection); + Ray NewRay = new Ray(RayStart,direction); // Ray Trace against target here EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters); @@ -3513,13 +3593,13 @@ namespace OpenSim.Region.Framework.Scenes Quaternion worldRot = target2.GetWorldRotation(); // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); - copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot); + copy = m_sceneGraph.DuplicateObject(localID, pos, AgentID, GroupID, worldRot, createSelected); //obj.Rotation = worldRot; //obj.UpdateGroupRotationR(worldRot); } else { - copy = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, Quaternion.Identity); + copy = m_sceneGraph.DuplicateObject(localID, pos, AgentID, GroupID, Quaternion.Identity, createSelected); } if (copy != null) @@ -3553,7 +3633,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Remove the given client from the scene. + /// Remove the given client from the scene. /// /// /// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead @@ -3564,11 +3644,15 @@ namespace OpenSim.Region.Framework.Scenes /// /// Close the neighbour child agents associated with this client. /// + /// + + private object m_removeClientPrivLock = new Object(); + public void RemoveClient(UUID agentID, bool closeChildAgents) { AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID); - // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which + // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not // However, will keep for now just in case. if (acd == null) @@ -3580,13 +3664,13 @@ namespace OpenSim.Region.Framework.Scenes } // TODO: Can we now remove this lock? - lock (acd) + lock (m_removeClientPrivLock) { bool isChildAgent = false; ScenePresence avatar = GetScenePresence(agentID); - // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which + // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not // However, will keep for now just in case. if (avatar == null) @@ -3625,7 +3709,7 @@ namespace OpenSim.Region.Framework.Scenes // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI if (closeChildAgents && CapsModule != null) - CapsModule.RemoveCaps(agentID); + CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode); if (closeChildAgents && !isChildAgent) { @@ -3637,13 +3721,17 @@ namespace OpenSim.Region.Framework.Scenes } m_eventManager.TriggerClientClosed(agentID, this); +// m_log.Debug("[Scene]TriggerClientClosed done"); m_eventManager.TriggerOnRemovePresence(agentID); +// m_log.Debug("[Scene]TriggerOnRemovePresence done"); if (!isChildAgent) { if (AttachmentsModule != null) { +// m_log.Debug("[Scene]DeRezAttachments"); AttachmentsModule.DeRezAttachments(avatar); +// m_log.Debug("[Scene]DeRezAttachments done"); } ForEachClient( @@ -3657,7 +3745,11 @@ namespace OpenSim.Region.Framework.Scenes // It's possible for child agents to have transactions if changes are being made cross-border. if (AgentTransactionsModule != null) + { +// m_log.Debug("[Scene]RemoveAgentAssetTransactions"); AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); + } + m_log.Debug("[Scene] The avatar has left the building"); } catch (Exception e) { @@ -3691,7 +3783,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Removes region from an avatar's known region list. This coincides with child agents. For each child agent, there will be a known region entry. - /// + /// /// /// /// @@ -3721,15 +3813,9 @@ namespace OpenSim.Region.Framework.Scenes foreach (uint localID in localIDs) { SceneObjectPart part = GetSceneObjectPart(localID); - if (part != null) // It is a prim - { - if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid - { - if (part.ParentGroup.RootPart != part) // Child part - continue; - } - } - deleteIDs.Add(localID); + if (part != null && part.ParentGroup != null && + part.ParentGroup.RootPart == part) + deleteIDs.Add(localID); } ForEachClient(c => c.SendKillObject(deleteIDs)); @@ -3746,7 +3832,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Source region (may be null) /// Outputs the reason for the false response on this string - /// True if the region accepts this agent. False if it does not. False will + /// True if the region accepts this agent. False if it does not. False will /// also return a reason. public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, GridRegion source, out string reason) { @@ -3774,14 +3860,17 @@ namespace OpenSim.Region.Framework.Scenes /// Outputs the reason for the false response on this string /// True for normal presence. False for NPC /// or other applications where a full grid/Hypergrid presence may not be required. - /// True if the region accepts this agent. False if it does not. False will + /// True if the region accepts this agent. False if it does not. False will /// also return a reason. + /// + private object m_newUserConnLock = new object(); + public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, GridRegion source, out string reason, bool requirePresenceLookup) { bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); bool viahome = ((teleportFlags & (uint)TPFlags.ViaHome) != 0); - bool godlike = ((teleportFlags & (uint)TPFlags.Godlike) != 0); +// bool godlike = ((teleportFlags & (uint)TPFlags.Godlike) != 0); reason = String.Empty; @@ -3809,9 +3898,11 @@ namespace OpenSim.Region.Framework.Scenes (source == null) ? "" : string.Format("From region {0} ({1}){2}", source.RegionName, source.RegionID, (source.RawServerURI == null) ? "" : " @ " + source.ServerURI) ); +// m_log.DebugFormat("NewUserConnection stack {0}", Environment.StackTrace); + if (!LoginsEnabled) { - reason = "Logins Disabled"; + reason = "Logins to this region are disabled"; return false; } @@ -3858,14 +3949,13 @@ namespace OpenSim.Region.Framework.Scenes return false; } - ILandObject land; ScenePresence sp; lock (m_removeClientLock) { sp = GetScenePresence(acd.AgentID); - // We need to ensure that we are not already removing the scene presence before we ask it not to be + // We need to ensure that we are not already removing the scene presence before we ask it not to be // closed. if (sp != null && sp.IsChildAgent && (sp.LifecycleState == ScenePresenceState.Running @@ -3879,16 +3969,16 @@ namespace OpenSim.Region.Framework.Scenes // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C // renews the lease on the child agent at B, we must make sure that the close from A does not succeed. // - // XXX: In the end, this should not be necessary if child agents are closed without delay on + // XXX: In the end, this should not be necessary if child agents are closed without delay on // teleport, since realistically, the close request should always be processed before any other - // region tried to re-establish a child agent. This is much simpler since the logic below is + // region tried to re-establish a child agent. This is much simpler since the logic below is // vulnerable to an issue when a viewer quits a region without sending a proper logout but then // re-establishes the connection on a relogin. This could wrongly set the DoNotCloseAfterTeleport // flag when no teleport had taken place (and hence no close was going to come). // if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle)) // { // m_log.DebugFormat( -// "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", +// "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", // sp.Name, Name); // // sp.DoNotCloseAfterTeleport = true; @@ -3902,7 +3992,7 @@ namespace OpenSim.Region.Framework.Scenes sp.DoNotCloseAfterTeleport = true; m_log.DebugFormat( - "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt end-of-teleport close from a previous close.", + "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt end-of-teleport close from a previous close.", sp.Name, Name); } } @@ -3922,7 +4012,7 @@ namespace OpenSim.Region.Framework.Scenes if (sp.LifecycleState == ScenePresenceState.Removing) { m_log.WarnFormat( - "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.", + "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.", sp.Name, Name, polls * pollInterval / 1000); return false; @@ -3936,14 +4026,14 @@ namespace OpenSim.Region.Framework.Scenes } // TODO: can we remove this lock? - lock (acd) + lock (m_newUserConnLock) { if (sp != null && !sp.IsChildAgent) { // We have a root agent. Is it in transit? if (!EntityTransferModule.IsInTransit(sp.UUID)) { - // We have a zombie from a crashed session. + // We have a zombie from a crashed session. // Or the same user is trying to be root twice here, won't work. // Kill it. m_log.WarnFormat( @@ -3963,20 +4053,21 @@ namespace OpenSim.Region.Framework.Scenes // We need the circuit data here for some of the subsequent checks. (groups, for example) // If the checks fail, we remove the circuit. acd.teleportFlags = teleportFlags; - m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd); - land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y); - - // On login test land permisions if (vialogin) { - if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y)) - { - m_authenticateHandler.RemoveCircuit(acd.circuitcode); - return false; - } + IUserAccountCacheModule cache = RequestModuleInterface(); + if (cache != null) +// cache.Remove(acd.firstname + " " + acd.lastname); + cache.Remove(acd.AgentID); + + // Remove any preexisting circuit - we don't want duplicates + // This is a stab at preventing avatar "ghosting" + m_authenticateHandler.RemoveCircuit(acd.AgentID); } + m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd); + if (sp == null) // We don't have an [child] agent here already { if (requirePresenceLookup) @@ -4024,7 +4115,7 @@ namespace OpenSim.Region.Framework.Scenes if (CapsModule != null) { CapsModule.SetAgentCapsSeeds(acd); - CapsModule.CreateCaps(acd.AgentID); + CapsModule.CreateCaps(acd.AgentID, acd.circuitcode); } } else @@ -4039,13 +4130,13 @@ namespace OpenSim.Region.Framework.Scenes "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", acd.AgentID, RegionInfo.RegionName); - sp.AdjustKnownSeeds(); - if (CapsModule != null) { CapsModule.SetAgentCapsSeeds(acd); - CapsModule.CreateCaps(acd.AgentID); + CapsModule.CreateCaps(acd.AgentID, acd.circuitcode); } + + sp.AdjustKnownSeeds(); } } @@ -4055,88 +4146,48 @@ namespace OpenSim.Region.Framework.Scenes CacheUserName(null, acd); } - if (vialogin) + if (CapsModule != null) { -// CleanDroppedAttachments(); - - // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking) - if (acd.startpos.X < 0) acd.startpos.X = 1f; - if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f; - if (acd.startpos.Y < 0) acd.startpos.Y = 1f; - if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f; - -// m_log.DebugFormat( -// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}", -// RegionInfo.RegionSettings.TelehubObject, acd.Name, Name); - - // Honor Estate teleport routing via Telehubs excluding ViaHome and GodLike TeleportFlags - if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && - RegionInfo.EstateSettings.AllowDirectTeleport == false && - !viahome && !godlike) - { - SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject); - - if (telehub != null) - { - // Can have multiple SpawnPoints - List spawnpoints = RegionInfo.RegionSettings.SpawnPoints(); - if (spawnpoints.Count > 1) - { - // We have multiple SpawnPoints, Route the agent to a random or sequential one - if (SpawnPointRouting == "random") - acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - else - acd.startpos = spawnpoints[SpawnPoint()].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - } - else if (spawnpoints.Count == 1) - { - // We have a single SpawnPoint and will route the agent to it - acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); - } - else - { - m_log.DebugFormat( - "[SCENE]: No spawnpoints defined for telehub {0} for {1} in {2}. Continuing.", - RegionInfo.RegionSettings.TelehubObject, acd.Name, Name); - } - } - else - { - m_log.DebugFormat( - "[SCENE]: No telehub {0} found to direct {1} in {2}. Continuing.", - RegionInfo.RegionSettings.TelehubObject, acd.Name, Name); - } + CapsModule.ActivateCaps(acd.circuitcode); + } - // Final permissions check; this time we don't allow changing the position - if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason)) - { - m_authenticateHandler.RemoveCircuit(acd.circuitcode); - return false; - } +// if (vialogin) +// { +// CleanDroppedAttachments(); +// } - return true; - } + if(teleportFlags != (uint) TPFlags.Default) + { + // Make sure root avatar position is in the region + if (acd.startpos.X < 0) + acd.startpos.X = 1f; + else if (acd.startpos.X >= RegionInfo.RegionSizeX) + acd.startpos.X = RegionInfo.RegionSizeX - 1f; + if (acd.startpos.Y < 0) + acd.startpos.Y = 1f; + else if (acd.startpos.Y >= RegionInfo.RegionSizeY) + acd.startpos.Y = RegionInfo.RegionSizeY - 1f; + } + // only check access, actual relocations will happen later on ScenePresence MakeRoot + // allow child agents creation +// if(!godlike && teleportFlags != (uint) TPFlags.Default) + if(teleportFlags != (uint) TPFlags.Default) + { + bool checkTeleHub; + + // don't check hubs if via home or via lure + if((teleportFlags & (uint) TPFlags.ViaHome) != 0 + || (teleportFlags & (uint) TPFlags.ViaLure) != 0) + checkTeleHub = false; + else + checkTeleHub = vialogin + || (TelehubAllowLandmarks == true ? false : ((teleportFlags & (uint)TPFlags.ViaLandmark) != 0 )) + || (teleportFlags & (uint) TPFlags.ViaLocation) != 0; - // Honor parcel landing type and position. - if (land != null) + if(!CheckLandPositionAccess(acd.AgentID, true, checkTeleHub, acd.startpos, out reason)) { - if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) - { - acd.startpos = land.LandData.UserLocation; - - // Final permissions check; this time we don't allow changing the position - if (!IsPositionAllowed(acd.AgentID, acd.startpos, ref reason)) - { - m_authenticateHandler.RemoveCircuit(acd.circuitcode); - return false; - } - } + m_authenticateHandler.RemoveCircuit(acd.circuitcode); + return false; } } @@ -4162,12 +4213,13 @@ namespace OpenSim.Region.Framework.Scenes { if (posX < 0) posX = 0; - else if (posX >= (float)RegionInfo.RegionSizeX) - posX = (float)RegionInfo.RegionSizeX - 0.001f; + + else if (posX >= RegionInfo.RegionSizeX) + posX = RegionInfo.RegionSizeX - 0.5f; if (posY < 0) posY = 0; - else if (posY >= (float)RegionInfo.RegionSizeY) - posY = (float)RegionInfo.RegionSizeY - 0.001f; + else if (posY >= RegionInfo.RegionSizeY) + posY = RegionInfo.RegionSizeY - 0.5f; reason = String.Empty; if (Permissions.IsGod(agentID)) @@ -4183,14 +4235,14 @@ namespace OpenSim.Region.Framework.Scenes if (banned || restricted) { ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY); + Vector2? newPosition = null; if (nearestParcel != null) { //Move agent to nearest allowed - Vector3 newPosition = GetParcelCenterAtGround(nearestParcel); - posX = newPosition.X; - posY = newPosition.Y; +// Vector2 newPosition = GetParcelSafeCorner(nearestParcel); + newPosition = nearestParcel.GetNearestPoint(new Vector3(posX, posY,0)); } - else + if(newPosition == null) { if (banned) { @@ -4203,6 +4255,11 @@ namespace OpenSim.Region.Framework.Scenes } return false; } + else + { + posX = newPosition.Value.X; + posY = newPosition.Value.Y; + } } reason = ""; return true; @@ -4213,7 +4270,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Circuit Data of the Agent we're verifying /// Outputs the reason for the false response on this string - /// True if the user has a session on the grid. False if it does not. False will + /// True if the user has a session on the grid. False if it does not. False will /// also return a reason. public virtual bool VerifyUserPresence(AgentCircuitData agent, out string reason) { @@ -4242,14 +4299,16 @@ namespace OpenSim.Region.Framework.Scenes /// /// The circuit data for the agent /// outputs the reason to this string - /// True if the region accepts this agent. False if it does not. False will + /// True if the region accepts this agent. False if it does not. False will /// also return a reason. protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason) { reason = String.Empty; - if (!m_strictAccessControl) return true; - if (Permissions.IsGod(agent.AgentID)) return true; + if (!m_strictAccessControl) + return true; + if (Permissions.IsGod(agent.AgentID)) + return true; if (AuthorizationService != null) { @@ -4269,98 +4328,85 @@ namespace OpenSim.Region.Framework.Scenes // the root is done elsewhere (QueryAccess) if (!bypassAccessControl) { - if (RegionInfo.EstateSettings != null) + if(RegionInfo.EstateSettings == null) { - if (RegionInfo.EstateSettings.IsBanned(agent.AgentID)) - { - m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", - agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); - reason = String.Format("Denied access to region {0}: You have been banned from that region.", - RegionInfo.RegionName); - return false; - } + // something is broken? let it get in + m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!"); + return true; } - else + + // check estate ban + int flags = GetUserFlags(agent.AgentID); + if (RegionInfo.EstateSettings.IsBanned(agent.AgentID, flags)) { - m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!"); + m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", + agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); + reason = String.Format("Denied access to region {0}: You have been banned from that region.", + RegionInfo.RegionName); + return false; } - List agentGroups = new List(); + // public access + if (RegionInfo.EstateSettings.PublicAccess) + return true; + + // in access list / owner / manager + if (RegionInfo.EstateSettings.HasAccess(agent.AgentID)) + return true; + + // finally test groups + bool groupAccess = false; + + // some say GOTO is ugly + if(m_groupsModule == null) // if no groups refuse + goto Label_GroupsDone; + + UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups; - if (m_groupsModule != null) + if(estateGroups == null) { - GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID); + m_log.ErrorFormat("[CONNECTION BEGIN]: Estate GroupMembership is null!"); + goto Label_GroupsDone; + } - if (GroupMembership != null) - { - for (int i = 0; i < GroupMembership.Length; i++) - agentGroups.Add(GroupMembership[i].GroupID); - } - else - { - m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!"); - } + if(estateGroups.Length == 0) + goto Label_GroupsDone; + + List agentGroups = new List(); + GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID); + + if(GroupMembership == null) + { + m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!"); + goto Label_GroupsDone; } - bool groupAccess = false; - UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups; + if(GroupMembership.Length == 0) + goto Label_GroupsDone; - if (estateGroups != null) + for(int i = 0;i < GroupMembership.Length;i++) + agentGroups.Add(GroupMembership[i].GroupID); + + foreach(UUID group in estateGroups) { - foreach (UUID group in estateGroups) + if(agentGroups.Contains(group)) { - if (agentGroups.Contains(group)) - { - groupAccess = true; - break; - } + groupAccess = true; + break; } } - else - { - m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!"); - } - if (!RegionInfo.EstateSettings.PublicAccess && - !RegionInfo.EstateSettings.HasAccess(agent.AgentID) && - !groupAccess) +Label_GroupsDone: + if (!groupAccess) { m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); - reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", - RegionInfo.RegionName); + reason = String.Format("Denied access to private region {0}: You do not have access to that region.", + RegionInfo.RegionName); return false; } } - // TODO: estate/region settings are not properly hooked up - // to ILandObject.isRestrictedFromLand() - // if (null != LandChannel) - // { - // // region seems to have local Id of 1 - // ILandObject land = LandChannel.GetLandObject(1); - // if (null != land) - // { - // if (land.isBannedFromLand(agent.AgentID)) - // { - // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user has been banned from land", - // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); - // reason = String.Format("Denied access to private region {0}: You are banned from that region.", - // RegionInfo.RegionName); - // return false; - // } - - // if (land.isRestrictedFromLand(agent.AgentID)) - // { - // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the region", - // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); - // reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", - // RegionInfo.RegionName); - // return false; - // } - // } - // } - return true; } @@ -4449,7 +4495,7 @@ namespace OpenSim.Region.Framework.Scenes // } /// - /// We've got an update about an agent that sees into this region, + /// We've got an update about an agent that sees into this region, /// send it to ScenePresence for processing It's the full data. /// /// Agent that contains all of the relevant things about an agent. @@ -4460,8 +4506,25 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat( "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); + if (!LoginsEnabled) + { +// reason = "Logins Disabled"; + m_log.DebugFormat( + "[SCENE]: update for {0} in {1} refused: Logins Disabled", cAgentData.AgentID, RegionInfo.RegionName); + return false; + } + // We have to wait until the viewer contacts this region after receiving EAC. + // That calls AddNewClient, which finally creates the ScenePresence + int flags = GetUserFlags(cAgentData.AgentID); + if (RegionInfo.EstateSettings.IsBanned(cAgentData.AgentID, flags)) + { + m_log.DebugFormat("[SCENE]: Denying root agent entry to {0}: banned", cAgentData.AgentID); + return false; + } + // TODO: This check should probably be in QueryAccess(). - ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, RegionInfo.RegionSizeX / 2, RegionInfo.RegionSizeY / 2); + ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, + (float)RegionInfo.RegionSizeX * 0.5f, (float)RegionInfo.RegionSizeY * 0.5f); if (nearestParcel == null) { m_log.InfoFormat( @@ -4472,20 +4535,26 @@ namespace OpenSim.Region.Framework.Scenes } // We have to wait until the viewer contacts this region - // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol) + // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol) // or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send // a UseCircuitCode packet which in turn calls AddNewAgent which finally creates the ScenePresence. ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID); if (sp != null) { + if (!sp.IsChildAgent) + { + m_log.WarnFormat("[SCENE]: Ignoring a child update on a root agent {0} {1} in {2}", + sp.Name, sp.UUID, Name); + return false; + } if (cAgentData.SessionID != sp.ControllingClient.SessionId) { m_log.WarnFormat( - "[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", + "[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", sp.UUID, cAgentData.SessionID); - Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}", + Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}", sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID)); } @@ -4517,7 +4586,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// We've got an update about an agent that sees into this region, + /// We've got an update about an agent that sees into this region, /// send it to ScenePresence for processing It's only positional data /// /// AgentPosition that contains agent positional data so we can know what to send @@ -4525,7 +4594,7 @@ namespace OpenSim.Region.Framework.Scenes public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData) { // m_log.DebugFormat( -// "[SCENE PRESENCE]: IncomingChildAgentDataUpdate POSITION for {0} in {1}, position {2}", +// "[SCENE PRESENCE]: IncomingChildAgentDataUpdate POSITION for {0} in {1}, position {2}", // cAgentData.AgentID, Name, cAgentData.Position); ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); @@ -4533,7 +4602,7 @@ namespace OpenSim.Region.Framework.Scenes { // if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID) // // Only warn for now -// m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", +// m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", // childAgentUpdate.UUID, cAgentData.SessionID); // I can't imagine *yet* why we would get an update if the agent is a root agent.. @@ -4563,10 +4632,10 @@ namespace OpenSim.Region.Framework.Scenes /// protected virtual ScenePresence WaitGetScenePresence(UUID agentID) { - int ntimes = 20; + int ntimes = 120; // 30s ScenePresence sp = null; while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0)) - Thread.Sleep(1000); + Thread.Sleep(250); if (sp == null) m_log.WarnFormat( @@ -4593,7 +4662,7 @@ namespace OpenSim.Region.Framework.Scenes if (acd == null) { m_log.DebugFormat( - "[SCENE]: Request to close agent {0} but no such agent in scene {1}. May have been closed previously.", + "[SCENE]: Request to close agent {0} but no such agent in scene {1}. May have been closed previously.", agentID, Name); return false; @@ -4606,13 +4675,23 @@ namespace OpenSim.Region.Framework.Scenes else { m_log.WarnFormat( - "[SCENE]: Request to close agent {0} with invalid authorization token {1} in {2}", + "[SCENE]: Request to close agent {0} with invalid authorization token {1} in {2}", agentID, auth_token, Name); } return false; } +// public bool IncomingCloseAgent(UUID agentID) +// { +// return IncomingCloseAgent(agentID, false); +// } + +// public bool IncomingCloseChildAgent(UUID agentID) +// { +// return IncomingCloseAgent(agentID, true); +// } + /// /// Tell a single client to prepare to close. /// @@ -4675,8 +4754,22 @@ namespace OpenSim.Region.Framework.Scenes if (sp == null) { + // If there is no scene presence, we may be handling a dead + // client. These can keep an avatar from reentering a region + // and since they don't get cleaned up they will stick + // around until region restart. So, if there is no SP, + // remove the client as well. + IClientAPI client = null; + if (m_clientManager.TryGetValue(agentID, out client)) + { + m_clientManager.Remove(agentID); + if (CapsModule != null) + CapsModule.RemoveCaps(agentID, 0); + m_log.DebugFormat( "[SCENE]: Dead client for agent ID {0} was cleaned up in {1}", agentID, Name); + return true; + } m_log.DebugFormat( - "[SCENE]: Called CloseClient() with agent ID {0} but no such presence is in {1}", + "[SCENE]: Called CloseClient() with agent ID {0} but no such presence is in {1}", agentID, Name); return false; @@ -4709,7 +4802,11 @@ namespace OpenSim.Region.Framework.Scenes sp.LifecycleState = ScenePresenceState.Removing; } - sp.ControllingClient.Close(force); + if (sp != null) + { + sp.ControllingClient.Close(force, force); + return true; + } return true; } @@ -4728,16 +4825,34 @@ namespace OpenSim.Region.Framework.Scenes public void RequestTeleportLocation(IClientAPI remoteClient, string regionName, Vector3 position, Vector3 lookat, uint teleportFlags) { - GridRegion region = GridService.GetRegionByName(RegionInfo.ScopeID, regionName); + if (EntityTransferModule == null) + { + m_log.DebugFormat("[SCENE]: Unable to perform teleports: no AgentTransferModule is active"); + return; + } + + ScenePresence sp = GetScenePresence(remoteClient.AgentId); + if (sp == null || sp.IsDeleted || sp.IsInTransit) + return; + + ulong regionHandle = 0; + if(regionName == RegionInfo.RegionName) + regionHandle = RegionInfo.RegionHandle; + else + { + GridRegion region = GridService.GetRegionByName(RegionInfo.ScopeID, regionName); + if (region != null) + regionHandle = region.RegionHandle; + } - if (region == null) + if(regionHandle == 0) { // can't find the region: Tell viewer and abort remoteClient.SendTeleportFailed("The region '" + regionName + "' could not be found."); return; } - RequestTeleportLocation(remoteClient, region.RegionHandle, position, lookat, teleportFlags); + EntityTransferModule.Teleport(sp, regionHandle, position, lookat, teleportFlags); } /// @@ -4751,19 +4866,17 @@ namespace OpenSim.Region.Framework.Scenes public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { - ScenePresence sp = GetScenePresence(remoteClient.AgentId); - if (sp != null) + if (EntityTransferModule == null) { - if (EntityTransferModule != null) - { - EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); - } - else - { - m_log.DebugFormat("[SCENE]: Unable to perform teleports: no AgentTransferModule is active"); - sp.ControllingClient.SendTeleportFailed("Unable to perform teleports on this simulator."); - } + m_log.DebugFormat("[SCENE]: Unable to perform teleports: no AgentTransferModule is active"); + return; } + + ScenePresence sp = GetScenePresence(remoteClient.AgentId); + if (sp == null || sp.IsDeleted || sp.IsInTransit) + return; + + EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); } public bool CrossAgentToNewRegion(ScenePresence agent, bool isFlying) @@ -4871,7 +4984,10 @@ namespace OpenSim.Region.Framework.Scenes public LandData GetLandData(float x, float y) { - return LandChannel.GetLandObject(x, y).LandData; + ILandObject parcel = LandChannel.GetLandObject(x, y); + if (parcel == null) + return null; + return parcel.LandData; } /// @@ -4886,72 +5002,69 @@ namespace OpenSim.Region.Framework.Scenes public LandData GetLandData(uint x, uint y) { - m_log.DebugFormat("[SCENE]: returning land for {0},{1}", x, y); - return LandChannel.GetLandObject((int)x, (int)y).LandData; +// m_log.DebugFormat("[SCENE]: returning land for {0},{1}", x, y); + ILandObject parcel = LandChannel.GetLandObject((int)x, (int)y); + if (parcel == null) + return null; + return parcel.LandData; } #endregion #region Script Engine - - private bool ScriptDanger(SceneObjectPart part, Vector3 pos) + public bool LSLScriptDanger(SceneObjectPart part, Vector3 pos) { + ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y); - if (part != null) - { - if (parcel != null) - { - if ((parcel.LandData.Flags & (uint)ParcelFlags.AllowOtherScripts) != 0) - { - return true; - } - else if ((part.OwnerID == parcel.LandData.OwnerID) || Permissions.IsGod(part.OwnerID)) - { - return true; - } - else if (((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0) - && (parcel.LandData.GroupID != UUID.Zero) && (parcel.LandData.GroupID == part.GroupID)) - { - return true; - } - else - { - return false; - } - } - else - { + if (parcel == null) + return true; + + LandData ldata = parcel.LandData; + if (ldata == null) + return true; + + uint landflags = ldata.Flags; + + uint mask = (uint)(ParcelFlags.CreateObjects | ParcelFlags.AllowAPrimitiveEntry); + if((landflags & mask) != mask) + return true; + + if((landflags & (uint)ParcelFlags.AllowOtherScripts) != 0) + return false; - if (pos.X > 0f && pos.X < RegionInfo.RegionSizeX && pos.Y > 0f && pos.Y < RegionInfo.RegionSizeY) - { - // The only time parcel != null when an object is inside a region is when - // there is nothing behind the landchannel. IE, no land plugin loaded. - return true; - } - else - { - // The object is outside of this region. Stop piping events to it. - return false; - } - } - } - else - { + if(part == null) + return true; + if(part.GroupID == ldata.GroupID && (landflags & (uint)ParcelFlags.AllowGroupScripts) != 0) return false; - } + + return true; } - public bool ScriptDanger(uint localID, Vector3 pos) + private bool ScriptDanger(SceneObjectPart part, Vector3 pos) { - SceneObjectPart part = GetSceneObjectPart(localID); - if (part != null) + if (part == null) + return false; + + ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y); + if (parcel != null) { - return ScriptDanger(part, pos); + if ((parcel.LandData.Flags & (uint)ParcelFlags.AllowOtherScripts) != 0) + return true; + + if ((part.OwnerID == parcel.LandData.OwnerID) || Permissions.IsGod(part.OwnerID)) + return true; + + if (((parcel.LandData.Flags & (uint)ParcelFlags.AllowGroupScripts) != 0) + && (parcel.LandData.GroupID != UUID.Zero) && (parcel.LandData.GroupID == part.GroupID)) + return true; } else { - return false; + if (pos.X > 0f && pos.X < RegionInfo.RegionSizeX && pos.Y > 0f && pos.Y < RegionInfo.RegionSizeY) + return true; } + + return false; } public bool PipeEventsForScript(uint localID) @@ -5177,7 +5290,7 @@ namespace OpenSim.Region.Framework.Scenes /// Get a scene object group that contains the prim with the given local id /// /// - /// null if no scene object group containing that prim is found + /// null if no scene object group containing that prim is found public SceneObjectGroup GetGroupByPrim(uint localID) { return m_sceneGraph.GetGroupByPrim(localID); @@ -5187,7 +5300,7 @@ namespace OpenSim.Region.Framework.Scenes /// Get a scene object group that contains the prim with the given uuid /// /// - /// null if no scene object group containing that prim is found + /// null if no scene object group containing that prim is found public SceneObjectGroup GetGroupByPrim(UUID fullID) { return m_sceneGraph.GetGroupByPrim(fullID); @@ -5221,7 +5334,12 @@ namespace OpenSim.Region.Framework.Scenes /// public void ForEachClient(Action action) { - m_clientManager.ForEachSync(action); + m_clientManager.ForEach(action); + } + + public int GetNumberOfClients() + { + return m_clientManager.Count; } public bool TryGetClient(UUID avatarID, out IClientAPI client) @@ -5264,6 +5382,7 @@ namespace OpenSim.Region.Framework.Scenes public void CleanTempObjects() { + DateTime now = DateTime.UtcNow; EntityBase[] entities = GetEntities(); foreach (EntityBase obj in entities) { @@ -5275,13 +5394,12 @@ namespace OpenSim.Region.Framework.Scenes { if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) { - if (grp.RootPart.Expires <= DateTime.Now) + if (grp.GetSittingAvatarsCount() == 0 && grp.RootPart.Expires <= now) DeleteSceneObject(grp, false); } } } } - } public void DeleteFromStorage(UUID uuid) @@ -5289,7 +5407,7 @@ namespace OpenSim.Region.Framework.Scenes SimulationDataService.RemoveObject(uuid, RegionInfo.RegionID); } - public int GetHealth() + public int GetHealth(out int flags, out string message) { // Returns: // 1 = sim is up and accepting http requests. The heartbeat has @@ -5297,27 +5415,74 @@ namespace OpenSim.Region.Framework.Scenes // admin restart may succeed // // 2 = Sim is up and the heartbeat is running. The sim is likely - // usable for people within and logins _may_ work + // usable for people within + // + // 3 = Sim is up and one packet thread is running. Sim is + // unstable and will not accept new logins // - // 3 = We have seen a new user enter within the past 4 minutes + // 4 = Sim is up and both packet threads are running. Sim is + // likely usable + // + // 5 = We have seen a new user enter within the past 4 minutes // which can be seen as positive confirmation of sim health // int health = 1; // Start at 1, means we're up - if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 1000) - health += 1; + flags = 0; + message = String.Empty; + + CheckHeartbeat(); + + if (m_firstHeartbeat || (m_lastIncoming == 0 && m_lastOutgoing == 0)) + { + // We're still starting + // 0 means "in startup", it can't happen another way, since + // to get here, we must be able to accept http connections + return 0; + } + + if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) < 2000) + { + health+=1; + flags |= 1; + } + + if (Util.EnvironmentTickCountSubtract(m_lastIncoming) < 2000) + { + health+=1; + flags |= 2; + } + + if (Util.EnvironmentTickCountSubtract(m_lastOutgoing) < 2000) + { + health+=1; + flags |= 4; + } + /* else + { +int pid = System.Diagnostics.Process.GetCurrentProcess().Id; +System.Diagnostics.Process proc = new System.Diagnostics.Process(); +proc.EnableRaisingEvents=false; +proc.StartInfo.FileName = "/bin/kill"; +proc.StartInfo.Arguments = "-QUIT " + pid.ToString(); +proc.Start(); +proc.WaitForExit(); +Thread.Sleep(1000); +Environment.Exit(1); + } + */ + + if (flags != 7) return health; // A login in the last 4 mins? We can't be doing too badly // - if ((Util.EnvironmentTickCountSubtract(m_LastLogin)) < 240000) + if (Util.EnvironmentTickCountSubtract(m_LastLogin) < 240000) health++; else return health; -// CheckHeartbeat(); - return health; } @@ -5405,7 +5570,7 @@ namespace OpenSim.Region.Framework.Scenes bool wasUsingPhysics = ((jointProxyObject.Flags & PrimFlags.Physics) != 0); if (wasUsingPhysics) { - jointProxyObject.UpdatePrimFlags(false, false, true, false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock + jointProxyObject.UpdatePrimFlags(false, false, true, false,false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock } } @@ -5508,14 +5673,14 @@ namespace OpenSim.Region.Framework.Scenes return (((vsn.X * xdiff) + (vsn.Y * ydiff)) / (-1 * vsn.Z)) + p0.Z; } -// private void CheckHeartbeat() -// { -// if (m_firstHeartbeat) -// return; -// -// if (Util.EnvironmentTickCountSubtract(m_lastFrameTick) > 2000) -// StartTimer(); -// } + private void CheckHeartbeat() + { + if (m_firstHeartbeat) + return; + + if ((Util.EnvironmentTickCountSubtract(m_lastFrameTick)) > 5000) + Start(); + } public override ISceneObject DeserializeObject(string representation) { @@ -5534,27 +5699,26 @@ namespace OpenSim.Region.Framework.Scenes public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel) { - ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel); + Vector3 pos = avatar.AbsolutePosition; + + ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, pos.X, pos.Y, excludeParcel); if (nearestParcel != null) { - Vector3 dir = Vector3.Normalize(Vector3.Multiply(avatar.Velocity, -1)); - //Try to get a location that feels like where they came from - Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); - if (nearestPoint != null) - { - m_log.Debug("Found a sane previous position based on velocity, sending them to: " + nearestPoint.ToString()); - return nearestPoint.Value; - } + Vector2? nearestPoint = null; + Vector3 dir = -avatar.Velocity; + float dirlen = dir.Length(); + if(dirlen > 1.0f) + //Try to get a location that feels like where they came from + nearestPoint = nearestParcel.GetNearestPointAlongDirection(pos, dir); + + if (nearestPoint == null) + nearestPoint = nearestParcel.GetNearestPoint(pos); - //Sometimes velocity might be zero (local teleport), so try finding point along path from avatar to center of nearest parcel - Vector3 directionToParcelCenter = Vector3.Subtract(GetParcelCenterAtGround(nearestParcel), avatar.AbsolutePosition); - dir = Vector3.Normalize(directionToParcelCenter); - nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); if (nearestPoint != null) { - m_log.Debug("They had a zero velocity, sending them to: " + nearestPoint.ToString()); - return nearestPoint.Value; + return GetPositionAtAvatarHeightOrGroundHeight(avatar, + nearestPoint.Value.X, nearestPoint.Value.Y); } ILandObject dest = LandChannel.GetLandObject(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y); @@ -5572,32 +5736,16 @@ namespace OpenSim.Region.Framework.Scenes //Go to the edge, this happens in teleporting to a region with no available parcels Vector3 nearestRegionEdgePoint = GetNearestRegionEdgePosition(avatar); - //m_log.Debug("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString()); - + //Debug.WriteLine("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString()); return nearestRegionEdgePoint; } private Vector3 GetParcelCenterAtGround(ILandObject parcel) { - Vector2 center = GetParcelCenter(parcel); + Vector2 center = parcel.CenterPoint; return GetPositionAtGround(center.X, center.Y); } - private Vector3? GetNearestPointInParcelAlongDirectionFromPoint(Vector3 pos, Vector3 direction, ILandObject parcel) - { - Vector3 unitDirection = Vector3.Normalize(direction); - //Making distance to search go through some sane limit of distance - for (float distance = 0; distance < Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY) * 2; distance += .5f) - { - Vector3 testPos = Vector3.Add(pos, Vector3.Multiply(unitDirection, distance)); - if (parcel.ContainsPoint((int)testPos.X, (int)testPos.Y)) - { - return testPos; - } - } - return null; - } - public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y) { return GetNearestAllowedParcel(avatarId, x, y, null); @@ -5605,18 +5753,30 @@ namespace OpenSim.Region.Framework.Scenes public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel) { - List all = AllParcels(); - float minParcelDistance = float.MaxValue; + if(LandChannel == null) + return null; + + List all = LandChannel.AllParcels(); + + if(all == null || all.Count == 0) + return null; + + float minParcelDistanceSQ = float.MaxValue; ILandObject nearestParcel = null; + Vector2 curCenter; + float parcelDistanceSQ; foreach (var parcel in all) { - if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel) + if (parcel != excludeParcel && !parcel.IsEitherBannedOrRestricted(avatarId)) { - float parcelDistance = GetParcelDistancefromPoint(parcel, x, y); - if (parcelDistance < minParcelDistance) + curCenter = parcel.CenterPoint; + curCenter.X -= x; + curCenter.Y -= y; + parcelDistanceSQ = curCenter.LengthSquared(); + if (parcelDistanceSQ < minParcelDistanceSQ) { - minParcelDistance = parcelDistance; + minParcelDistanceSQ = parcelDistanceSQ; nearestParcel = parcel; } } @@ -5625,82 +5785,52 @@ namespace OpenSim.Region.Framework.Scenes return nearestParcel; } - private List AllParcels() - { - return LandChannel.AllParcels(); - } - - private float GetParcelDistancefromPoint(ILandObject parcel, float x, float y) - { - return Vector2.Distance(new Vector2(x, y), GetParcelCenter(parcel)); - } - - //calculate the average center point of a parcel - private Vector2 GetParcelCenter(ILandObject parcel) + private Vector2 GetParcelSafeCorner(ILandObject parcel) { - int count = 0; - int avgx = 0; - int avgy = 0; - for (int x = 0; x < RegionInfo.RegionSizeX; x++) - { - for (int y = 0; y < RegionInfo.RegionSizeY; y++) - { - //Just keep a running average as we check if all the points are inside or not - if (parcel.ContainsPoint(x, y)) - { - if (count == 0) - { - avgx = x; - avgy = y; - } - else - { - avgx = (avgx * count + x) / (count + 1); - avgy = (avgy * count + y) / (count + 1); - } - count += 1; - } - } - } - return new Vector2(avgx, avgy); + Vector2 place = parcel.StartPoint; + place.X += 2f; + place.Y += 2f; + return place; } private Vector3 GetNearestRegionEdgePosition(ScenePresence avatar) { - float xdistance = avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2 - ? avatar.AbsolutePosition.X : RegionInfo.RegionSizeX - avatar.AbsolutePosition.X; - float ydistance = avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2 - ? avatar.AbsolutePosition.Y : RegionInfo.RegionSizeY - avatar.AbsolutePosition.Y; + float posX = avatar.AbsolutePosition.X; + float posY = avatar.AbsolutePosition.Y; + float regionSizeX = RegionInfo.RegionSizeX; + float halfRegionSizeX = regionSizeX * 0.5f; + float regionSizeY = RegionInfo.RegionSizeY; + float halfRegionSizeY = regionSizeY * 0.5f; + + float xdistance = posX < halfRegionSizeX ? posX : regionSizeX - posX; + float ydistance = posY < halfRegionSizeY ? posY : regionSizeY - posY; //find out what vertical edge to go to if (xdistance < ydistance) { - if (avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2) - { - return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.0f, avatar.AbsolutePosition.Y); - } + if (posX < halfRegionSizeX) + return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.5f, posY); else - { - return GetPositionAtAvatarHeightOrGroundHeight(avatar, RegionInfo.RegionSizeY, avatar.AbsolutePosition.Y); - } + return GetPositionAtAvatarHeightOrGroundHeight(avatar, regionSizeX - 0.5f, posY); } //find out what horizontal edge to go to else { - if (avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2) - { - return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, 0.0f); - } + if (posY < halfRegionSizeY) + return GetPositionAtAvatarHeightOrGroundHeight(avatar, posX, 0.5f); else - { - return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, RegionInfo.RegionSizeY); - } + return GetPositionAtAvatarHeightOrGroundHeight(avatar, posX, regionSizeY - 0.5f); } } private Vector3 GetPositionAtAvatarHeightOrGroundHeight(ScenePresence avatar, float x, float y) { Vector3 ground = GetPositionAtGround(x, y); + if(avatar.Appearance != null) + ground.Z += avatar.Appearance.AvatarHeight * 0.5f; + else + ground.Z += 0.8f; + if (avatar.AbsolutePosition.Z > ground.Z) { ground.Z = avatar.AbsolutePosition.Z; @@ -5780,7 +5910,7 @@ namespace OpenSim.Region.Framework.Scenes g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); // m_log.DebugFormat( -// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}", +// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}", // g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ)); ominX += vec.X; @@ -5829,7 +5959,55 @@ namespace OpenSim.Region.Framework.Scenes mapModule.GenerateMaptile(); } - private void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e) +// public void CleanDroppedAttachments() +// { +// List objectsToDelete = +// new List(); +// +// lock (m_cleaningAttachments) +// { +// ForEachSOG(delegate (SceneObjectGroup grp) +// { +// if (grp.RootPart.Shape.PCode == 0 && grp.RootPart.Shape.State != 0 && (!objectsToDelete.Contains(grp))) +// { +// UUID agentID = grp.OwnerID; +// if (agentID == UUID.Zero) +// { +// objectsToDelete.Add(grp); +// return; +// } +// +// ScenePresence sp = GetScenePresence(agentID); +// if (sp == null) +// { +// objectsToDelete.Add(grp); +// return; +// } +// } +// }); +// } +// +// foreach (SceneObjectGroup grp in objectsToDelete) +// { +// m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID); +// DeleteSceneObject(grp, true); +// } +// } + + public void ThreadAlive(int threadCode) + { + switch(threadCode) + { + case 1: // Incoming + m_lastIncoming = Util.EnvironmentTickCount(); + break; + case 2: // Incoming + m_lastOutgoing = Util.EnvironmentTickCount(); + break; + } + } + + public void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e) { RegenerateMaptile(); @@ -5861,13 +6039,16 @@ namespace OpenSim.Region.Framework.Scenes reason = string.Empty; if (Permissions.IsGod(agentID)) - { - reason = String.Empty; return true; - } if (!AllowAvatarCrossing && !viaTeleport) + { + reason = "Region Crossing not allowed"; return false; + } + + bool isAdmin = Permissions.IsAdministrator(agentID); + bool isManager = Permissions.IsEstateManager(agentID); // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check. // However, the long term fix is to make sure root agent count is always accurate. @@ -5877,7 +6058,7 @@ namespace OpenSim.Region.Framework.Scenes if (num >= RegionInfo.RegionSettings.AgentLimit) { - if (!Permissions.IsAdministrator(agentID)) + if (!(isAdmin || isManager)) { reason = "The region is full"; @@ -5915,6 +6096,7 @@ namespace OpenSim.Region.Framework.Scenes if (!AuthorizeUser(aCircuit, false, out reason)) { //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); +// reason = "Region authorization fail"; return false; } } @@ -5925,52 +6107,101 @@ namespace OpenSim.Region.Framework.Scenes return false; } - if (viaTeleport) + // last check aditional land access restrictions and relocations + // if crossing (viaTeleport false) check only the specified parcel + return CheckLandPositionAccess(agentID, viaTeleport, true, position, out reason); + } + + // check access to land. + public bool CheckLandPositionAccess(UUID agentID, bool NotCrossing, bool checkTeleHub, Vector3 position, out string reason) + { + reason = string.Empty; + + if (Permissions.IsGod(agentID)) + return true; + + // Permissions.IsAdministrator is the same as IsGod for now +// bool isAdmin = Permissions.IsAdministrator(agentID); +// if(isAdmin) +// return true; + + // also honor estate managers access rights + bool isManager = Permissions.IsEstateManager(agentID); + if(isManager) + return true; + + if (NotCrossing) { if (!RegionInfo.EstateSettings.AllowDirectTeleport) { SceneObjectGroup telehub; - if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject)) != null) + if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = GetSceneObjectGroup (RegionInfo.RegionSettings.TelehubObject)) != null && checkTeleHub) { - List spawnPoints = RegionInfo.RegionSettings.SpawnPoints(); bool banned = true; - foreach (SpawnPoint sp in spawnPoints) + bool validTelehub = false; + List spawnPoints = RegionInfo.RegionSettings.SpawnPoints(); + Vector3 spawnPoint; + ILandObject land = null; + Vector3 telehubPosition = telehub.AbsolutePosition; + + if(spawnPoints.Count == 0) + { + // will this ever happen? + // if so use the telehub object position + spawnPoint = telehubPosition; + land = LandChannel.GetLandObject(spawnPoint.X, spawnPoint.Y); + if(land != null && !land.IsEitherBannedOrRestricted(agentID)) + { + banned = false; + validTelehub = true; + } + } + else { - Vector3 spawnPoint = sp.GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); - ILandObject land = LandChannel.GetLandObject(spawnPoint.X, spawnPoint.Y); - if (land == null) - continue; - if (land.IsEitherBannedOrRestricted(agentID)) - continue; - banned = false; - break; + Quaternion telehubRotation = telehub.GroupRotation; + foreach (SpawnPoint spawn in spawnPoints) + { + spawnPoint = spawn.GetLocation(telehubPosition, telehubRotation); + land = LandChannel.GetLandObject(spawnPoint.X, spawnPoint.Y); + if (land == null) + continue; + validTelehub = true; + if (!land.IsEitherBannedOrRestricted(agentID)) + { + banned = false; + break; + } + } } - if (banned) + if(validTelehub) { - if (Permissions.IsAdministrator(agentID) == false || Permissions.IsGridGod(agentID) == false) + if (banned) { reason = "No suitable landing point found"; return false; } - reason = "Administrative access only"; - return true; + else + return true; } + // possible broken telehub, fall into normal check } } - float posX = 128.0f; - float posY = 128.0f; + float posX = position.X; + float posY = position.Y; + // allow position relocation if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY)) { // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID); - reason = "You are banned from the region on all parcels"; + reason = "You dont have access to the region parcels"; return false; } } - else // Walking + else // check for query region crossing only { + // no relocation allowed on crossings ILandObject land = LandChannel.GetLandObject(position.X, position.Y); if (land == null) { @@ -5991,11 +6222,48 @@ namespace OpenSim.Region.Framework.Scenes } } - reason = String.Empty; return true; } - /// + public void StartTimerWatchdog() + { + m_timerWatchdog.Interval = 1000; + m_timerWatchdog.Elapsed += TimerWatchdog; + m_timerWatchdog.AutoReset = true; + m_timerWatchdog.Start(); + } + + public void TimerWatchdog(object sender, ElapsedEventArgs e) + { + CheckHeartbeat(); + + IEtcdModule etcd = RequestModuleInterface(); + int flags; + string message; + if (etcd != null) + { + int health = GetHealth(out flags, out message); + if (health != m_lastHealth) + { + m_lastHealth = health; + + etcd.Store("Health", health.ToString(), 300000); + etcd.Store("HealthFlags", flags.ToString(), 300000); + } + + int roots = 0; + foreach (ScenePresence sp in GetScenePresences()) + if (!sp.IsChildAgent && !sp.IsNPC) + roots++; + + if (m_lastUsers != roots) + { + m_lastUsers = roots; + etcd.Store("RootAgents", roots.ToString(), 300000); + } + } + } + /// This method deals with movement when an avatar is automatically moving (but this is distinct from the /// autopilot that moves an avatar to a sit target!. /// @@ -6003,6 +6271,7 @@ namespace OpenSim.Region.Framework.Scenes /// This is not intended as a permament location for this method. /// /// +/* move to target is now done on presence update private void HandleOnSignificantClientMovement(ScenePresence presence) { if (presence.MovingToTarget) @@ -6059,7 +6328,7 @@ namespace OpenSim.Region.Framework.Scenes } } } - +*/ // manage and select spawn points in sequence public int SpawnPoint() { @@ -6074,8 +6343,13 @@ namespace OpenSim.Region.Framework.Scenes return m_SpawnPoint - 1; } + private void HandleGcCollect(string module, string[] args) + { + GC.Collect(); + } + /// - /// Wrappers to get physics modules retrieve assets. + /// Wrappers to get physics modules retrieve assets. /// /// /// Has to be done this way @@ -6144,5 +6418,21 @@ namespace OpenSim.Region.Framework.Scenes m_eventManager.TriggerExtraSettingChanged(this, name, String.Empty); } + + public bool InTeleportTargetsCoolDown(UUID sourceID, UUID targetID, double timeout) + { + lock(TeleportTargetsCoolDown) + { + UUID lastSource = UUID.Zero; + TeleportTargetsCoolDown.TryGetValue(targetID, out lastSource); + if(lastSource == UUID.Zero) + { + TeleportTargetsCoolDown.Add(targetID, sourceID, timeout); + return false; + } + TeleportTargetsCoolDown.AddOrUpdate(targetID, sourceID, timeout); + return lastSource == sourceID; + } + } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index 7ff3d40..e3e54e2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -57,7 +57,7 @@ namespace OpenSim.Region.Framework.Scenes #region Fields public string Name { get { return RegionInfo.RegionName; } } - + public IConfigSource Config { get { return GetConfig(); } @@ -95,7 +95,7 @@ namespace OpenSim.Region.Framework.Scenes /// The module commanders available from this scene /// protected Dictionary m_moduleCommanders = new Dictionary(); - + /// /// Registered classes that are capable of creating entities. /// @@ -108,7 +108,7 @@ namespace OpenSim.Region.Framework.Scenes protected uint m_lastAllocatedLocalId = 720000; private readonly Mutex _primAllocateMutex = new Mutex(false); - + protected readonly ClientManager m_clientManager = new ClientManager(); public bool LoginsEnabled @@ -153,6 +153,7 @@ namespace OpenSim.Region.Framework.Scenes } public ITerrainChannel Heightmap; + public ITerrainChannel Bakedmap; /// /// Allows retrieval of land information for this scene. @@ -200,7 +201,7 @@ namespace OpenSim.Region.Framework.Scenes /// If -1 then updates until shutdown. /// /// true if update completed within minimum frame time, false otherwise. - public abstract bool Update(int frames); + public abstract void Update(int frames); #endregion @@ -263,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes public virtual RegionInfo RegionInfo { get; private set; } #region admin stuff - + public abstract void OtherRegionUp(GridRegion otherRegion); public virtual string GetSimulatorVersion() @@ -286,7 +287,7 @@ namespace OpenSim.Region.Framework.Scenes } catch (Exception e) { - m_log.Error(string.Format("[SCENE]: SceneBase.cs: Close() - Failed with exception ", e)); + m_log.Error(string.Format("[SCENE]: SceneBase.cs: Close() - Failed with exception {0}", e)); } } @@ -306,7 +307,7 @@ namespace OpenSim.Region.Framework.Scenes return myID; } - + #region Module Methods /// @@ -365,7 +366,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_moduleCommanders.ContainsKey(name)) return m_moduleCommanders[name]; } - + return null; } @@ -415,7 +416,7 @@ namespace OpenSim.Region.Framework.Scenes public void RegisterModuleInterface(M mod) { // m_log.DebugFormat("[SCENE BASE]: Registering interface {0}", typeof(M)); - + List l = null; if (!ModuleInterfaces.TryGetValue(typeof(M), out l)) { @@ -526,9 +527,9 @@ namespace OpenSim.Region.Framework.Scenes return new T[] {}; } } - + #endregion - + /// /// Call this from a region module to add a command to the OpenSim console. /// diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index b9526da..6304778 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs @@ -66,7 +66,7 @@ namespace OpenSim.Region.Framework.Scenes private void InformNeighborsThatRegionisUpCompleted(IAsyncResult iar) { - InformNeighbourThatRegionUpDelegate icon = (InformNeighbourThatRegionUpDelegate) iar.AsyncState; + InformNeighbourThatRegionUpDelegate icon = (InformNeighbourThatRegionUpDelegate)iar.AsyncState; icon.EndInvoke(iar); } @@ -84,11 +84,11 @@ namespace OpenSim.Region.Framework.Scenes if (neighbourService != null) neighbour = neighbourService.HelloNeighbour(regionhandle, region); else - m_log.DebugFormat( "{0} neighbour service provided for region {0} to inform neigbhours of status", LogHeader, m_scene.Name); + m_log.DebugFormat("{0} neighbour service provided for region {0} to inform neigbhours of status", LogHeader, m_scene.Name); if (neighbour != null) { - m_log.DebugFormat( "{0} Region {1} successfully informed neighbour {2} at {3}-{4} that it is up", + m_log.DebugFormat("{0} Region {1} successfully informed neighbour {2} at {3}-{4} that it is up", LogHeader, m_scene.Name, neighbour.RegionName, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y)); m_scene.EventManager.TriggerOnRegionUp(neighbour); @@ -114,9 +114,9 @@ namespace OpenSim.Region.Framework.Scenes { OpenSim.Framework.RegionFlags? regionFlags = n.RegionFlags; -// m_log.DebugFormat( -// "{0}: Region flags for {1} as seen by {2} are {3}", -// LogHeader, n.RegionName, m_scene.Name, regionFlags != null ? regionFlags.ToString() : "not present"); + // m_log.DebugFormat( + // "{0}: Region flags for {1} as seen by {2} are {3}", + // LogHeader, n.RegionName, m_scene.Name, regionFlags != null ? regionFlags.ToString() : "not present"); // Robust services before 2015-01-14 do not return the regionFlags information. In this case, we could // make a separate RegionFlags call but this would involve a network call for each neighbour. @@ -132,7 +132,7 @@ namespace OpenSim.Region.Framework.Scenes } m_log.DebugFormat( - "{0} Informing {1} neighbours that region {2} is up", + "{0} Informing {1} neighbours that region {2} is up", LogHeader, onlineNeighbours.Count, m_scene.Name); foreach (GridRegion n in onlineNeighbours) @@ -168,15 +168,15 @@ namespace OpenSim.Region.Framework.Scenes private void SendChildAgentDataUpdateCompleted(IAsyncResult iar) { - SendChildAgentDataUpdateDelegate icon = (SendChildAgentDataUpdateDelegate) iar.AsyncState; + SendChildAgentDataUpdateDelegate icon = (SendChildAgentDataUpdateDelegate)iar.AsyncState; icon.EndInvoke(iar); } public void SendChildAgentDataUpdate(AgentPosition cAgentData, ScenePresence presence) { -// m_log.DebugFormat( -// "[SCENE COMMUNICATION SERVICE]: Sending child agent position updates for {0} in {1}", -// presence.Name, m_scene.Name); + // m_log.DebugFormat( + // "[SCENE COMMUNICATION SERVICE]: Sending child agent position updates for {0} in {1}", + // presence.Name, m_scene.Name); // This assumes that we know what our neighbors are. try @@ -218,8 +218,11 @@ namespace OpenSim.Region.Framework.Scenes } } + public delegate void SendCloseChildAgentDelegate(UUID agentID, ulong regionHandle); + /// - /// Closes a child agent on a given region + /// This Closes child agents on neighboring regions + /// Calls an asynchronous method to do so.. so it doesn't lag the sim. /// protected void SendCloseChildAgent(UUID agentID, ulong regionHandle, string auth_token) { @@ -231,6 +234,13 @@ namespace OpenSim.Region.Framework.Scenes GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); + if (destination == null) + { + m_log.DebugFormat( + "[SCENE COMMUNICATION SERVICE]: Sending close agent ID {0} FAIL, region with handle {1} not found", agentID, regionHandle); + return; + } + m_log.DebugFormat( "[SCENE COMMUNICATION SERVICE]: Sending close agent ID {0} to {1}", agentID, destination.RegionName); @@ -238,28 +248,29 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Closes a child agents in a collection of regions. Does so asynchronously + /// Closes a child agents in a collection of regions. Does so asynchronously /// so that the caller doesn't wait. /// /// /// public void SendCloseChildAgentConnections(UUID agentID, string auth_code, List regionslst) { - foreach (ulong handle in regionslst) + if (regionslst.Count == 0) + return; + + // use a single thread job for all + Util.FireAndForget(o => { - // We must take a copy here since handle is acts like a reference when used in an iterator. - // This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region. - ulong handleCopy = handle; - Util.FireAndForget( - o => SendCloseChildAgent(agentID, handleCopy, auth_code), - null, - "SceneCommunicationService.SendCloseChildAgentConnections"); - } + foreach (ulong handle in regionslst) + { + SendCloseChildAgent(agentID, handle, auth_code); + } + }, null, "SceneCommunicationService.SendCloseChildAgentConnections"); } - + public List RequestNamedRegions(string name, int maxNumber) { return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs old mode 100644 new mode 100755 index e0080f2..61a243d --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -41,6 +41,12 @@ namespace OpenSim.Region.Framework.Scenes { public delegate void PhysicsCrash(); + public delegate void AttachToBackupDelegate(SceneObjectGroup sog); + + public delegate void DetachFromBackupDelegate(SceneObjectGroup sog); + + public delegate void ChangedBackupDelegate(SceneObjectGroup sog); + /// /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components /// should be migrated out over time. @@ -54,11 +60,15 @@ namespace OpenSim.Region.Framework.Scenes protected internal event PhysicsCrash UnRecoverableError; private PhysicsCrash handlerPhysicsCrash = null; + public event AttachToBackupDelegate OnAttachToBackup; + public event DetachFromBackupDelegate OnDetachFromBackup; + public event ChangedBackupDelegate OnChangeBackup; + #endregion #region Fields - protected object m_presenceLock = new object(); + protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim(); protected Dictionary m_scenePresenceMap = new Dictionary(); protected List m_scenePresenceArray = new List(); @@ -77,21 +87,21 @@ namespace OpenSim.Region.Framework.Scenes protected int m_scriptLPS = 0; protected internal PhysicsScene _PhyScene; - + /// /// Index the SceneObjectGroup for each part by the root part's UUID. /// protected internal Dictionary SceneObjectGroupsByFullID = new Dictionary(); - + /// /// Index the SceneObjectGroup for each part by that part's UUID. /// protected internal Dictionary SceneObjectGroupsByFullPartID = new Dictionary(); - + /// /// Index the SceneObjectGroup for each part by that part's local ID. /// - protected internal Dictionary SceneObjectGroupsByLocalPartID = new Dictionary(); + protected internal Dictionary SceneObjectGroupsByLocalPartID = new Dictionary(); /// /// Lock to prevent object group update, linking, delinking and duplication operations from running concurrently. @@ -111,11 +121,11 @@ namespace OpenSim.Region.Framework.Scenes public PhysicsScene PhysicsScene { - get + get { if (_PhyScene == null) _PhyScene = m_parentScene.RequestModuleInterface(); - return _PhyScene; + return _PhyScene; } set { @@ -134,13 +144,18 @@ namespace OpenSim.Region.Framework.Scenes protected internal void Close() { - lock (m_presenceLock) + m_scenePresencesLock.EnterWriteLock(); + try { Dictionary newmap = new Dictionary(); List newlist = new List(); m_scenePresenceMap = newmap; m_scenePresenceArray = newlist; } + finally + { + m_scenePresencesLock.ExitWriteLock(); + } lock (SceneObjectGroupsByFullID) SceneObjectGroupsByFullID.Clear(); @@ -200,13 +215,20 @@ namespace OpenSim.Region.Framework.Scenes // the joint in the Scene does not exist in the PhysicsScene. // // To solve this, we have an event in the PhysicsScene that is fired when a joint - // has changed position (because one of its associated PhysicsActors has changed + // has changed position (because one of its associated PhysicsActors has changed // position). // // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate(). + return PhysicsScene.Simulate((float)elapsed); } + protected internal void ProcessPhysicsPreSimulation() + { + if(PhysicsScene != null) + PhysicsScene.ProcessPreSimulation(); + } + protected internal void UpdateScenePresenceMovement() { ForEachScenePresence(delegate(ScenePresence presence) @@ -220,17 +242,32 @@ namespace OpenSim.Region.Framework.Scenes coarseLocations = new List(); avatarUUIDs = new List(); + // coarse locations are sent as BYTE, so limited to the 255m max of normal regions + // try to work around that scale down X and Y acording to region size, so reducing the resolution + // + // viewers need to scale up + float scaleX = (float)m_parentScene.RegionInfo.RegionSizeX / (float)Constants.RegionSize; + if (scaleX == 0) + scaleX = 1.0f; + scaleX = 1.0f / scaleX; + float scaleY = (float)m_parentScene.RegionInfo.RegionSizeY / (float)Constants.RegionSize; + if (scaleY == 0) + scaleY = 1.0f; + scaleY = 1.0f / scaleY; + List presences = GetScenePresences(); for (int i = 0; i < Math.Min(presences.Count, maxLocations); ++i) { ScenePresence sp = presences[i]; - + // If this presence is a child agent, we don't want its coarse locations if (sp.IsChildAgent) continue; + Vector3 pos = sp.AbsolutePosition; + pos.X *= scaleX; + pos.Y *= scaleY; - coarseLocations.Add(sp.AbsolutePosition); - + coarseLocations.Add(pos); avatarUUIDs.Add(sp.UUID); } } @@ -261,15 +298,55 @@ namespace OpenSim.Region.Framework.Scenes protected internal bool AddRestoredSceneObject( SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) { + // temporary checks to remove after varsize suport + float regionSizeX = m_parentScene.RegionInfo.RegionSizeX; + if (regionSizeX == 0) + regionSizeX = Constants.RegionSize; + float regionSizeY = m_parentScene.RegionInfo.RegionSizeY; + if (regionSizeY == 0) + regionSizeY = Constants.RegionSize; + + // KF: Check for out-of-region, move inside and make static. + Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X, + sceneObject.RootPart.GroupPosition.Y, + sceneObject.RootPart.GroupPosition.Z); + bool clampZ = m_parentScene.ClampNegativeZ; + + if (!(((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0))) && (npos.X < 0.0 || npos.Y < 0.0 || (npos.Z < 0.0 && clampZ) || + npos.X > regionSizeX || + npos.Y > regionSizeY)) + { + if (npos.X < 0.0) npos.X = 1.0f; + if (npos.Y < 0.0) npos.Y = 1.0f; + if (npos.Z < 0.0 && clampZ) npos.Z = 0.0f; + if (npos.X > regionSizeX) npos.X = regionSizeX - 1.0f; + if (npos.Y > regionSizeY) npos.Y = regionSizeY - 1.0f; + + SceneObjectPart rootpart = sceneObject.RootPart; + rootpart.GroupPosition = npos; + + foreach (SceneObjectPart part in sceneObject.Parts) + { + if (part == rootpart) + continue; + part.GroupPosition = npos; + } + rootpart.Velocity = Vector3.Zero; + rootpart.AngularVelocity = Vector3.Zero; + rootpart.Acceleration = Vector3.Zero; + } + + bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); + if (attachToBackup && (!alreadyPersisted)) { sceneObject.ForceInventoryPersistence(); sceneObject.HasGroupChanged = true; } - - return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); + sceneObject.InvalidateDeepEffectivePerms(); + return ret; } - + /// /// Add a newly created object to the scene. This will both update the scene, and send information about the /// new object to all clients interested in the scene. @@ -284,18 +361,22 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) { - // Ensure that we persist this new scene object if it's not an + + bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); + + // Ensure that we persist this new scene object if it's not an // attachment + if (attachToBackup) sceneObject.HasGroupChanged = true; - return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); + return ret; } - + /// /// Add a newly created object to the scene. /// - /// + /// /// This method does not send updates to the client - callers need to handle this themselves. /// Caller should also trigger EventManager.TriggerObjectAddedToScene /// @@ -307,26 +388,25 @@ namespace OpenSim.Region.Framework.Scenes public bool AddNewSceneObject( SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel) { - AddNewSceneObject(sceneObject, attachToBackup, false); - if (pos != null) sceneObject.AbsolutePosition = (Vector3)pos; + if (rot != null) + sceneObject.UpdateGroupRotationR((Quaternion)rot); + + AddNewSceneObject(sceneObject, attachToBackup, false); + if (sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) { sceneObject.ClearPartAttachmentData(); } - if (rot != null) - sceneObject.UpdateGroupRotationR((Quaternion)rot); - PhysicsActor pa = sceneObject.RootPart.PhysActor; if (pa != null && pa.IsPhysical && vel != Vector3.Zero) { sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false); - sceneObject.Velocity = vel; } - + return true; } @@ -351,6 +431,11 @@ namespace OpenSim.Region.Framework.Scenes /// protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) { + if (sceneObject == null) + { + m_log.ErrorFormat("[SCENEGRAPH]: Tried to add null scene object"); + return false; + } if (sceneObject.UUID == UUID.Zero) { m_log.ErrorFormat( @@ -383,9 +468,9 @@ namespace OpenSim.Region.Framework.Scenes { Vector3 scale = part.Shape.Scale; - scale.X = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.X)); - scale.Y = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Y)); - scale.Z = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Z)); + scale.X = Util.Clamp(scale.X, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys); + scale.Y = Util.Clamp(scale.Y, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys); + scale.Z = Util.Clamp(scale.Z, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys); part.Shape.Scale = scale; } @@ -406,36 +491,39 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.AttachToScene(m_parentScene); - if (sendClientUpdates) - sceneObject.ScheduleGroupForFullUpdate(); - Entities.Add(sceneObject); - if (attachToBackup) - sceneObject.AttachToBackup(); - lock (SceneObjectGroupsByFullID) SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; - lock (SceneObjectGroupsByFullPartID) + foreach (SceneObjectPart part in parts) { - foreach (SceneObjectPart part in parts) + lock (SceneObjectGroupsByFullPartID) SceneObjectGroupsByFullPartID[part.UUID] = sceneObject; - } - lock (SceneObjectGroupsByLocalPartID) - { -// m_log.DebugFormat( -// "[SCENE GRAPH]: Adding scene object {0} {1} {2} to SceneObjectGroupsByLocalPartID in {3}", -// sceneObject.Name, sceneObject.UUID, sceneObject.LocalId, m_parentScene.RegionInfo.RegionName); - - foreach (SceneObjectPart part in parts) + lock (SceneObjectGroupsByLocalPartID) SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject; } + if (sendClientUpdates) + sceneObject.ScheduleGroupForFullUpdate(); + + if (attachToBackup) + sceneObject.AttachToBackup(); + return true; } + public void updateScenePartGroup(SceneObjectPart part, SceneObjectGroup grp) + { + // no tests, caller has responsability... + lock (SceneObjectGroupsByFullPartID) + SceneObjectGroupsByFullPartID[part.UUID] = grp; + + lock (SceneObjectGroupsByLocalPartID) + SceneObjectGroupsByLocalPartID[part.LocalId] = grp; + } + /// /// Delete an object from the scene /// @@ -461,6 +549,8 @@ namespace OpenSim.Region.Framework.Scenes // that are part of the Scene Object being removed m_numTotalPrim -= grp.PrimCount; + bool isPh = (grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics; + int nphysparts = 0; // Go through all parts (primitives and meshes) of this Scene Object foreach (SceneObjectPart part in grp.Parts) { @@ -471,30 +561,31 @@ namespace OpenSim.Region.Framework.Scenes m_numMesh--; else m_numPrim--; + + if(isPh && part.PhysicsShapeType != (byte)PhysShapeType.none) + nphysparts++; } - if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics) - RemovePhysicalPrim(grp.PrimCount); + if (nphysparts > 0 ) + RemovePhysicalPrim(nphysparts); } - + + bool ret = Entities.Remove(uuid); + lock (SceneObjectGroupsByFullID) SceneObjectGroupsByFullID.Remove(grp.UUID); - lock (SceneObjectGroupsByFullPartID) + SceneObjectPart[] parts = grp.Parts; + for (int i = 0; i < parts.Length; i++) { - SceneObjectPart[] parts = grp.Parts; - for (int i = 0; i < parts.Length; i++) + lock (SceneObjectGroupsByFullPartID) SceneObjectGroupsByFullPartID.Remove(parts[i].UUID); - } - lock (SceneObjectGroupsByLocalPartID) - { - SceneObjectPart[] parts = grp.Parts; - for (int i = 0; i < parts.Length; i++) + lock (SceneObjectGroupsByLocalPartID) SceneObjectGroupsByLocalPartID.Remove(parts[i].LocalId); } - return Entities.Remove(uuid); + return ret; } /// @@ -509,6 +600,30 @@ namespace OpenSim.Region.Framework.Scenes m_updateList[obj.UUID] = obj; } + public void FireAttachToBackup(SceneObjectGroup obj) + { + if (OnAttachToBackup != null) + { + OnAttachToBackup(obj); + } + } + + public void FireDetachFromBackup(SceneObjectGroup obj) + { + if (OnDetachFromBackup != null) + { + OnDetachFromBackup(obj); + } + } + + public void FireChangeBackup(SceneObjectGroup obj) + { + if (OnChangeBackup != null) + { + OnChangeBackup(obj); + } + } + /// /// Process all pending updates /// @@ -520,7 +635,7 @@ namespace OpenSim.Region.Framework.Scenes { List updates; - // Some updates add more updates to the updateList. + // Some updates add more updates to the updateList. // Get the current list of updates and clear the list before iterating lock (m_updateList) { @@ -600,7 +715,8 @@ namespace OpenSim.Region.Framework.Scenes Entities[presence.UUID] = presence; - lock (m_presenceLock) + m_scenePresencesLock.EnterWriteLock(); + try { m_numChildAgents++; @@ -626,6 +742,10 @@ namespace OpenSim.Region.Framework.Scenes m_scenePresenceMap = newmap; m_scenePresenceArray = newlist; } + finally + { + m_scenePresencesLock.ExitWriteLock(); + } return presence; } @@ -642,11 +762,12 @@ namespace OpenSim.Region.Framework.Scenes agentID); } - lock (m_presenceLock) + m_scenePresencesLock.EnterWriteLock(); + try { Dictionary newmap = new Dictionary(m_scenePresenceMap); List newlist = new List(m_scenePresenceArray); - + // Remove the presence reference from the dictionary if (newmap.ContainsKey(agentID)) { @@ -664,6 +785,10 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); } } + finally + { + m_scenePresencesLock.ExitWriteLock(); + } } protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) @@ -754,7 +879,7 @@ namespace OpenSim.Region.Framework.Scenes #endregion #region Get Methods - + /// /// Get the controlling client for the given avatar, if there is one. /// @@ -892,7 +1017,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[SCENE GRAPH]: Found scene object {0} {1} {2} via SceneObjectGroupsByLocalPartID index but it doesn't contain part with local id {3}. Removing from entry from index in {4}.", sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName); - + m_log.WarnFormat("stack: {0}", Environment.StackTrace); SceneObjectGroupsByLocalPartID.Remove(localID); } } @@ -1066,11 +1191,11 @@ namespace OpenSim.Region.Framework.Scenes protected internal SceneObjectPart GetSceneObjectPart(uint localID) { SceneObjectGroup group = GetGroupByPrim(localID); - if (group == null) + if (group == null || group.IsDeleted) return null; return group.GetPart(localID); } - + /// /// Get a prim by name from the scene (will return the first /// found, if there are more than one prim with the same name) @@ -1089,7 +1214,7 @@ namespace OpenSim.Region.Framework.Scenes foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts) { // m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name); - + if (p.Name == name) { sop = p; @@ -1188,7 +1313,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Performs action on all scene presences. This can ultimately run the actions in parallel but /// any delegates passed in will need to implement their own locking on data they reference and - /// modify outside of the scope of the delegate. + /// modify outside of the scope of the delegate. /// /// public void ForEachScenePresence(Action action) @@ -1223,11 +1348,57 @@ namespace OpenSim.Region.Framework.Scenes } } } - + #endregion #region Client Event handlers + protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient) + { + SceneObjectPart part = GetSceneObjectPart(localID); + ObjectChangeData data = (ObjectChangeData)odata; + + if (part != null) + { + SceneObjectGroup grp = part.ParentGroup; + if (grp != null) + { + if (m_parentScene.Permissions.CanEditObject(grp, remoteClient)) + { + // These two are exceptions SL makes in the interpretation + // of the change flags. Must check them here because otherwise + // the group flag (see below) would be lost + if (data.change == ObjectChangeType.groupS) + data.change = ObjectChangeType.primS; + if (data.change == ObjectChangeType.groupPS) + data.change = ObjectChangeType.primPS; + part.StoreUndoState(data.change); // lets test only saving what we changed + grp.doChangeObject(part, (ObjectChangeData)data); + } + else + { + // Is this any kind of group operation? + if ((data.change & ObjectChangeType.Group) != 0) + { + // Is a move and/or rotation requested? + if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0) + { + // Are we allowed to move it? + if (m_parentScene.Permissions.CanMoveObject(grp, remoteClient)) + { + // Strip all but move and rotation from request + data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation); + + part.StoreUndoState(data.change); + grp.doChangeObject(part, (ObjectChangeData)data); + } + } + } + } + } + } + } + /// /// Update the scale of an individual prim. /// @@ -1240,9 +1411,19 @@ namespace OpenSim.Region.Framework.Scenes if (part != null) { - if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(part.ParentGroup, remoteClient)) { + bool physbuild = false; + if (part.ParentGroup.RootPart.PhysActor != null) + { + part.ParentGroup.RootPart.PhysActor.Building = true; + physbuild = true; + } + part.Resize(scale); + + if (physbuild) + part.ParentGroup.RootPart.PhysActor.Building = false; } } } @@ -1252,9 +1433,19 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(group, remoteClient)) { + bool physbuild = false; + if (group.RootPart.PhysActor != null) + { + group.RootPart.PhysActor.Building = true; + physbuild = true; + } + group.GroupResize(scale); + + if (physbuild) + group.RootPart.PhysActor.Building = false; } } } @@ -1288,7 +1479,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanMoveObject(group, remoteClient)) { group.UpdateSingleRotation(rot, localID); } @@ -1306,7 +1497,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanMoveObject(group, remoteClient)) { group.UpdateSingleRotation(rot, pos, localID); } @@ -1324,7 +1515,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanMoveObject(group, remoteClient)) { group.UpdateGroupRotationR(rot); } @@ -1343,7 +1534,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanMoveObject(group, remoteClient)) { group.UpdateGroupRotationPR(pos, rot); } @@ -1361,7 +1552,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) || group.IsAttachment) + if (m_parentScene.Permissions.CanMoveObject(group, remoteClient) || group.IsAttachment) { group.UpdateSinglePosition(pos, localID); } @@ -1376,30 +1567,24 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdatePrimGroupPosition(uint localId, Vector3 pos, IClientAPI remoteClient) { - UpdatePrimGroupPosition(localId, pos, remoteClient.AgentId); - } - - /// - /// Update the position of the given group. - /// - /// - /// - /// - public void UpdatePrimGroupPosition(uint localId, Vector3 pos, UUID updatingAgentId) - { SceneObjectGroup group = GetGroupByPrim(localId); - + if (group != null) { if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) { - if (m_parentScene.AttachmentsModule != null) - m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); + // Set the new attachment point data in the object + byte attachmentPoint = (byte)group.AttachmentPoint; + group.UpdateGroupPosition(pos); + group.IsAttachment = false; + group.AbsolutePosition = group.RootPart.AttachedPos; + group.AttachmentPoint = attachmentPoint; + group.HasGroupChanged = true; } else { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, updatingAgentId) - && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos)) + if (m_parentScene.Permissions.CanMoveObject(group, remoteClient) + && m_parentScene.Permissions.CanObjectEntry(group, false, pos)) { group.UpdateGroupPosition(pos); } @@ -1419,13 +1604,16 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient) { - SceneObjectGroup group = GetGroupByPrim(localID); - - if (group != null) + SceneObjectPart part = GetSceneObjectPart(localID); + if(part == null) + return; + + SceneObjectGroup group = part.ParentGroup; + if (group != null && !group.IsDeleted) { - if (m_parentScene.Permissions.CanEditObject(group.UUID,remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(group, remoteClient)) { - group.UpdateTextureEntry(localID, texture); + part.UpdateTextureEntry(texture); } } } @@ -1447,11 +1635,12 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(localID); if (group != null) { - if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(group, remoteClient)) { // VolumeDetect can't be set via UI and will always be off when a change is made there // now only change volume dtc if phantom off + bool wantedPhys = UsePhysics; if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data { bool vdtc; @@ -1460,7 +1649,7 @@ namespace OpenSim.Region.Framework.Scenes else // else turn it off vdtc = false; - group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc); + group.UpdateFlags(UsePhysics, SetTemporary, SetPhantom, vdtc); } else { @@ -1468,77 +1657,21 @@ namespace OpenSim.Region.Framework.Scenes if (part != null) { part.UpdateExtraPhysics(PhysData); - if (part.UpdatePhysRequired) + if (remoteClient != null) remoteClient.SendPartPhysicsProprieties(part); } } - } - } - } - - /// - /// Move the given object - /// - /// - /// - /// - /// - protected internal void MoveObject(UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List surfaceArgs) - { - SceneObjectGroup group = GetGroupByPrim(objectID); - if (group != null) - { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.) - { - group.GrabMovement(objectID, offset, pos, remoteClient); - } - // This is outside the above permissions condition - // so that if the object is locked the client moving the object - // get's it's position on the simulator even if it was the same as before - // This keeps the moving user's client in sync with the rest of the world. - group.SendGroupTerseUpdate(); - } - } - - /// - /// Start spinning the given object - /// - /// - /// - /// - protected internal void SpinStart(UUID objectID, IClientAPI remoteClient) - { - SceneObjectGroup group = GetGroupByPrim(objectID); - if (group != null) - { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.) - { - group.SpinStart(remoteClient); - } - } - } - - /// - /// Spin the given object - /// - /// - /// - /// - protected internal void SpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient) - { - SceneObjectGroup group = GetGroupByPrim(objectID); - if (group != null) - { - if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.) - { - group.SpinMovement(rotation, remoteClient); + if (wantedPhys != group.UsesPhysics && remoteClient != null) + { + if(m_parentScene.m_linksetPhysCapacity != 0) + remoteClient.SendAlertMessage("Object physics cancelled because it exceeds limits for physical prims, either size or number of primswith shape type not set to None"); + else + remoteClient.SendAlertMessage("Object physics cancelled because it exceeds size limits for physical prims"); + + group.RootPart.ScheduleFullUpdate(); + } } - // This is outside the above permissions condition - // so that if the object is locked the client moving the object - // get's it's position on the simulator even if it was the same as before - // This keeps the moving user's client in sync with the rest of the world. - group.SendGroupTerseUpdate(); } } @@ -1552,7 +1685,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(primLocalID); if (group != null) { - if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(group, remoteClient)) { group.SetPartName(Util.CleanString(name), primLocalID); group.HasGroupChanged = true; @@ -1570,7 +1703,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(primLocalID); if (group != null) { - if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(group, remoteClient)) { group.SetPartDescription(Util.CleanString(description), primLocalID); group.HasGroupChanged = true; @@ -1592,13 +1725,13 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(primLocalID); if (group != null) { - if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(group, remoteClient)) { SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID); if (part != null) { - part.ClickAction = Convert.ToByte(clickAction); - group.HasGroupChanged = true; + part.ClickAction = Convert.ToByte(clickAction); + group.HasGroupChanged = true; } } } @@ -1609,13 +1742,14 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup group = GetGroupByPrim(primLocalID); if (group != null) { - if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId)) + if (m_parentScene.Permissions.CanEditObject(group, remoteClient)) { SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID); if (part != null) { part.Material = Convert.ToByte(material); group.HasGroupChanged = true; + remoteClient.SendPartPhysicsProprieties(part); } } } @@ -1694,12 +1828,14 @@ namespace OpenSim.Region.Framework.Scenes return; Monitor.Enter(m_updateLock); + try { + List childGroups = new List(); // We do this in reverse to get the link order of the prims correct - for (int i = 0 ; i < children.Count ; i++) + for (int i = 0; i < children.Count; i++) { SceneObjectGroup child = children[i].ParentGroup; @@ -1710,9 +1846,13 @@ namespace OpenSim.Region.Framework.Scenes // Make sure no child prim is set for sale // So that, on delink, no prims are unwittingly // left for sale and sold off - child.RootPart.ObjectSaleType = 0; - child.RootPart.SalePrice = 10; - childGroups.Add(child); + + if (child != null) + { + child.RootPart.ObjectSaleType = 0; + child.RootPart.SalePrice = 10; + childGroups.Add(child); + } } foreach (SceneObjectGroup child in childGroups) @@ -1725,7 +1865,8 @@ namespace OpenSim.Region.Framework.Scenes // this is here so physics gets updated! // Don't remove! Bad juju! Stay away! or fix physics! - child.AbsolutePosition = child.AbsolutePosition; + // already done in LinkToGroup +// child.AbsolutePosition = child.AbsolutePosition; } } @@ -1741,6 +1882,17 @@ namespace OpenSim.Region.Framework.Scenes } finally { +/* + lock (SceneObjectGroupsByLocalPartID) + { + foreach (SceneObjectPart part in parentGroup.Parts) + SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup; + } +*/ + parentGroup.AdjustChildPrimPermissions(false); + parentGroup.HasGroupChanged = true; + parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true); + parentGroup.ScheduleGroupForFullUpdate(); Monitor.Exit(m_updateLock); } } @@ -1761,42 +1913,50 @@ namespace OpenSim.Region.Framework.Scenes // foreach (SceneObjectPart part in prims) { - if (part != null) + if(part == null) + continue; + SceneObjectGroup parentSOG = part.ParentGroup; + if(parentSOG == null || + parentSOG.IsDeleted || + parentSOG.inTransit || + parentSOG.PrimCount == 1) + continue; + + if (!affectedGroups.Contains(parentSOG)) { - if (part.KeyframeMotion != null) - { - part.KeyframeMotion.Stop(); - part.KeyframeMotion = null; - } - if (part.ParentGroup.PrimCount != 1) // Skip single - { - if (part.LinkNum < 2) // Root - { - rootParts.Add(part); - } - else - { - part.LastOwnerID = part.ParentGroup.RootPart.LastOwnerID; - childParts.Add(part); - } + affectedGroups.Add(parentSOG); + if(parentSOG.RootPart.PhysActor != null) + parentSOG.RootPart.PhysActor.Building = true; + } - SceneObjectGroup group = part.ParentGroup; - if (!affectedGroups.Contains(group)) - affectedGroups.Add(group); - } + if (part.KeyframeMotion != null) + { + part.KeyframeMotion.Stop(); + part.KeyframeMotion = null; + } + + if (part.LinkNum < 2) // Root + { + rootParts.Add(part); + } + else + { + part.LastOwnerID = part.ParentGroup.RootPart.LastOwnerID; + part.RezzerID = part.ParentGroup.RootPart.RezzerID; + childParts.Add(part); } } - foreach (SceneObjectPart child in childParts) + if (childParts.Count > 0) { - // Unlink all child parts from their groups - // - child.ParentGroup.DelinkFromGroup(child, true); - - // These are not in affected groups and will not be - // handled further. Do the honors here. - child.ParentGroup.HasGroupChanged = true; - child.ParentGroup.ScheduleGroupForFullUpdate(); + foreach (SceneObjectPart child in childParts) + { + // Unlink all child parts from their groups + child.ParentGroup.DelinkFromGroup(child, true); + //child.ParentGroup is now other + child.ParentGroup.HasGroupChanged = true; + child.ParentGroup.ScheduleGroupForFullUpdate(); + } } foreach (SceneObjectPart root in rootParts) @@ -1806,63 +1966,54 @@ namespace OpenSim.Region.Framework.Scenes // However, editing linked parts and unlinking may be different // SceneObjectGroup group = root.ParentGroup; - + List newSet = new List(group.Parts); + + newSet.Remove(root); int numChildren = newSet.Count; + if(numChildren == 0) + break; + + foreach (SceneObjectPart p in newSet) + group.DelinkFromGroup(p, false); + + SceneObjectPart newRoot = newSet[0]; - // If there are prims left in a link set, but the root is - // slated for unlink, we need to do this + // If there is more than one prim remaining, we + // need to re-link // - if (numChildren != 1) + if (numChildren > 1) { - // Unlink the remaining set + // Determine new root // - bool sendEventsToRemainder = true; - if (numChildren > 1) - sendEventsToRemainder = false; + newSet.RemoveAt(0); + foreach (SceneObjectPart newChild in newSet) + newChild.ClearUpdateSchedule(); - foreach (SceneObjectPart p in newSet) - { - if (p != group.RootPart) - group.DelinkFromGroup(p, sendEventsToRemainder); - } - - // If there is more than one prim remaining, we - // need to re-link - // - if (numChildren > 2) - { - // Remove old root - // - if (newSet.Contains(root)) - newSet.Remove(root); - - // Preserve link ordering - // - newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) - { - return a.LinkNum.CompareTo(b.LinkNum); - }); - - // Determine new root - // - SceneObjectPart newRoot = newSet[0]; - newSet.RemoveAt(0); - - foreach (SceneObjectPart newChild in newSet) - newChild.ClearUpdateSchedule(); - - LinkObjects(newRoot, newSet); - if (!affectedGroups.Contains(newRoot.ParentGroup)) - affectedGroups.Add(newRoot.ParentGroup); - } + LinkObjects(newRoot, newSet); + } + else + { + newRoot.TriggerScriptChangedEvent(Changed.LINK); + newRoot.ParentGroup.HasGroupChanged = true; + newRoot.ParentGroup.InvalidatePartsLinkMaps(); + newRoot.ParentGroup.ScheduleGroupForFullUpdate(); } } - // Finally, trigger events in the roots + // trigger events in the roots // foreach (SceneObjectGroup g in affectedGroups) { + if(g.RootPart.PhysActor != null) + g.RootPart.PhysActor.Building = false; + g.AdjustChildPrimPermissions(false); + // Child prims that have been unlinked and deleted will + // return unless the root is deleted. This will remove them + // from the database. They will be rewritten immediately, + // minus the rows for the unlinked child prims. + m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID); + g.InvalidatePartsLinkMaps(); g.TriggerScriptChangedEvent(Changed.LINK); g.HasGroupChanged = true; // Persist g.ScheduleGroupForFullUpdate(); @@ -1876,27 +2027,9 @@ namespace OpenSim.Region.Framework.Scenes protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID) { - UUID user = remoteClient.AgentId; - UUID objid = UUID.Zero; - SceneObjectPart obj = null; - - EntityBase[] entityList = GetEntities(); - foreach (EntityBase ent in entityList) - { - if (ent is SceneObjectGroup) - { - SceneObjectGroup sog = ent as SceneObjectGroup; - - foreach (SceneObjectPart part in sog.Parts) - { - if (part.LocalId == localID) - { - objid = part.UUID; - obj = part; - } - } - } - } + SceneObjectGroup sog = GetGroupByPrim(localID); + if(sog == null) + return; //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints //aka ObjectFlags.JointWheel = IncludeInSearch @@ -1913,15 +2046,15 @@ namespace OpenSim.Region.Framework.Scenes // libomv will complain about PrimFlags.JointWheel being // deprecated, so we #pragma warning disable 0612 - if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(objid, user)) + if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(sog, remoteClient)) { - obj.ParentGroup.RootPart.AddFlag(PrimFlags.JointWheel); - obj.ParentGroup.HasGroupChanged = true; + sog.RootPart.AddFlag(PrimFlags.JointWheel); + sog.HasGroupChanged = true; } - else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(objid,user)) + else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(sog, remoteClient)) { - obj.ParentGroup.RootPart.RemFlag(PrimFlags.JointWheel); - obj.ParentGroup.HasGroupChanged = true; + sog.RootPart.RemFlag(PrimFlags.JointWheel); + sog.HasGroupChanged = true; } #pragma warning restore 0612 } @@ -1936,120 +2069,86 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// null if duplication fails, otherwise the duplicated object - public SceneObjectGroup DuplicateObject( - uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) + /// + public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, UUID AgentID, UUID GroupID, Quaternion rot, bool createSelected) { - Monitor.Enter(m_updateLock); +// m_log.DebugFormat( +// "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", +// originalPrimID, offset, AgentID); - try + SceneObjectGroup original = GetGroupByPrim(originalPrimID); + if (original != null) { - // m_log.DebugFormat( - // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", - // originalPrimID, offset, AgentID); - - SceneObjectGroup original = GetGroupByPrim(originalPrimID); - if (original == null) + if (m_parentScene.Permissions.CanDuplicateObject(original, AgentID)) { - m_log.WarnFormat( - "[SCENEGRAPH]: Attempt to duplicate nonexistent prim id {0} by {1}", originalPrimID, AgentID); + SceneObjectGroup copy = original.Copy(true); + copy.AbsolutePosition = copy.AbsolutePosition + offset; - return null; - } - - if (!m_parentScene.Permissions.CanDuplicateObject( - original.PrimCount, original.UUID, AgentID, original.AbsolutePosition)) - return null; - - SceneObjectGroup copy = original.Copy(true); - copy.AbsolutePosition = copy.AbsolutePosition + offset; - - if (original.OwnerID != AgentID) - { - copy.SetOwnerId(AgentID); - copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID); + SceneObjectPart[] parts = copy.Parts; - SceneObjectPart[] partList = copy.Parts; + m_numTotalPrim += parts.Length; - if (m_parentScene.Permissions.PropagatePermissions()) + if (original.OwnerID != AgentID) { - foreach (SceneObjectPart child in partList) + copy.SetOwner(AgentID, GroupID); + + if (m_parentScene.Permissions.PropagatePermissions()) { - child.Inventory.ChangeInventoryOwner(AgentID); - child.TriggerScriptChangedEvent(Changed.OWNER); - child.ApplyNextOwnerPermissions(); + foreach (SceneObjectPart child in parts) + { + child.Inventory.ChangeInventoryOwner(AgentID); + child.TriggerScriptChangedEvent(Changed.OWNER); + child.ApplyNextOwnerPermissions(); + } + copy.InvalidateEffectivePerms(); } } - copy.RootPart.ObjectSaleType = 0; - copy.RootPart.SalePrice = 10; - } + // FIXME: This section needs to be refactored so that it just calls AddSceneObject() + Entities.Add(copy); - // FIXME: This section needs to be refactored so that it just calls AddSceneObject() - Entities.Add(copy); - - lock (SceneObjectGroupsByFullID) - SceneObjectGroupsByFullID[copy.UUID] = copy; - - SceneObjectPart[] children = copy.Parts; - - lock (SceneObjectGroupsByFullPartID) - { - SceneObjectGroupsByFullPartID[copy.UUID] = copy; - foreach (SceneObjectPart part in children) - SceneObjectGroupsByFullPartID[part.UUID] = copy; - } - - lock (SceneObjectGroupsByLocalPartID) - { - SceneObjectGroupsByLocalPartID[copy.LocalId] = copy; - foreach (SceneObjectPart part in children) - SceneObjectGroupsByLocalPartID[part.LocalId] = copy; - } - // PROBABLE END OF FIXME + lock (SceneObjectGroupsByFullID) + SceneObjectGroupsByFullID[copy.UUID] = copy; - // Since we copy from a source group that is in selected - // state, but the copy is shown deselected in the viewer, - // We need to clear the selection flag here, else that - // prim never gets persisted at all. The client doesn't - // think it's selected, so it will never send a deselect... - copy.IsSelected = false; + foreach (SceneObjectPart part in parts) + { + if (part.GetPrimType() == PrimType.SCULPT) + m_numMesh++; + else + m_numPrim++; - m_numTotalPrim += copy.Parts.Length; + lock (SceneObjectGroupsByFullPartID) + SceneObjectGroupsByFullPartID[part.UUID] = copy; + lock (SceneObjectGroupsByLocalPartID) + SceneObjectGroupsByLocalPartID[part.LocalId] = copy; + } - // Go through all parts (primitives and meshes) of this Scene Object - foreach (SceneObjectPart part in copy.Parts) - { - // Keep track of the total number of meshes or geometric primitives now in the scene; - // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to - // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives - if (part.GetPrimType() == PrimType.SCULPT) - m_numMesh++; - else - m_numPrim++; - } + // PROBABLE END OF FIXME - if (rot != Quaternion.Identity) - { - copy.UpdateGroupRotationR(rot); - } + copy.IsSelected = createSelected; + + if (rot != Quaternion.Identity) + copy.UpdateGroupRotationR(rot); - copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); - copy.HasGroupChanged = true; - copy.ScheduleGroupForFullUpdate(); - copy.ResumeScripts(); + // required for physics to update it's position + copy.ResetChildPrimPhysicsPositions(); - // required for physics to update it's position - copy.AbsolutePosition = copy.AbsolutePosition; + copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); + copy.ResumeScripts(); - return copy; + copy.HasGroupChanged = true; + copy.ScheduleGroupForFullUpdate(); + return copy; + } } - finally + else { - Monitor.Exit(m_updateLock); + m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID); } + + return null; } - - /// + /// Calculates the distance between two Vector3s /// /// @@ -2067,6 +2166,6 @@ namespace OpenSim.Region.Framework.Scenes #endregion - + } } diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index 28f7896..1e418df 100644 --- a/OpenSim/Region/Framework/Scenes/SceneManager.cs +++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs @@ -91,19 +91,19 @@ namespace OpenSim.Region.Framework.Scenes private static SceneManager m_instance = null; public static SceneManager Instance - { + { get { if (m_instance == null) m_instance = new SceneManager(); return m_instance; - } + } } - private readonly List m_localScenes = new List(); + private readonly DoubleDictionary m_localScenes = new DoubleDictionary(); public List Scenes { - get { return new List(m_localScenes); } + get { return new List(m_localScenes.FindAll(delegate(Scene s) { return true; })); } } /// @@ -120,13 +120,10 @@ namespace OpenSim.Region.Framework.Scenes { if (CurrentScene == null) { - lock (m_localScenes) - { - if (m_localScenes.Count > 0) - return m_localScenes[0]; - else - return null; - } + List sceneList = Scenes; + if (sceneList.Count == 0) + return null; + return sceneList[0]; } else { @@ -138,41 +135,35 @@ namespace OpenSim.Region.Framework.Scenes public SceneManager() { m_instance = this; - m_localScenes = new List(); + m_localScenes = new DoubleDictionary(); } public void Close() { + List localScenes = null; + lock (m_localScenes) { - for (int i = 0; i < m_localScenes.Count; i++) - { - m_localScenes[i].Close(); - } + localScenes = Scenes; + } + + for (int i = 0; i < localScenes.Count; i++) + { + localScenes[i].Close(); } } public void Close(Scene cscene) { - lock (m_localScenes) - { - if (m_localScenes.Contains(cscene)) - { - for (int i = 0; i < m_localScenes.Count; i++) - { - if (m_localScenes[i].Equals(cscene)) - { - m_localScenes[i].Close(); - } - } - } - } + if (!m_localScenes.ContainsKey(cscene.RegionInfo.RegionID)) + return; + cscene.Close(); } public void Add(Scene scene) { lock (m_localScenes) - m_localScenes.Add(scene); + m_localScenes.Add(scene.RegionInfo.RegionID, scene.RegionInfo.RegionName, scene); scene.OnRestart += HandleRestart; scene.EventManager.OnRegionReadyStatusChange += HandleRegionReadyStatusChange; @@ -184,15 +175,8 @@ namespace OpenSim.Region.Framework.Scenes lock (m_localScenes) { - for (int i = 0; i < m_localScenes.Count; i++) - { - if (rdata.RegionName == m_localScenes[i].RegionInfo.RegionName) - { - restartedScene = m_localScenes[i]; - m_localScenes.RemoveAt(i); - break; - } - } + m_localScenes.TryGetValue(rdata.RegionID, out restartedScene); + m_localScenes.Remove(rdata.RegionID); } // If the currently selected scene has been restarted, then we can't reselect here since we the scene @@ -207,39 +191,36 @@ namespace OpenSim.Region.Framework.Scenes private void HandleRegionReadyStatusChange(IScene scene) { lock (m_localScenes) - AllRegionsReady = m_localScenes.TrueForAll(s => s.Ready); + AllRegionsReady = m_localScenes.FindAll(s => !s.Ready).Count == 0; } public void SendSimOnlineNotification(ulong regionHandle) { RegionInfo Result = null; - lock (m_localScenes) - { - for (int i = 0; i < m_localScenes.Count; i++) - { - if (m_localScenes[i].RegionInfo.RegionHandle == regionHandle) + Scene s = m_localScenes.FindValue(delegate(Scene x) { - // Inform other regions to tell their avatar about me - Result = m_localScenes[i].RegionInfo; - } - } + if (x.RegionInfo.RegionHandle == regionHandle) + return true; + return false; + }); - if (Result != null) + if (s != null) + { + List sceneList = Scenes; + + for (int i = 0; i < sceneList.Count; i++) { - for (int i = 0; i < m_localScenes.Count; i++) + if (sceneList[i]!= s) { - if (m_localScenes[i].RegionInfo.RegionHandle != regionHandle) - { - // Inform other regions to tell their avatar about me - //m_localScenes[i].OtherRegionUp(Result); - } + // Inform other regions to tell their avatar about me + //sceneList[i].OtherRegionUp(Result); } } - else - { - m_log.Error("[REGION]: Unable to notify Other regions of this Region coming up"); - } + } + else + { + m_log.Error("[REGION]: Unable to notify Other regions of this Region coming up"); } } @@ -359,7 +340,7 @@ namespace OpenSim.Region.Framework.Scenes public bool TrySetCurrentScene(string regionName) { - if ((String.Compare(regionName, "root") == 0) + if ((String.Compare(regionName, "root") == 0) || (String.Compare(regionName, "..") == 0) || (String.Compare(regionName, "/") == 0)) { @@ -368,16 +349,12 @@ namespace OpenSim.Region.Framework.Scenes } else { - lock (m_localScenes) + Scene s; + + if (m_localScenes.TryGetValue(regionName, out s)) { - foreach (Scene scene in m_localScenes) - { - if (String.Compare(scene.RegionInfo.RegionName, regionName, true) == 0) - { - CurrentScene = scene; - return true; - } - } + CurrentScene = s; + return true; } return false; @@ -386,18 +363,14 @@ namespace OpenSim.Region.Framework.Scenes public bool TrySetCurrentScene(UUID regionID) { - m_log.Debug("Searching for Region: '" + regionID + "'"); +// m_log.Debug("Searching for Region: '" + regionID + "'"); - lock (m_localScenes) + Scene s; + + if (m_localScenes.TryGetValue(regionID, out s)) { - foreach (Scene scene in m_localScenes) - { - if (scene.RegionInfo.RegionID == regionID) - { - CurrentScene = scene; - return true; - } - } + CurrentScene = s; + return true; } return false; @@ -405,74 +378,44 @@ namespace OpenSim.Region.Framework.Scenes public bool TryGetScene(string regionName, out Scene scene) { - lock (m_localScenes) - { - foreach (Scene mscene in m_localScenes) - { - if (String.Compare(mscene.RegionInfo.RegionName, regionName, true) == 0) - { - scene = mscene; - return true; - } - } - } - - scene = null; - return false; + return m_localScenes.TryGetValue(regionName, out scene); } public bool TryGetScene(UUID regionID, out Scene scene) { - lock (m_localScenes) - { - foreach (Scene mscene in m_localScenes) - { - if (mscene.RegionInfo.RegionID == regionID) - { - scene = mscene; - return true; - } - } - } - - scene = null; - return false; + return m_localScenes.TryGetValue(regionID, out scene); } public bool TryGetScene(uint locX, uint locY, out Scene scene) { - lock (m_localScenes) + List sceneList = Scenes; + foreach (Scene mscene in sceneList) { - foreach (Scene mscene in m_localScenes) + if (mscene.RegionInfo.RegionLocX == locX && + mscene.RegionInfo.RegionLocY == locY) { - if (mscene.RegionInfo.RegionLocX == locX && - mscene.RegionInfo.RegionLocY == locY) - { - scene = mscene; - return true; - } + scene = mscene; + return true; } } - + scene = null; return false; } public bool TryGetScene(IPEndPoint ipEndPoint, out Scene scene) { - lock (m_localScenes) + List sceneList = Scenes; + foreach (Scene mscene in sceneList) { - foreach (Scene mscene in m_localScenes) + if ((mscene.RegionInfo.InternalEndPoint.Equals(ipEndPoint.Address)) && + (mscene.RegionInfo.InternalEndPoint.Port == ipEndPoint.Port)) { - if ((mscene.RegionInfo.InternalEndPoint.Equals(ipEndPoint.Address)) && - (mscene.RegionInfo.InternalEndPoint.Port == ipEndPoint.Port)) - { - scene = mscene; - return true; - } + scene = mscene; + return true; } } - + scene = null; return false; } @@ -511,15 +454,10 @@ namespace OpenSim.Region.Framework.Scenes public RegionInfo GetRegionInfo(UUID regionID) { - lock (m_localScenes) + Scene s; + if (m_localScenes.TryGetValue(regionID, out s)) { - foreach (Scene scene in m_localScenes) - { - if (scene.RegionInfo.RegionID == regionID) - { - return scene.RegionInfo; - } - } + return s.RegionInfo; } return null; @@ -537,14 +475,12 @@ namespace OpenSim.Region.Framework.Scenes public bool TryGetScenePresence(UUID avatarId, out ScenePresence avatar) { - lock (m_localScenes) + List sceneList = Scenes; + foreach (Scene scene in sceneList) { - foreach (Scene scene in m_localScenes) + if (scene.TryGetScenePresence(avatarId, out avatar)) { - if (scene.TryGetScenePresence(avatarId, out avatar)) - { - return true; - } + return true; } } @@ -554,15 +490,13 @@ namespace OpenSim.Region.Framework.Scenes public bool TryGetRootScenePresence(UUID avatarId, out ScenePresence avatar) { - lock (m_localScenes) + List sceneList = Scenes; + foreach (Scene scene in sceneList) { - foreach (Scene scene in m_localScenes) - { - avatar = scene.GetScenePresence(avatarId); + avatar = scene.GetScenePresence(avatarId); - if (avatar != null && !avatar.IsChildAgent) - return true; - } + if (avatar != null && !avatar.IsChildAgent) + return true; } avatar = null; @@ -572,21 +506,19 @@ namespace OpenSim.Region.Framework.Scenes public void CloseScene(Scene scene) { lock (m_localScenes) - m_localScenes.Remove(scene); + m_localScenes.Remove(scene.RegionInfo.RegionID); scene.Close(); } public bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) { - lock (m_localScenes) + List sceneList = Scenes; + foreach (Scene scene in sceneList) { - foreach (Scene scene in m_localScenes) + if (scene.TryGetAvatarByName(avatarName, out avatar)) { - if (scene.TryGetAvatarByName(avatarName, out avatar)) - { - return true; - } + return true; } } @@ -596,14 +528,12 @@ namespace OpenSim.Region.Framework.Scenes public bool TryGetRootScenePresenceByName(string firstName, string lastName, out ScenePresence sp) { - lock (m_localScenes) + List sceneList = Scenes; + foreach (Scene scene in sceneList) { - foreach (Scene scene in m_localScenes) - { - sp = scene.GetScenePresence(firstName, lastName); - if (sp != null && !sp.IsChildAgent) - return true; - } + sp = scene.GetScenePresence(firstName, lastName); + if (sp != null && !sp.IsChildAgent) + return true; } sp = null; @@ -612,8 +542,8 @@ namespace OpenSim.Region.Framework.Scenes public void ForEachScene(Action action) { - lock (m_localScenes) - m_localScenes.ForEach(action); + List sceneList = Scenes; + sceneList.ForEach(action); } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 81cef5b..c20c81d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -88,10 +88,6 @@ namespace OpenSim.Region.Framework.Scenes /// /// Stop and remove the scripts contained in all the prims in this group /// - /// - /// Should be true if these scripts are being removed because the scene - /// object is being deleted. This will prevent spurious updates to the client. - /// public void RemoveScriptInstances(bool sceneObjectBeingDeleted) { SceneObjectPart[] parts = m_parts.GetArray(); @@ -115,78 +111,81 @@ namespace OpenSim.Region.Framework.Scenes /// The user inventory item being added. /// The item UUID that should be used by the new item. /// - public bool AddInventoryItem(UUID agentID, uint localID, InventoryItemBase item, UUID copyItemID) + public bool AddInventoryItem(UUID agentID, uint localID, InventoryItemBase item, UUID copyItemID, bool withModRights = true) { // m_log.DebugFormat( -// "[PRIM INVENTORY]: Adding inventory item {0} from {1} to part with local ID {2}", +// "[PRIM INVENTORY]: Adding inventory item {0} from {1} to part with local ID {2}", // item.Name, remoteClient.Name, localID); - + UUID newItemId = (copyItemID != UUID.Zero) ? copyItemID : item.ID; SceneObjectPart part = GetPart(localID); - if (part != null) + if (part == null) { - TaskInventoryItem taskItem = new TaskInventoryItem(); - - taskItem.ItemID = newItemId; - taskItem.AssetID = item.AssetID; - taskItem.Name = item.Name; - taskItem.Description = item.Description; - taskItem.OwnerID = part.OwnerID; // Transfer ownership - taskItem.CreatorID = item.CreatorIdAsUuid; - taskItem.Type = item.AssetType; - taskItem.InvType = item.InvType; - - if (agentID != part.OwnerID && m_scene.Permissions.PropagatePermissions()) - { - taskItem.BasePermissions = item.BasePermissions & - item.NextPermissions; - taskItem.CurrentPermissions = item.CurrentPermissions & - item.NextPermissions; - taskItem.EveryonePermissions = item.EveryOnePermissions & - item.NextPermissions; - taskItem.GroupPermissions = item.GroupPermissions & - item.NextPermissions; - taskItem.NextPermissions = item.NextPermissions; - // We're adding this to a prim we don't own. Force - // owner change - taskItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; - } - else - { - taskItem.BasePermissions = item.BasePermissions; - taskItem.CurrentPermissions = item.CurrentPermissions; - taskItem.EveryonePermissions = item.EveryOnePermissions; - taskItem.GroupPermissions = item.GroupPermissions; - taskItem.NextPermissions = item.NextPermissions; - } - - taskItem.Flags = item.Flags; + m_log.ErrorFormat( + "[PRIM INVENTORY]: " + + "Couldn't find prim local ID {0} in group {1}, {2} to add inventory item ID {3}", + localID, Name, UUID, newItemId); + return false; + } -// m_log.DebugFormat( -// "[PRIM INVENTORY]: Flags are 0x{0:X} for item {1} added to part {2} by {3}", -// taskItem.Flags, taskItem.Name, localID, remoteClient.Name); - - // TODO: These are pending addition of those fields to TaskInventoryItem -// taskItem.SalePrice = item.SalePrice; -// taskItem.SaleType = item.SaleType; - taskItem.CreationDate = (uint)item.CreationDate; + TaskInventoryItem taskItem = new TaskInventoryItem(); - bool addFromAllowedDrop = agentID != part.OwnerID; + taskItem.ItemID = newItemId; + taskItem.AssetID = item.AssetID; + taskItem.Name = item.Name; + taskItem.Description = item.Description; + taskItem.OwnerID = part.OwnerID; // Transfer ownership + taskItem.CreatorID = item.CreatorIdAsUuid; + taskItem.Type = item.AssetType; + taskItem.InvType = item.InvType; - part.Inventory.AddInventoryItem(taskItem, addFromAllowedDrop); + if (agentID != part.OwnerID && m_scene.Permissions.PropagatePermissions()) + { + taskItem.BasePermissions = item.BasePermissions & + item.NextPermissions; + taskItem.CurrentPermissions = item.CurrentPermissions & + item.NextPermissions; + taskItem.EveryonePermissions = item.EveryOnePermissions & + item.NextPermissions; + taskItem.GroupPermissions = item.GroupPermissions & + item.NextPermissions; + taskItem.NextPermissions = item.NextPermissions; + // We're adding this to a prim we don't own. Force + // owner change + taskItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; - return true; } else { - m_log.ErrorFormat( - "[PRIM INVENTORY]: " + - "Couldn't find prim local ID {0} in group {1}, {2} to add inventory item ID {3}", - localID, Name, UUID, newItemId); + taskItem.BasePermissions = item.BasePermissions; + taskItem.CurrentPermissions = item.CurrentPermissions; + taskItem.EveryonePermissions = item.EveryOnePermissions; + taskItem.GroupPermissions = item.GroupPermissions; + taskItem.NextPermissions = item.NextPermissions; } - return false; + taskItem.Flags = item.Flags; + +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Flags are 0x{0:X} for item {1} added to part {2} by {3}", +// taskItem.Flags, taskItem.Name, localID, remoteClient.Name); + + // TODO: These are pending addition of those fields to TaskInventoryItem +// taskItem.SalePrice = item.SalePrice; +// taskItem.SaleType = item.SaleType; + taskItem.CreationDate = (uint)item.CreationDate; + + bool addFromAllowedDrop; + if(withModRights) + addFromAllowedDrop = false; + else + addFromAllowedDrop = (part.ParentGroup.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) != 0; + + part.Inventory.AddInventoryItem(taskItem, addFromAllowedDrop); + part.ParentGroup.InvalidateEffectivePerms(); + return true; + } /// @@ -252,21 +251,201 @@ namespace OpenSim.Region.Framework.Scenes return -1; } - public uint GetEffectivePermissions() + // new test code, to place in better place later + private object m_PermissionsLock = new object(); + private bool m_EffectivePermsInvalid = true; + private bool m_DeepEffectivePermsInvalid = true; + + // should called when parts chanced by their contents did not, so we know their cacche is valid + // in case of doubt call InvalidateDeepEffectivePerms(), it only costs a bit more cpu time + public void InvalidateEffectivePerms() + { + lock(m_PermissionsLock) + m_EffectivePermsInvalid = true; + } + + // should called when parts chanced and their contents where accounted for + public void InvalidateDeepEffectivePerms() + { + lock(m_PermissionsLock) + { + m_DeepEffectivePermsInvalid = true; + m_EffectivePermsInvalid = true; + } + } + + private uint m_EffectiveEveryOnePerms; + public uint EffectiveEveryOnePerms + { + get + { + lock(m_PermissionsLock) + { + if(m_EffectivePermsInvalid) + AggregatePerms(); + return m_EffectiveEveryOnePerms; + } + } + } + + private uint m_EffectiveGroupPerms; + public uint EffectiveGroupPerms + { + get + { + lock(m_PermissionsLock) + { + if(m_EffectivePermsInvalid) + AggregatePerms(); + return m_EffectiveGroupPerms; + } + } + } + + private uint m_EffectiveGroupOrEveryOnePerms; + public uint EffectiveGroupOrEveryOnePerms + { + get + { + lock(m_PermissionsLock) + { + if(m_EffectivePermsInvalid) + AggregatePerms(); + return m_EffectiveGroupOrEveryOnePerms; + } + } + } + + private uint m_EffectiveOwnerPerms; + public uint EffectiveOwnerPerms + { + get + { + lock(m_PermissionsLock) + { + if(m_EffectivePermsInvalid) + AggregatePerms(); + return m_EffectiveOwnerPerms; + } + } + } + + public void AggregatePerms() + { + lock(m_PermissionsLock) + { + // aux + const uint allmask = (uint)PermissionMask.AllEffective; + const uint movemodmask = (uint)(PermissionMask.Move | PermissionMask.Modify); + const uint copytransfermast = (uint)(PermissionMask.Copy | PermissionMask.Transfer); + + uint basePerms = (RootPart.BaseMask & allmask) | (uint)PermissionMask.Move; + bool noBaseTransfer = (basePerms & (uint)PermissionMask.Transfer) == 0; + + uint rootOwnerPerms = RootPart.OwnerMask; + uint owner = rootOwnerPerms; + uint rootGroupPerms = RootPart.GroupMask; + uint group = rootGroupPerms; + uint rootEveryonePerms = RootPart.EveryoneMask; + uint everyone = rootEveryonePerms; + + bool needUpdate = false; + // date is time of writing april 30th 2017 + bool newobj = (RootPart.CreationDate == 0 || RootPart.CreationDate > 1493574994); + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + + if(m_DeepEffectivePermsInvalid) + part.AggregatedInnerPermsForGroup(); + + owner &= part.AggregatedInnerOwnerPerms; + group &= part.AggregatedInnerGroupPerms; + if(newobj) + group &= part.AggregatedInnerGroupPerms; + if(newobj) + everyone &= part.AggregatedInnerEveryonePerms; + } + // recover modify and move + rootOwnerPerms &= movemodmask; + owner |= rootOwnerPerms; + if((owner & copytransfermast) == 0) + owner |= (uint)PermissionMask.Transfer; + + owner &= basePerms; + if(owner != m_EffectiveOwnerPerms) + { + needUpdate = true; + m_EffectiveOwnerPerms = owner; + } + + uint ownertransfermask = owner & (uint)PermissionMask.Transfer; + + // recover modify and move + rootGroupPerms &= movemodmask; + group |= rootGroupPerms; + if(noBaseTransfer) + group &=~(uint)PermissionMask.Copy; + else + group |= ownertransfermask; + + uint groupOrEveryone = group; + uint tmpPerms = group & owner; + if(tmpPerms != m_EffectiveGroupPerms) + { + needUpdate = true; + m_EffectiveGroupPerms = tmpPerms; + } + + // recover move + rootEveryonePerms &= (uint)PermissionMask.Move; + everyone |= rootEveryonePerms; + everyone &= ~(uint)PermissionMask.Modify; + if(noBaseTransfer) + everyone &=~(uint)PermissionMask.Copy; + else + everyone |= ownertransfermask; + + groupOrEveryone |= everyone; + + tmpPerms = everyone & owner; + if(tmpPerms != m_EffectiveEveryOnePerms) + { + needUpdate = true; + m_EffectiveEveryOnePerms = tmpPerms; + } + + tmpPerms = groupOrEveryone & owner; + if(tmpPerms != m_EffectiveGroupOrEveryOnePerms) + { + needUpdate = true; + m_EffectiveGroupOrEveryOnePerms = tmpPerms; + } + + m_DeepEffectivePermsInvalid = false; + m_EffectivePermsInvalid = false; + + if(needUpdate) + RootPart.ScheduleFullUpdate(); + } + } + + public uint CurrentAndFoldedNextPermissions() { uint perms=(uint)(PermissionMask.Modify | PermissionMask.Copy | PermissionMask.Move | - PermissionMask.Transfer) | 7; + PermissionMask.Transfer | + PermissionMask.FoldedMask); - uint ownerMask = 0x7fffffff; + uint ownerMask = RootPart.OwnerMask; SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; -// m_log.DebugFormat("[SCENE OBJECT GROUP INVENTORY]: Effective perms of {0} are {1}", part.Name, (OpenMetaverse.PermissionMask)part.OwnerMask); - ownerMask &= part.OwnerMask; + ownerMask &= part.BaseMask; perms &= part.Inventory.MaskEffectivePermissions(); } @@ -276,17 +455,8 @@ namespace OpenSim.Region.Framework.Scenes perms &= ~(uint)PermissionMask.Copy; if ((ownerMask & (uint)PermissionMask.Transfer) == 0) perms &= ~(uint)PermissionMask.Transfer; - - // If root prim permissions are applied here, this would screw - // with in-inventory manipulation of the next owner perms - // in a major way. So, let's move this to the give itself. - // Yes. I know. Evil. -// if ((ownerMask & RootPart.NextOwnerMask & (uint)PermissionMask.Modify) == 0) -// perms &= ~((uint)PermissionMask.Modify >> 13); -// if ((ownerMask & RootPart.NextOwnerMask & (uint)PermissionMask.Copy) == 0) -// perms &= ~((uint)PermissionMask.Copy >> 13); -// if ((ownerMask & RootPart.NextOwnerMask & (uint)PermissionMask.Transfer) == 0) -// perms &= ~((uint)PermissionMask.Transfer >> 13); + if ((ownerMask & (uint)PermissionMask.Export) == 0) + perms &= ~(uint)PermissionMask.Export; return perms; } @@ -323,18 +493,19 @@ namespace OpenSim.Region.Framework.Scenes xmldoc.AppendChild(xmlnode); XmlElement rootElement = xmldoc.CreateElement("", "ScriptData", String.Empty); - + xmldoc.AppendChild(rootElement); - + XmlElement wrapper = xmldoc.CreateElement("", "ScriptStates", String.Empty); - + rootElement.AppendChild(wrapper); foreach (KeyValuePair state in states) { XmlDocument sdoc = new XmlDocument(); + sdoc.XmlResolver=null; sdoc.LoadXml(state.Value); XmlNodeList rootL = sdoc.GetElementsByTagName("State"); XmlNode rootNode = rootL[0]; @@ -357,7 +528,7 @@ namespace OpenSim.Region.Framework.Scenes return; IScriptModule scriptModule = null; - + foreach (IScriptModule sm in s.RequestModuleInterfaces()) { if (sm.ScriptEngineName == s.DefaultScriptEngine) @@ -370,6 +541,7 @@ namespace OpenSim.Region.Framework.Scenes return; XmlDocument doc = new XmlDocument(); + doc.XmlResolver=null; try { doc.LoadXml(objXMLData); @@ -396,7 +568,7 @@ namespace OpenSim.Region.Framework.Scenes return; XmlElement dataE = (XmlElement)dataL[0]; - + foreach (XmlNode n in dataE.ChildNodes) { XmlElement stateE = (XmlElement)n; @@ -408,6 +580,9 @@ namespace OpenSim.Region.Framework.Scenes public void ResumeScripts() { + if (m_scene.RegionInfo.RegionSettings.DisableScripts) + return; + SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) parts[i].Inventory.ResumeScripts(); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index d08237e..21311b0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -30,6 +30,7 @@ using System.ComponentModel; using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Xml; @@ -45,6 +46,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.Framework.Scenes { + [Flags] public enum scriptEvents { @@ -77,17 +79,18 @@ namespace OpenSim.Region.Framework.Scenes touch_end = 536870912, touch_start = 2097152, transaction_result = 33554432, - object_rez = 4194304 + object_rez = 4194304, + anytouch = touch | touch_end | touch_start } - struct scriptPosTarget + public struct scriptPosTarget { public Vector3 targetPos; public float tolerance; public uint handle; } - struct scriptRotTarget + public struct scriptRotTarget { public Quaternion targetRot; public float tolerance; @@ -109,11 +112,11 @@ namespace OpenSim.Region.Framework.Scenes STATUS_ROTATE_X = 0x002, STATUS_ROTATE_Y = 0x004, STATUS_ROTATE_Z = 0x008, + NOT_STATUS_ROTATE_X = 0xFD, + NOT_STATUS_ROTATE_Y = 0xFB, + NOT_STATUS_ROTATE_Z = 0xF7 } - // This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm - public static readonly uint SLAM = 16; - // private PrimCountTaintedDelegate handlerPrimCountTainted = null; /// @@ -121,8 +124,11 @@ namespace OpenSim.Region.Framework.Scenes /// since the group's last persistent backup /// private bool m_hasGroupChanged = false; - private long timeFirstChanged; - private long timeLastChanged; + private long timeFirstChanged = 0; + private long timeLastChanged = 0; + private long m_maxPersistTime = 0; + private long m_minPersistTime = 0; +// private Random m_rand; /// /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage @@ -139,12 +145,47 @@ namespace OpenSim.Region.Framework.Scenes { if (value) { - timeLastChanged = DateTime.Now.Ticks; + + if (Backup) + { + m_scene.SceneGraph.FireChangeBackup(this); + } + timeLastChanged = DateTime.UtcNow.Ticks; if (!m_hasGroupChanged) - timeFirstChanged = DateTime.Now.Ticks; + timeFirstChanged = DateTime.UtcNow.Ticks; + if (m_rootPart != null && m_scene != null) + { +/* + if (m_rand == null) + { + byte[] val = new byte[16]; + m_rootPart.UUID.ToBytes(val, 0); + m_rand = new Random(BitConverter.ToInt32(val, 0)); + } + */ + if (m_scene.GetRootAgentCount() == 0) + { + //If the region is empty, this change has been made by an automated process + //and thus we delay the persist time by a random amount between 1.5 and 2.5. + +// float factor = 1.5f + (float)(m_rand.NextDouble()); + float factor = 2.0f; + m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor); + m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor); + } + else + { + //If the region is not empty, we want to obey the minimum and maximum persist times + //but add a random factor so we stagger the object persistance a little +// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5 +// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0 + m_maxPersistTime = m_scene.m_persistAfter; + m_minPersistTime = m_scene.m_dontPersistBefore; + } + } } m_hasGroupChanged = value; - + // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId); } @@ -153,7 +194,7 @@ namespace OpenSim.Region.Framework.Scenes } private bool m_groupContainsForeignPrims = false; - + /// /// Whether the group contains prims that came from a different group. This happens when /// linking or delinking groups. The implication is that until the group is persisted, @@ -172,6 +213,7 @@ namespace OpenSim.Region.Framework.Scenes get { return m_groupContainsForeignPrims; } } + public bool HasGroupChangedDueToDelink { get; set; } private bool isTimeToPersist() { @@ -181,8 +223,19 @@ namespace OpenSim.Region.Framework.Scenes return false; if (m_scene.ShuttingDown) return true; - long currentTime = DateTime.Now.Ticks; - if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) + + if (m_minPersistTime == 0 || m_maxPersistTime == 0) + { + m_maxPersistTime = m_scene.m_persistAfter; + m_minPersistTime = m_scene.m_dontPersistBefore; + } + + long currentTime = DateTime.UtcNow.Ticks; + + if (timeLastChanged == 0) timeLastChanged = currentTime; + if (timeFirstChanged == 0) timeFirstChanged = currentTime; + + if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime) return true; return false; } @@ -240,6 +293,11 @@ namespace OpenSim.Region.Framework.Scenes { AttachmentPoint = 0; + // Don't zap trees + if (RootPart.Shape.PCode == (byte)PCode.Tree || + RootPart.Shape.PCode == (byte)PCode.NewTree) + return; + // Even though we don't use child part state parameters for attachments any more, we still need to set // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if // we store them correctly, scene objects that we receive from elsewhere might not. @@ -269,6 +327,7 @@ namespace OpenSim.Region.Framework.Scenes get { return (RootPart.Flags & PrimFlags.Physics) != 0; } } + /// /// Is this scene object temporary? /// @@ -285,9 +344,6 @@ namespace OpenSim.Region.Framework.Scenes get { return RootPart.VolumeDetectActive; } } - private Vector3 lastPhysGroupPos; - private Quaternion lastPhysGroupRot; - /// /// Is this entity set to be saved in persistent storage? /// @@ -299,17 +355,29 @@ namespace OpenSim.Region.Framework.Scenes protected SceneObjectPart m_rootPart; // private Dictionary m_scriptEvents = new Dictionary(); - private Dictionary m_targets = new Dictionary(); - private Dictionary m_rotTargets = new Dictionary(); + private SortedDictionary m_targets = new SortedDictionary(); + private SortedDictionary m_rotTargets = new SortedDictionary(); + + public SortedDictionary AtTargets + { + get { return m_targets; } + } + + public SortedDictionary RotTargets + { + get { return m_rotTargets; } + } private bool m_scriptListens_atTarget; private bool m_scriptListens_notAtTarget; - private bool m_scriptListens_atRotTarget; private bool m_scriptListens_notAtRotTarget; + public bool m_dupeInProgress = false; internal Dictionary m_savedScriptState; + public UUID MonitoringObject { get; set; } + #region Properties /// @@ -344,6 +412,16 @@ namespace OpenSim.Region.Framework.Scenes get { return m_parts.Count; } } +// protected Quaternion m_rotation = Quaternion.Identity; +// +// public virtual Quaternion Rotation +// { +// get { return m_rotation; } +// set { +// m_rotation = value; +// } +// } + public Quaternion GroupRotation { get { return m_rootPart.RotationOffset; } @@ -356,27 +434,27 @@ namespace OpenSim.Region.Framework.Scenes Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize); Vector3 maxScale = Vector3.Zero; Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); - + SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; Vector3 partscale = part.Scale; Vector3 partoffset = part.OffsetPosition; - + minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; - + maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; } - + finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; - + return finalScale; } } @@ -441,7 +519,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't /// have the IsAttachment property yet checked. - /// + /// /// FIXME: However, this should be fixed so that this property /// propertly reflects the underlying status. /// @@ -451,13 +529,17 @@ namespace OpenSim.Region.Framework.Scenes return (IsAttachment || (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0)); } - + private struct avtocrossInfo { public ScenePresence av; public uint ParentID; } + + public bool inTransit = false; + private delegate SceneObjectGroup SOGCrossDelegate(SceneObjectGroup sog,Vector3 pos, TeleportObjectData tpData); + /// /// The absolute position of this scene object in the scene /// @@ -467,142 +549,20 @@ namespace OpenSim.Region.Framework.Scenes set { Vector3 val = value; - - if (Scene != null) + if (Scene != null + && !Scene.PositionIsInCurrentRegion(val) + && !IsAttachmentCheckFull() + && !Scene.LoadingPrims + && !Scene.DisableObjectTransfer + ) { - if ( - !Scene.PositionIsInCurrentRegion(val) - && !IsAttachmentCheckFull() - && (!Scene.LoadingPrims) - ) + if (!inTransit) { - IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface(); - EntityTransferContext ctx = new EntityTransferContext(); - Vector3 newpos = Vector3.Zero; - string failureReason = String.Empty; - OpenSim.Services.Interfaces.GridRegion destination = null; - - if (m_rootPart.KeyframeMotion != null) - m_rootPart.KeyframeMotion.StartCrossingCheck(); - - bool canCross = true; - foreach (ScenePresence av in GetSittingAvatars()) - { - // We need to cross these agents. First, let's find - // out if any of them can't cross for some reason. - // We have to deny the crossing entirely if any - // of them are banned. Alternatively, we could - // unsit banned agents.... - - - // We set the avatar position as being the object - // position to get the region to send to - if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, ctx, out newpos, out failureReason)) == null) - { - canCross = false; - break; - } - - m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName); - } - - if (canCross) - { - // We unparent the SP quietly so that it won't - // be made to stand up - - List avsToCross = new List(); - - foreach (ScenePresence av in GetSittingAvatars()) - { - avtocrossInfo avinfo = new avtocrossInfo(); - SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID); - if (parentPart != null) - av.ParentUUID = parentPart.UUID; - - avinfo.av = av; - avinfo.ParentID = av.ParentID; - avsToCross.Add(avinfo); - - av.PrevSitOffset = av.OffsetPosition; - av.ParentID = 0; - } - - m_scene.CrossPrimGroupIntoNewRegion(val, this, true); - - // Normalize - if (val.X >= m_scene.RegionInfo.RegionSizeX) - val.X -= m_scene.RegionInfo.RegionSizeX; - if (val.Y >= m_scene.RegionInfo.RegionSizeY) - val.Y -= m_scene.RegionInfo.RegionSizeY; - if (val.X < 0) - val.X += m_scene.RegionInfo.RegionSizeX; - if (val.Y < 0) - val.Y += m_scene.RegionInfo.RegionSizeY; - - // If it's deleted, crossing was successful - if (IsDeleted) - { - foreach (avtocrossInfo avinfo in avsToCross) - { - ScenePresence av = avinfo.av; - if (!av.IsInTransit) // just in case... - { - m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val); - - av.IsInTransit = true; - - // A temporary measure to allow regression tests to work. - // Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget - // or similar since BeginInvoke() always uses the system threadpool to launch - // threads rather than any replace threadpool that we might be using. - if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest) - { - entityTransfer.CrossAgentToNewRegionAsync(av, val, destination, av.Flying, ctx); - CrossAgentToNewRegionCompleted(av); - } - else - { - CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync; - d.BeginInvoke( - av, val, destination, av.Flying, ctx, - ar => CrossAgentToNewRegionCompleted(d.EndInvoke(ar)), null); - } - } - else - { - m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val); - } - } - - return; - } - else // cross failed, put avas back ?? - { - foreach (avtocrossInfo avinfo in avsToCross) - { - ScenePresence av = avinfo.av; - av.ParentUUID = UUID.Zero; - av.ParentID = avinfo.ParentID; - } - } - } - else - { - if (m_rootPart.KeyframeMotion != null) - m_rootPart.KeyframeMotion.CrossingFailure(); - - if (RootPart.PhysActor != null) - { - RootPart.PhysActor.CrossingFailure(); - } - } - - Vector3 oldp = AbsolutePosition; - val.X = Util.Clamp(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f); - val.Y = Util.Clamp(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f); - val.Z = Util.Clamp(oldp.Z, 0.5f, Constants.RegionHeight); + inTransit = true; + SOGCrossDelegate d = CrossAsync; + d.BeginInvoke(this, val, null, CrossAsyncCompleted, d); } + return; } if (RootPart.GetStatusSandbox()) @@ -610,190 +570,703 @@ namespace OpenSim.Region.Framework.Scenes if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) { RootPart.ScriptSetPhysicsStatus(false); - + if (Scene != null) Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); - + return; } } - // Restuff the new GroupPosition into each SOP of the linkset. - // This has the affect of resetting and tainting the physics actors. + bool triggerScriptEvent = m_rootPart.GroupPosition != val; + if (m_dupeInProgress || IsDeleted) + triggerScriptEvent = false; + + m_rootPart.GroupPosition = val; + + // Restuff the new GroupPosition into each child SOP of the linkset. + // this is needed because physics may not have linksets but just loose SOPs in world + SceneObjectPart[] parts = m_parts.GetArray(); - for (int i = 0; i < parts.Length; i++) - parts[i].GroupPosition = val; - //if (m_rootPart.PhysActor != null) - //{ - //m_rootPart.PhysActor.Position = - //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y, - //m_rootPart.GroupPosition.Z); - //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); - //} - + foreach (SceneObjectPart part in parts) + { + if (part != m_rootPart) + part.GroupPosition = val; + } + + foreach (ScenePresence av in m_sittingAvatars) + { + av.sitSOGmoved(); + } + + // now that position is changed tell it to scripts + if (triggerScriptEvent) + { + foreach (SceneObjectPart part in parts) + { + part.TriggerScriptChangedEvent(Changed.POSITION); + } + } + if (Scene != null) Scene.EventManager.TriggerParcelPrimCountTainted(); + } } - public override Vector3 Velocity + private SceneObjectGroup CrossAsync(SceneObjectGroup sog, Vector3 val, TeleportObjectData tpdata) { - get { return RootPart.Velocity; } - set { RootPart.Velocity = value; } - } + Scene sogScene = sog.m_scene; + SceneObjectPart root = sog.RootPart; - private void CrossAgentToNewRegionCompleted(ScenePresence agent) - { - //// If the cross was successful, this agent is a child agent - if (agent.IsChildAgent) + bool isTeleport = tpdata != null; + + if(!isTeleport) { - if (agent.ParentUUID != UUID.Zero) + if (root.DIE_AT_EDGE) + { + try + { + sogScene.DeleteSceneObject(sog, false); + } + catch (Exception) + { + m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border."); + } + return sog; + } + + if (root.RETURN_AT_EDGE) { - agent.ParentPart = null; -// agent.ParentPosition = Vector3.Zero; -// agent.ParentUUID = UUID.Zero; + // We remove the object here + try + { + List localIDs = new List(); + localIDs.Add(root.LocalId); + sogScene.AddReturn(sog.OwnerID, sog.Name, sog.AbsolutePosition, + "Returned at region cross"); + sogScene.DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, UUID.Zero, false); + } + catch (Exception) + { + m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border."); + } + return sog; } } - agent.ParentUUID = UUID.Zero; -// agent.Reset(); -// else // Not successful -// agent.RestoreInCurrentScene(); +// if(!m_scene.IsRunning) +// return sog; - // In any case - agent.IsInTransit = false; + if (root.KeyframeMotion != null) + root.KeyframeMotion.StartCrossingCheck(); - m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); - } + if(root.PhysActor != null) + root.PhysActor.CrossingStart(); - public override uint LocalId - { - get { return m_rootPart.LocalId; } - set { m_rootPart.LocalId = value; } - } + IEntityTransferModule entityTransfer = sogScene.RequestModuleInterface(); - public override UUID UUID - { - get { return m_rootPart.UUID; } - set + if (entityTransfer == null) + return sog; + + Vector3 newpos = Vector3.Zero; + OpenSim.Services.Interfaces.GridRegion destination = null; + + destination = entityTransfer.GetObjectDestination(sog, val, out newpos); + if (destination == null) + return sog; + + if (sog.m_sittingAvatars.Count == 0) { - lock (m_parts.SyncRoot) - { - m_parts.Remove(m_rootPart.UUID); - m_rootPart.UUID = value; - m_parts.Add(value, m_rootPart); - } + entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, !isTeleport, true); + return sog; } - } - public UUID LastOwnerID - { - get { return m_rootPart.LastOwnerID; } - set { m_rootPart.LastOwnerID = value; } - } + string reason = String.Empty; + EntityTransferContext ctx = new EntityTransferContext(); - public UUID OwnerID - { - get { return m_rootPart.OwnerID; } - set { m_rootPart.OwnerID = value; } - } + Vector3 curPos = root.GroupPosition; + foreach (ScenePresence av in sog.m_sittingAvatars) + { + // We need to cross these agents. First, let's find + // out if any of them can't cross for some reason. + // We have to deny the crossing entirely if any + // of them are banned. Alternatively, we could + // unsit banned agents.... + + // We set the avatar position as being the object + // position to get the region to send to + if(av.IsNPC) + continue; - public float Damage - { - get { return m_rootPart.Damage; } - set { m_rootPart.Damage = value; } - } + if(av.IsInTransit) + return sog; - public Color Color - { - get { return m_rootPart.Color; } - set { m_rootPart.Color = value; } - } + if(!entityTransfer.checkAgentAccessToRegion(av, destination, newpos, ctx, out reason)) + return sog; - public string Text - { - get { - string returnstr = m_rootPart.Text; - if (returnstr.Length > 255) - { - returnstr = returnstr.Substring(0, 255); - } - return returnstr; + m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName); } - set { m_rootPart.Text = value; } - } - /// - /// If set to true then the scene object can be backed up in principle, though this will only actually occur - /// if Backup is set. If false then the scene object will never be backed up, Backup will always be false. - /// - protected virtual bool CanBeBackedUp - { - get { return true; } - } - - public bool IsSelected - { - get { return m_isSelected; } - set + // We unparent the SP quietly so that it won't + // be made to stand up + + List avsToCross = new List(); + List avsToCrossFar = new List(); + ulong destHandle = destination.RegionHandle; + List sittingAvatars = GetSittingAvatars(); + foreach (ScenePresence av in sittingAvatars) { - m_isSelected = value; - // Tell physics engine that group is selected + byte cflags = 1; - PhysicsActor pa = m_rootPart.PhysActor; - if (pa != null) + avtocrossInfo avinfo = new avtocrossInfo(); + SceneObjectPart parentPart = sogScene.GetSceneObjectPart(av.ParentID); + if (parentPart != null) { - pa.Selected = value; + av.ParentUUID = parentPart.UUID; + if(parentPart.SitTargetAvatar == av.UUID) + cflags = 7; // low 3 bits set + else + cflags = 3; + } + if(!av.knowsNeighbourRegion(destHandle)) + cflags |= 8; - // Pass it on to the children. - SceneObjectPart[] parts = m_parts.GetArray(); - for (int i = 0; i < parts.Length; i++) - { - SceneObjectPart child = parts[i]; + // 1 is crossing + // 2 is sitting + // 4 is sitting at sittarget + // 8 far crossing - PhysicsActor childPa = child.PhysActor; - if (childPa != null) - childPa.Selected = value; - } + avinfo.av = av; + avinfo.ParentID = av.ParentID; + avsToCross.Add(avinfo); + + if(!av.knowsNeighbourRegion(destHandle)) + { + cflags |= 8; + avsToCrossFar.Add(av); } - if (RootPart.KeyframeMotion != null) - RootPart.KeyframeMotion.Selected = value; - } - } - private SceneObjectPart m_PlaySoundMasterPrim = null; - public SceneObjectPart PlaySoundMasterPrim - { - get { return m_PlaySoundMasterPrim; } - set { m_PlaySoundMasterPrim = value; } - } + if(av.IsNPC) + av.crossingFlags = 0; + else + av.crossingFlags = cflags; - private List m_PlaySoundSlavePrims = new List(); - public List PlaySoundSlavePrims - { - get { return m_PlaySoundSlavePrims; } - set { m_PlaySoundSlavePrims = value; } - } + av.PrevSitOffset = av.OffsetPosition; + av.ParentID = 0; + } - private SceneObjectPart m_LoopSoundMasterPrim = null; - public SceneObjectPart LoopSoundMasterPrim - { - get { return m_LoopSoundMasterPrim; } - set { m_LoopSoundMasterPrim = value; } - } + Vector3 vel = root.Velocity; + Vector3 avel = root.AngularVelocity; + Vector3 acc = root.Acceleration; + Quaternion ori = root.RotationOffset; - private List m_LoopSoundSlavePrims = new List(); - public List LoopSoundSlavePrims - { - get { return m_LoopSoundSlavePrims; } - set { m_LoopSoundSlavePrims = value; } - } + if(isTeleport) + { + root.Stop(); + sogScene.ForEachScenePresence(delegate(ScenePresence av) + { + av.ControllingClient.SendEntityUpdate(root,PrimUpdateFlags.SendInTransit); + av.ControllingClient.SendEntityTerseUpdateImmediate(root); + }); - /// - /// The UUID for the region this object is in. - /// + root.Velocity = tpdata.vel; + root.AngularVelocity = tpdata.avel; + root.Acceleration = tpdata.acc; + root.RotationOffset = tpdata.ori; + } + + if (entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true, false)) + { + if(isTeleport) + { + sogScene.ForEachScenePresence(delegate(ScenePresence oav) + { + if(sittingAvatars.Contains(oav)) + return; + if(oav.knowsNeighbourRegion(destHandle)) + return; + oav.ControllingClient.SendEntityUpdate(root, PrimUpdateFlags.Kill); + foreach (ScenePresence sav in sittingAvatars) + { + sav.SendKillTo(oav); + } + }); + } + bool crossedfar = false; + foreach (ScenePresence av in avsToCrossFar) + { + if(entityTransfer.CrossAgentCreateFarChild(av,destination, newpos, ctx)) + crossedfar = true; + else + av.crossingFlags = 0; + } + + if(crossedfar) + Thread.Sleep(1000); + + foreach (avtocrossInfo avinfo in avsToCross) + { + ScenePresence av = avinfo.av; + av.IsInLocalTransit = true; + av.IsInTransit = true; + m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val); + + if(av.crossingFlags > 0) + entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, false, ctx); + + if (av.IsChildAgent) + { + // avatar crossed do some extra cleanup + if (av.ParentUUID != UUID.Zero) + { + av.ClearControls(); + av.ParentPart = null; + } + av.ParentUUID = UUID.Zero; + av.ParentPart = null; + // In any case + av.IsInTransit = false; + av.crossingFlags = 0; + m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname); + } + else + { + // avatar cross failed we need do dedicated standUp + // part of it was done at CrossAgentToNewRegionAsync + // so for now just remove the sog controls + // this may need extra care + av.UnRegisterSeatControls(sog.UUID); + av.ParentUUID = UUID.Zero; + av.ParentPart = null; + Vector3 oldp = curPos; + oldp.X = Util.Clamp(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f); + oldp.Y = Util.Clamp(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f); + av.AbsolutePosition = oldp; + av.crossingFlags = 0; + av.sitAnimation = "SIT"; + av.IsInTransit = false; + if(av.Animator!= null) + av.Animator.SetMovementAnimations("STAND"); + av.AddToPhysicalScene(false); + sogScene.ForEachScenePresence(delegate(ScenePresence oav) + { + if(sittingAvatars.Contains(oav)) + return; + if(oav.knowsNeighbourRegion(destHandle)) + av.SendAvatarDataToAgent(oav); + else + { + av.SendAvatarDataToAgent(oav); + av.SendAppearanceToAgent(oav); + if (av.Animator != null) + av.Animator.SendAnimPackToClient(oav.ControllingClient); + av.SendAttachmentsToAgentNF(oav); // not ok + } + }); + m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} failed.", av.Firstname, av.Lastname); + } + } + + if(crossedfar) + { + Thread.Sleep(10000); + foreach (ScenePresence av in avsToCrossFar) + { + if(av.IsChildAgent) + { + av.Scene.CloseAgent(av.UUID, false); + } + else + av.RemoveNeighbourRegion(destHandle); + } + } + avsToCrossFar.Clear(); + avsToCross.Clear(); + sog.RemoveScriptInstances(true); + sog.Clear(); + return sog; + } + else + { + if(isTeleport) + { + if((tpdata.flags & OSTPOBJ_STOPONFAIL) == 0) + { + root.Velocity = vel; + root.AngularVelocity = avel; + root.Acceleration = acc; + } + root.RotationOffset = ori; + } + foreach (avtocrossInfo avinfo in avsToCross) + { + ScenePresence av = avinfo.av; + av.ParentUUID = UUID.Zero; + av.ParentID = avinfo.ParentID; + av.crossingFlags = 0; + } + } + avsToCross.Clear(); + return sog; + } + + public void CrossAsyncCompleted(IAsyncResult iar) + { + SOGCrossDelegate icon = (SOGCrossDelegate)iar.AsyncState; + SceneObjectGroup sog = icon.EndInvoke(iar); + + if (!sog.IsDeleted) + { + SceneObjectPart rootp = sog.m_rootPart; + + Vector3 oldp = rootp.GroupPosition; + oldp.X = Util.Clamp(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f); + oldp.Y = Util.Clamp(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f); + rootp.GroupPosition = oldp; + + rootp.Stop(); + + SceneObjectPart[] parts = sog.m_parts.GetArray(); + + foreach (SceneObjectPart part in parts) + { + if (part != rootp) + part.GroupPosition = oldp; + } + + foreach (ScenePresence av in sog.m_sittingAvatars) + { + av.sitSOGmoved(); + } + + if (sog.m_rootPart.KeyframeMotion != null) + sog.m_rootPart.KeyframeMotion.CrossingFailure(); + + if (sog.RootPart.PhysActor != null) + sog.RootPart.PhysActor.CrossingFailure(); + + sog.inTransit = false; + AttachToBackup(); + sog.ScheduleGroupForFullUpdate(); + } + } + + private class TeleportObjectData + { + public int flags; + public Vector3 vel; + public Vector3 avel; + public Vector3 acc; + public Quaternion ori; + public UUID sourceID; + } + + // copy from LSL_constants.cs + const int OSTPOBJ_STOPATTARGET = 0x1; // stops at destination + const int OSTPOBJ_STOPONFAIL = 0x2; // stops at start if tp fails + const int OSTPOBJ_SETROT = 0x4; // the rotation is the final rotation, otherwise is a added rotation + + public int TeleportObject(UUID sourceID, Vector3 targetPosition, Quaternion rotation, int flags) + { + if(inTransit || IsDeleted || IsAttachmentCheckFull() || IsSelected || Scene == null) + return -1; + + inTransit = true; + + PhysicsActor pa = RootPart.PhysActor; + if(pa == null || RootPart.KeyframeMotion != null /*|| m_sittingAvatars.Count == 0*/) + { + inTransit = false; + return -1; + } + + bool stop = (flags & OSTPOBJ_STOPATTARGET) != 0; + bool setrot = (flags & OSTPOBJ_SETROT) != 0; + + rotation.Normalize(); + + Quaternion currentRot = RootPart.RotationOffset; + if(setrot) + rotation = Quaternion.Conjugate(currentRot) * rotation; + + bool dorot = setrot | (Math.Abs(rotation.W) < 0.99999); + + Vector3 vel = Vector3.Zero; + Vector3 avel = Vector3.Zero; + Vector3 acc = Vector3.Zero; + + if(!stop) + { + vel = RootPart.Velocity; + avel = RootPart.AngularVelocity; + acc = RootPart.Acceleration; + } + Quaternion ori = RootPart.RotationOffset; + + if(dorot) + { + if(!stop) + { + vel *= rotation; + avel *= rotation; + acc *= rotation; + } + ori *= rotation; + } + + if(Scene.PositionIsInCurrentRegion(targetPosition)) + { + if(Scene.InTeleportTargetsCoolDown(UUID, sourceID, 1.0)) + { + inTransit = false; + return -2; + } + + Vector3 curPos = AbsolutePosition; + ILandObject curLand = Scene.LandChannel.GetLandObject(curPos.X, curPos.Y); + float posX = targetPosition.X; + float posY = targetPosition.Y; + ILandObject land = Scene.LandChannel.GetLandObject(posX, posY); + if(land != null && land != curLand) + { + if(!Scene.Permissions.CanObjectEnterWithScripts(this, land)) + { + inTransit = false; + return -3; + } + + UUID agentID; + foreach (ScenePresence av in m_sittingAvatars) + { + agentID = av.UUID; + if(land.IsRestrictedFromLand(agentID) || land.IsBannedFromLand(agentID)) + { + inTransit = false; + return -4; + } + } + } + + RootPart.Velocity = vel; + RootPart.AngularVelocity = avel; + RootPart.Acceleration = acc; + RootPart.RotationOffset = ori; + + Vector3 s = RootPart.Scale * RootPart.RotationOffset; + float h = Scene.GetGroundHeight(posX, posY) + 0.5f * (float)Math.Abs(s.Z) + 0.01f; + if(targetPosition.Z < h) + targetPosition.Z = h; + + inTransit = false; + AbsolutePosition = targetPosition; + RootPart.ScheduleTerseUpdate(); + return 1; + } + + if(Scene.InTeleportTargetsCoolDown(UUID, sourceID, 20.0)) + { + inTransit = false; + return -1; + } + + TeleportObjectData tdata = new TeleportObjectData(); + tdata.flags = flags; + tdata.vel = vel; + tdata.avel = avel; + tdata.acc = acc; + tdata.ori = ori; + tdata.sourceID = sourceID; + + + SOGCrossDelegate d = CrossAsync; + d.BeginInvoke(this, targetPosition, tdata, CrossAsyncCompleted, d); + return 0; + } + + public override Vector3 Velocity + { + get { return RootPart.Velocity; } + set { RootPart.Velocity = value; } + } + + public override uint LocalId + { + get { return m_rootPart.LocalId; } + set { m_rootPart.LocalId = value; } + } + + public override UUID UUID + { + get { return m_rootPart.UUID; } + set + { + lock (m_parts.SyncRoot) + { + m_parts.Remove(m_rootPart.UUID); + m_rootPart.UUID = value; + m_parts.Add(value, m_rootPart); + } + } + } + + public UUID LastOwnerID + { + get { return m_rootPart.LastOwnerID; } + set { m_rootPart.LastOwnerID = value; } + } + + public UUID RezzerID + { + get { return m_rootPart.RezzerID; } + set { m_rootPart.RezzerID = value; } + } + + public UUID OwnerID + { + get { return m_rootPart.OwnerID; } + set { m_rootPart.OwnerID = value; } + } + + public float Damage + { + get { return m_rootPart.Damage; } + set { m_rootPart.Damage = value; } + } + + public Color Color + { + get { return m_rootPart.Color; } + set { m_rootPart.Color = value; } + } + + public string Text + { + get { + string returnstr = m_rootPart.Text; + if (returnstr.Length > 255) + { + returnstr = returnstr.Substring(0, 255); + } + return returnstr; + } + set { m_rootPart.Text = value; } + } + + /// + /// If set to true then the scene object can be backed up in principle, though this will only actually occur + /// if Backup is set. If false then the scene object will never be backed up, Backup will always be false. + /// + protected virtual bool CanBeBackedUp + { + get { return true; } + } + + public bool IsSelected + { + get { return m_isSelected; } + set + { + m_isSelected = value; + // Tell physics engine that group is selected + + // this is not right + // but ode engines should only really need to know about root part + // so they can put entire object simulation on hold and not colliding + // keep as was for now + + PhysicsActor pa = m_rootPart.PhysActor; + if (pa != null) + { + pa.Selected = value; + + // Pass it on to the children. + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart child = parts[i]; + + PhysicsActor childPa = child.PhysActor; + if (childPa != null) + childPa.Selected = value; + } + } + if (RootPart.KeyframeMotion != null) + RootPart.KeyframeMotion.Selected = value; + } + } + + public void PartSelectChanged(bool partSelect) + { + // any part selected makes group selected + if (m_isSelected == partSelect) + return; + + if (partSelect) + { + IsSelected = partSelect; +// if (!IsAttachment) +// ScheduleGroupForFullUpdate(); + } + else + { + // bad bad bad 2 heavy for large linksets + // since viewer does send lot of (un)selects + // this needs to be replaced by a specific list or count ? + // but that will require extra code in several places + + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part.IsSelected) + return; + } + IsSelected = partSelect; +// if (!IsAttachment) +// { +// ScheduleGroupForFullUpdate(); +// } + } + } + // PlaySoundMasterPrim no longer in use to remove + private SceneObjectPart m_PlaySoundMasterPrim = null; + public SceneObjectPart PlaySoundMasterPrim + { + get { return m_PlaySoundMasterPrim; } + set { m_PlaySoundMasterPrim = value; } + } + // PlaySoundSlavePrims no longer in use to remove + private List m_PlaySoundSlavePrims = new List(); + public List PlaySoundSlavePrims + { + get { return m_PlaySoundSlavePrims; } + set { m_PlaySoundSlavePrims = value; } + } + + // LoopSoundMasterPrim no longer in use to remove + private SceneObjectPart m_LoopSoundMasterPrim = null; + public SceneObjectPart LoopSoundMasterPrim + { + get { return m_LoopSoundMasterPrim; } + set { m_LoopSoundMasterPrim = value; } + } + + // m_LoopSoundSlavePrims no longer in use to remove + private List m_LoopSoundSlavePrims = new List(); + public List LoopSoundSlavePrims + { + get { return m_LoopSoundSlavePrims; } + set { m_LoopSoundSlavePrims = value; } + } + + private double m_lastCollisionSoundMS; + + /// + /// The UUID for the region this object is in. + /// public UUID RegionUUID { get @@ -820,7 +1293,12 @@ namespace OpenSim.Region.Framework.Scenes /// /// If not applicable will be UUID.Zero /// - public UUID FromPartID { get; set; } + /// obsolete use RezzerID + public UUID FromPartID + { + get { return RezzerID; } + set {RezzerID = value; } + } /// /// The folder ID that this object was rezzed from, if applicable. @@ -863,6 +1341,7 @@ namespace OpenSim.Region.Framework.Scenes /// public SceneObjectGroup() { + m_lastCollisionSoundMS = Util.GetTimeStampMS() + 1000.0; } /// @@ -880,8 +1359,8 @@ namespace OpenSim.Region.Framework.Scenes /// Constructor. This object is added to the scene later via AttachToScene() /// public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) - :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) - { + { + SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); } /// @@ -907,7 +1386,7 @@ namespace OpenSim.Region.Framework.Scenes if (itemid != UUID.Zero) m_savedScriptState[itemid] = node.InnerXml; } - } + } } } @@ -940,7 +1419,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}", Name); + m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0} id: {1}", Name,UUID); } } else @@ -956,18 +1435,21 @@ namespace OpenSim.Region.Framework.Scenes /// public virtual void AttachToBackup() { - if (CanBeBackedUp) + if (IsAttachment) return; + m_scene.SceneGraph.FireAttachToBackup(this); + +// if (InSceneBackup) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID); if (!Backup) m_scene.EventManager.OnBackup += ProcessBackup; - + Backup = true; } } - + /// /// Attach this object to a scene. It will also now appear to agents. /// @@ -1018,6 +1500,10 @@ namespace OpenSim.Region.Framework.Scenes EntityIntersection result = new EntityIntersection(); SceneObjectPart[] parts = m_parts.GetArray(); + + // Find closest hit here + float idist = float.MaxValue; + for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; @@ -1032,11 +1518,6 @@ namespace OpenSim.Region.Framework.Scenes EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); - // This may need to be updated to the maximum draw distance possible.. - // We might (and probably will) be checking for prim creation from other sims - // when the camera crosses the border. - float idist = Constants.RegionSize; - if (inter.HitTF) { // We need to find the closest prim to return to the testcaller along the ray @@ -1047,10 +1528,11 @@ namespace OpenSim.Region.Framework.Scenes result.obj = part; result.normal = inter.normal; result.distance = inter.distance; + + idist = inter.distance; } } } - return result; } @@ -1062,25 +1544,27 @@ namespace OpenSim.Region.Framework.Scenes /// public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) { - maxX = -256f; - maxY = -256f; - maxZ = -256f; - minX = 10000f; - minY = 10000f; - minZ = 10000f; + maxX = float.MinValue; + maxY = float.MinValue; + maxZ = float.MinValue; + minX = float.MaxValue; + minY = float.MaxValue; + minZ = float.MaxValue; SceneObjectPart[] parts = m_parts.GetArray(); - for (int i = 0; i < parts.Length; i++) + foreach (SceneObjectPart part in parts) { - SceneObjectPart part = parts[i]; - Vector3 worldPos = part.GetWorldPosition(); Vector3 offset = worldPos - AbsolutePosition; Quaternion worldRot; if (part.ParentID == 0) + { worldRot = part.RotationOffset; + } else + { worldRot = part.GetWorldRotation(); + } Vector3 frontTopLeft; Vector3 frontTopRight; @@ -1092,6 +1576,8 @@ namespace OpenSim.Region.Framework.Scenes Vector3 backBottomLeft; Vector3 backBottomRight; + // Vector3[] corners = new Vector3[8]; + Vector3 orig = Vector3.Zero; frontTopLeft.X = orig.X - (part.Scale.X / 2); @@ -1126,6 +1612,38 @@ namespace OpenSim.Region.Framework.Scenes backBottomRight.Y = orig.Y + (part.Scale.Y / 2); backBottomRight.Z = orig.Z - (part.Scale.Z / 2); + + + //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); + //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); + //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); + //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); + //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); + //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); + //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); + //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); + + //for (int i = 0; i < 8; i++) + //{ + // corners[i] = corners[i] * worldRot; + // corners[i] += offset; + + // if (corners[i].X > maxX) + // maxX = corners[i].X; + // if (corners[i].X < minX) + // minX = corners[i].X; + + // if (corners[i].Y > maxY) + // maxY = corners[i].Y; + // if (corners[i].Y < minY) + // minY = corners[i].Y; + + // if (corners[i].Z > maxZ) + // maxZ = corners[i].Y; + // if (corners[i].Z < minZ) + // minZ = corners[i].Z; + //} + frontTopLeft = frontTopLeft * worldRot; frontTopRight = frontTopRight * worldRot; frontBottomLeft = frontBottomLeft * worldRot; @@ -1147,6 +1665,15 @@ namespace OpenSim.Region.Framework.Scenes backTopLeft += offset; backTopRight += offset; + //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); + //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); + //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); + //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); + //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); + //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); + //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); + //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); + if (frontTopRight.X > maxX) maxX = frontTopRight.X; if (frontTopLeft.X > maxX) @@ -1290,17 +1817,192 @@ namespace OpenSim.Region.Framework.Scenes #endregion + private float? m_boundsRadius = null; + public void InvalidBoundsRadius() + { + m_boundsRadius = null; + } + + private Vector3 m_boundsCenter; + public Vector3 getBoundsCenter() + { + // math is done in GetBoundsRadius(); + if(m_boundsRadius == null) + GetBoundsRadius(); + return m_boundsCenter; + } + + private float m_areaFactor; + public float getAreaFactor() + { + // math is done in GetBoundsRadius(); + if(m_boundsRadius == null) + GetBoundsRadius(); + return m_areaFactor; + } + + public float GetBoundsRadius() + { + // this may need more threading work + if(m_boundsRadius == null) + { + float res = 0; + float areaF = 0; + SceneObjectPart p; + SceneObjectPart[] parts; + float partR; + Vector3 offset = Vector3.Zero; + lock (m_parts) + { + parts = m_parts.GetArray(); + } + + int nparts = parts.Length; + for (int i = 0; i < nparts; i++) + { + p = parts[i]; + partR = 0.5f * p.Scale.Length(); + if(p != RootPart) + { + partR += p.OffsetPosition.Length(); + offset += p.OffsetPosition; + } + if(partR > res) + res = partR; + if(p.maxSimpleArea() > areaF) + areaF = p.maxSimpleArea(); + } + if(parts.Length > 1) + { + offset /= parts.Length; // basicly geometric center + offset = offset * RootPart.RotationOffset; + } + + areaF = 10.0f / areaF; // scale it + areaF = Util.Clamp(areaF, 0.001f, 1000f); // clamp it + + m_areaFactor = (float)Math.Sqrt(areaF); + m_boundsCenter = offset; + m_boundsRadius = res; + return res; + } + + return m_boundsRadius.Value; + } + + public void GetResourcesCosts(SceneObjectPart apart, + out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost) + { + // this information may need to be cached + + float cost; + float tmpcost; + + bool ComplexCost = false; + + SceneObjectPart p; + SceneObjectPart[] parts; + + lock (m_parts) + { + parts = m_parts.GetArray(); + } + + int nparts = parts.Length; + + + for (int i = 0; i < nparts; i++) + { + p = parts[i]; + + if (p.UsesComplexCost) + { + ComplexCost = true; + break; + } + } + + if (ComplexCost) + { + linksetResCost = 0; + linksetPhysCost = 0; + partCost = 0; + partPhysCost = 0; + + for (int i = 0; i < nparts; i++) + { + p = parts[i]; + + cost = p.StreamingCost; + tmpcost = p.SimulationCost; + if (tmpcost > cost) + cost = tmpcost; + tmpcost = p.PhysicsCost; + if (tmpcost > cost) + cost = tmpcost; + + linksetPhysCost += tmpcost; + linksetResCost += cost; + + if (p == apart) + { + partCost = cost; + partPhysCost = tmpcost; + } + } + } + else + { + partPhysCost = 1.0f; + partCost = 1.0f; + linksetResCost = (float)nparts; + linksetPhysCost = linksetResCost; + } + } + + public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost) + { + SceneObjectPart p; + SceneObjectPart[] parts; + + lock (m_parts) + { + parts = m_parts.GetArray(); + } + + int nparts = parts.Length; + + PhysCost = 0; + StreamCost = 0; + SimulCost = 0; + + for (int i = 0; i < nparts; i++) + { + p = parts[i]; + + StreamCost += p.StreamingCost; + SimulCost += p.SimulationCost; + PhysCost += p.PhysicsCost; + } + } + public void SaveScriptedState(XmlTextWriter writer) { + SaveScriptedState(writer, false); + } + + public void SaveScriptedState(XmlTextWriter writer, bool oldIDs) + { XmlDocument doc = new XmlDocument(); + doc.XmlResolver=null; Dictionary states = new Dictionary(); SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { - Dictionary pstates = parts[i].Inventory.GetScriptStates(); + Dictionary pstates = parts[i].Inventory.GetScriptStates(oldIDs); foreach (KeyValuePair kvp in pstates) - states.Add(kvp.Key, kvp.Value); + states[kvp.Key] = kvp.Value; } if (states.Count > 0) @@ -1319,6 +2021,73 @@ namespace OpenSim.Region.Framework.Scenes } } + public byte GetAttachmentPoint() + { + return m_rootPart.Shape.State; + } + + public void DetachToGround() + { + ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); + if (avatar == null) + return; + m_rootPart.Shape.LastAttachPoint = m_rootPart.Shape.State; + m_rootPart.AttachedPos = m_rootPart.OffsetPosition; + avatar.RemoveAttachment(this); + + Vector3 detachedpos = new Vector3(127f,127f,127f); + if (avatar == null) + return; + + detachedpos = avatar.AbsolutePosition; + FromItemID = UUID.Zero; + + AbsolutePosition = detachedpos; + AttachedAvatar = UUID.Zero; + + //SceneObjectPart[] parts = m_parts.GetArray(); + //for (int i = 0; i < parts.Length; i++) + // parts[i].AttachedAvatar = UUID.Zero; + + m_rootPart.SetParentLocalId(0); + AttachmentPoint = (byte)0; + // must check if buildind should be true or false here +// m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false); + ApplyPhysics(); + + HasGroupChanged = true; + RootPart.Rezzed = DateTime.Now; + RootPart.RemFlag(PrimFlags.TemporaryOnRez); + AttachToBackup(); + m_scene.EventManager.TriggerParcelPrimCountTainted(); + m_rootPart.ScheduleFullUpdate(); + m_rootPart.ClearUndoState(); + } + + public void DetachToInventoryPrep() + { + ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); + //Vector3 detachedpos = new Vector3(127f, 127f, 127f); + if (avatar != null) + { + //detachedpos = avatar.AbsolutePosition; + avatar.RemoveAttachment(this); + } + + AttachedAvatar = UUID.Zero; + + /*SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + parts[i].AttachedAvatar = UUID.Zero;*/ + + m_rootPart.SetParentLocalId(0); + //m_rootPart.SetAttachmentPoint((byte)0); + IsAttachment = false; + AbsolutePosition = m_rootPart.AttachedPos; + //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim); + //AttachToBackup(); + //m_rootPart.ScheduleFullUpdate(); + } /// /// @@ -1334,7 +2103,7 @@ namespace OpenSim.Region.Framework.Scenes { return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); } - + /// /// Set a part to act as the root part for this scene object /// @@ -1349,7 +2118,7 @@ namespace OpenSim.Region.Framework.Scenes if (!IsAttachment) part.ParentID = 0; part.LinkNum = 0; - + m_parts.Add(m_rootPart.UUID, m_rootPart); } @@ -1360,9 +2129,13 @@ namespace OpenSim.Region.Framework.Scenes public void AddPart(SceneObjectPart part) { part.SetParent(this); - part.LinkNum = m_parts.Add(part.UUID, part); + m_parts.Add(part.UUID, part); + + part.LinkNum = m_parts.Count; + if (part.LinkNum == 2) RootPart.LinkNum = 1; + InvalidatePartsLinkMaps(); } /// @@ -1386,32 +2159,50 @@ namespace OpenSim.Region.Framework.Scenes parts[i].UUID = UUID.Random(); } + // helper provided for parts. + public int GetSceneMaxUndo() + { + if (m_scene != null) + return m_scene.MaxUndoCount; + return 5; + } + // justincc: I don't believe this hack is needed any longer, especially since the physics // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false // this method was preventing proper reload of scene objects. - + // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects // at region startup - - // teravus: After this was removed from the linking algorithm, Linked prims no longer collided + + // teravus: After this was removed from the linking algorithm, Linked prims no longer collided // properly when non-physical if they havn't been moved. This breaks ALL builds. // see: http://opensimulator.org/mantis/view.php?id=3108 - - // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the - // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and - // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute + + // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the + // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and + // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute // Position has been set! - + public void ResetChildPrimPhysicsPositions() { // Setting this SOG's absolute position also loops through and sets the positions // of the SOP's in this SOG's linkset. This has the side affect of making sure // the physics world matches the simulated world. - AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? + // AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? // teravus: AbsolutePosition is NOT a normal property! // the code in the getter of AbsolutePosition is significantly different then the code in the setter! // jhurliman: Then why is it a property instead of two methods? + + // do only what is supposed to do + Vector3 groupPosition = m_rootPart.GroupPosition; + SceneObjectPart[] parts = m_parts.GetArray(); + + foreach (SceneObjectPart part in parts) + { + if (part != m_rootPart) + part.GroupPosition = groupPosition; + } } public UUID GetPartsFullID(uint localID) @@ -1443,7 +2234,7 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", // remoteClient.Name, part.Name, part.LocalId, offsetPos); - part.StoreUndoState(); +// part.StoreUndoState(); part.OnGrab(offsetPos, remoteClient); } @@ -1463,15 +2254,23 @@ namespace OpenSim.Region.Framework.Scenes /// If true then deletion is not broadcast to clients public void DeleteGroupFromScene(bool silent) { + // We need to keep track of this state in case this group is still queued for backup. + IsDeleted = true; + + DetachFromBackup(); + + if(Scene == null) // should not happen unless restart/shutdown ? + return; + SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; - Scene.ForEachScenePresence(sp => + Scene.ForEachScenePresence(delegate(ScenePresence avatar) { - if (!sp.IsChildAgent && sp.ParentID == part.LocalId) - sp.StandUp(); + if (!avatar.IsChildAgent && avatar.ParentID == part.LocalId && avatar.ParentUUID == UUID.Zero) + avatar.StandUp(); if (!silent) { @@ -1479,9 +2278,14 @@ namespace OpenSim.Region.Framework.Scenes if (part == m_rootPart) { if (!IsAttachment - || AttachedAvatar == sp.UUID + || AttachedAvatar == avatar.ControllingClient.AgentId || !HasPrivateAttachmentPoint) - sp.ControllingClient.SendKillObject(new List { part.LocalId }); + { + // Send a kill object immediately + avatar.ControllingClient.SendKillObject(new List { part.LocalId }); + //direct enqueue another delayed kill + avatar.ControllingClient.SendEntityUpdate(part,PrimUpdateFlags.Kill); + } } } }); @@ -1499,6 +2303,12 @@ namespace OpenSim.Region.Framework.Scenes d.AddActiveScripts(count); } + private const scriptEvents PhysicsNeeedSubsEvents = ( + scriptEvents.collision | scriptEvents.collision_start | scriptEvents.collision_end | + scriptEvents.land_collision | scriptEvents.land_collision_start | scriptEvents.land_collision_end); + + private scriptEvents lastRootPartPhysEvents = 0; + public void aggregateScriptEvents() { PrimFlags objectflagupdate = (PrimFlags)RootPart.GetEffectiveObjectFlags(); @@ -1535,6 +2345,20 @@ namespace OpenSim.Region.Framework.Scenes m_scene.RemoveGroupTarget(this); } + scriptEvents rootPartPhysEvents = RootPart.AggregateScriptEvents; + rootPartPhysEvents &= PhysicsNeeedSubsEvents; + if (rootPartPhysEvents != lastRootPartPhysEvents) + { + lastRootPartPhysEvents = rootPartPhysEvents; + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part == null) + continue; + part.UpdatePhysicsSubscribedEvents(); + } + } + ScheduleGroupForFullUpdate(); } @@ -1555,28 +2379,44 @@ namespace OpenSim.Region.Framework.Scenes /// public void ApplyPhysics() { - // Apply physics to the root prim - m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive); - - // Apply physics to child prims SceneObjectPart[] parts = m_parts.GetArray(); if (parts.Length > 1) { + ResetChildPrimPhysicsPositions(); + + // Apply physics to the root prim + m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true); + for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; if (part.LocalId != m_rootPart.LocalId) - part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); + part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true); } - // Hack to get the physics scene geometries in the right spot - ResetChildPrimPhysicsPositions(); +// ResetChildPrimPhysicsPositions(); + + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; + } + else + { + // Apply physics to the root prim + m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false); } } public void SetOwnerId(UUID userId) { - ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); + ForEachPart(delegate(SceneObjectPart part) + { + if (part.OwnerID != userId) + { + if(part.GroupID != part.OwnerID) + part.LastOwnerID = part.OwnerID; + part.OwnerID = userId; + } + }); } public void ForEachPart(Action whatToDo) @@ -1601,18 +2441,24 @@ namespace OpenSim.Region.Framework.Scenes return; } - if (IsDeleted || UUID == UUID.Zero) + if (IsDeleted || inTransit || UUID == UUID.Zero) { // m_log.DebugFormat( // "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID); return; } + if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) + return; + // Since this is the top of the section of call stack for backing up a particular scene object, don't let // any exception propogate upwards. try { - if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart + // if shutting down then there will be nothing to handle the return so leave till next restart + if (!m_scene.ShuttingDown && + m_scene.LoginsEnabled && // We're starting up or doing maintenance, don't mess with things + !m_scene.LoadingPrims) // Land may not be valid yet { ILandObject parcel = m_scene.LandChannel.GetLandObject( m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); @@ -1627,18 +2473,33 @@ namespace OpenSim.Region.Framework.Scenes if ((DateTime.UtcNow - RootPart.Rezzed).TotalMinutes > parcel.LandData.OtherCleanTime) { + // don't autoreturn if we have a sitting avatar + // mantis 7828 (but none the provided patchs) + + if(GetSittingAvatarsCount() > 0) + { + // do not respect npcs + List sitters = GetSittingAvatars(); + foreach(ScenePresence sp in sitters) + { + if(!sp.IsDeleted && !sp.IsNPC && sp.IsSatOnObject) + return; + } + } + DetachFromBackup(); m_log.DebugFormat( - "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn", + "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn", RootPart.UUID); m_scene.AddReturn(OwnerID == GroupID ? LastOwnerID : OwnerID, Name, AbsolutePosition, "parcel autoreturn"); m_scene.DeRezObjects(null, new List() { RootPart.LocalId }, UUID.Zero, - DeRezAction.Return, UUID.Zero); + DeRezAction.Return, UUID.Zero, false); return; } } } + } if (m_scene.UseBackup && HasGroupChanged) @@ -1646,10 +2507,31 @@ namespace OpenSim.Region.Framework.Scenes // don't backup while it's selected or you're asking for changes mid stream. if (isTimeToPersist() || forcedBackup) { + if (m_rootPart.PhysActor != null && + (!m_rootPart.PhysActor.IsPhysical)) + { + // Possible ghost prim + if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition) + { + foreach (SceneObjectPart part in m_parts.GetArray()) + { + // Re-set physics actor positions and + // orientations + part.GroupPosition = m_rootPart.GroupPosition; + } + } + } // m_log.DebugFormat( // "[SCENE]: Storing {0}, {1} in {2}", // Name, UUID, m_scene.RegionInfo.RegionName); + if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0) + { + RootPart.Shape.LastAttachPoint = RootPart.Shape.State; + RootPart.Shape.State = 0; + ScheduleGroupForFullUpdate(); + } + SceneObjectGroup backup_group = Copy(false); backup_group.RootPart.Velocity = RootPart.Velocity; backup_group.RootPart.Acceleration = RootPart.Acceleration; @@ -1659,13 +2541,21 @@ namespace OpenSim.Region.Framework.Scenes GroupContainsForeignPrims = false; m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); + datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); - backup_group.ForEachPart(delegate(SceneObjectPart part) - { - part.Inventory.ProcessInventoryBackup(datastore); + backup_group.ForEachPart(delegate(SceneObjectPart part) + { + part.Inventory.ProcessInventoryBackup(datastore); + + if(part.KeyframeMotion != null) + { + part.KeyframeMotion.Delete(); + part.KeyframeMotion = null; + } }); + backup_group.Clear(); backup_group = null; } // else @@ -1679,7 +2569,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}", + "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}", Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace); } } @@ -1715,14 +2605,21 @@ namespace OpenSim.Region.Framework.Scenes /// public SceneObjectGroup Copy(bool userExposed) { - // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up - // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator - // but not between regions on different simulators). Really, all copying should be done explicitly. + m_dupeInProgress = true; SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); - dupe.Backup = false; dupe.m_parts = new MapAndArray(); + + // a copy isnt backedup + dupe.Backup = false; + dupe.InvalidBoundsRadius(); + + // a copy is not in transit hopefully + dupe.inTransit = false; + + // new group as no sitting avatars dupe.m_sittingAvatars = new List(); + dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; @@ -1730,12 +2627,12 @@ namespace OpenSim.Region.Framework.Scenes dupe.m_rootPart.TrimPermissions(); List partList = new List(m_parts.GetArray()); - + partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) - { - return p1.LinkNum.CompareTo(p2.LinkNum); - } - ); + { + return p1.LinkNum.CompareTo(p2.LinkNum); + } + ); foreach (SceneObjectPart part in partList) { @@ -1744,43 +2641,59 @@ namespace OpenSim.Region.Framework.Scenes { newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); newPart.LinkNum = part.LinkNum; - } +// if (userExposed) + newPart.ParentID = dupe.m_rootPart.LocalId; + } else { newPart = dupe.m_rootPart; } +/* + bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0); + bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0); // Need to duplicate the physics actor as well - PhysicsActor originalPartPa = part.PhysActor; - if (originalPartPa != null && userExposed) + if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive)) { PrimitiveBaseShape pbs = newPart.Shape; - newPart.PhysActor = m_scene.PhysicsScene.AddPrimShape( string.Format("{0}/{1}", newPart.Name, newPart.UUID), pbs, newPart.AbsolutePosition, newPart.Scale, - newPart.RotationOffset, - originalPartPa.IsPhysical, + newPart.GetWorldRotation(), + isphys, + isphan, newPart.LocalId); - - newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); - } + + newPart.DoPhysicsPropertyUpdate(isphys, true); + */ + if (userExposed) + newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true); +// } + // copy keyframemotion if (part.KeyframeMotion != null) newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); } - + if (userExposed) { - dupe.UpdateParentIDs(); +// done above dupe.UpdateParentIDs(); + + if (dupe.m_rootPart.PhysActor != null) + dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building + + dupe.InvalidateDeepEffectivePerms(); + dupe.HasGroupChanged = true; dupe.AttachToBackup(); - ScheduleGroupForFullUpdate(); + dupe.ScheduleGroupForFullUpdate(); } + dupe.InvalidatePartsLinkMaps(); + m_dupeInProgress = false; return dupe; } @@ -1792,7 +2705,13 @@ namespace OpenSim.Region.Framework.Scenes /// public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) { - SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); + SceneObjectPart newpart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed); +// SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed); +// newpart.LocalId = m_scene.AllocateLocalId(); + + SetRootPart(newpart); + if (userExposed) + RootPart.Velocity = Vector3.Zero; // In case source is moving } public void ScriptSetPhysicsStatus(bool usePhysics) @@ -1803,35 +2722,22 @@ namespace OpenSim.Region.Framework.Scenes RootPart.KeyframeMotion.Stop(); RootPart.KeyframeMotion = null; } - UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); + UpdateFlags(usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); } public void ScriptSetTemporaryStatus(bool makeTemporary) { - UpdatePrimFlags(RootPart.LocalId, UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect); + UpdateFlags(UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect); } public void ScriptSetPhantomStatus(bool makePhantom) { - UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect); + UpdateFlags(UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect); } public void ScriptSetVolumeDetect(bool makeVolumeDetect) { - UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect); - - /* - ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore - - if (PhysActor != null) // Should always be the case now - { - PhysActor.SetVolumeDetect(param); - } - if (param != 0) - AddFlag(PrimFlags.Phantom); - - ScheduleFullUpdate(); - */ + UpdateFlags(UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect); } public void applyImpulse(Vector3 impulse) @@ -1850,27 +2756,14 @@ namespace OpenSim.Region.Framework.Scenes if (pa != null) { - pa.AddForce(impulse, true); - m_scene.PhysicsScene.AddPhysicsActorTaint(pa); - } - } - } - - public void applyAngularImpulse(Vector3 impulse) - { - PhysicsActor pa = RootPart.PhysActor; - - if (pa != null) - { - if (!IsAttachment) - { - pa.AddAngularForce(impulse, true); + // false to be applied as a impulse + pa.AddForce(impulse, false); m_scene.PhysicsScene.AddPhysicsActorTaint(pa); } } } - public void setAngularImpulse(Vector3 impulse) + public void ApplyAngularImpulse(Vector3 impulse) { PhysicsActor pa = RootPart.PhysActor; @@ -1878,7 +2771,8 @@ namespace OpenSim.Region.Framework.Scenes { if (!IsAttachment) { - pa.Torque = impulse; + // false to be applied as a impulse + pa.AddAngularForce(impulse, false); m_scene.PhysicsScene.AddPhysicsActorTaint(pa); } } @@ -1886,20 +2780,10 @@ namespace OpenSim.Region.Framework.Scenes public Vector3 GetTorque() { - PhysicsActor pa = RootPart.PhysActor; - - if (pa != null) - { - if (!IsAttachment) - { - Vector3 torque = pa.Torque; - return torque; - } - } - - return Vector3.Zero; + return RootPart.Torque; } + // This is used by llMoveToTarget() in an attached object public void MoveToTarget(Vector3 target, float tau) { if (IsAttachment) @@ -1907,7 +2791,7 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); if (avatar != null) - avatar.MoveToTarget(target, false, false); + avatar.MoveToTarget(target, false, false, tau); } else { @@ -1929,21 +2813,73 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); if (avatar != null) + { avatar.ResetMoveToTarget(); + } } else { PhysicsActor pa = RootPart.PhysActor; - if (pa != null && pa.PIDActive) - { + if (pa != null) pa.PIDActive = false; - - ScheduleGroupForTerseUpdate(); + + RootPart.ScheduleTerseUpdate(); // send a stop information + } + } + + public void RotLookAt(Quaternion target, float strength, float damping) + { + if(IsDeleted) + return; + + // non physical is handle in LSL api + if(!UsesPhysics || IsAttachment) + return; + + SceneObjectPart rootpart = m_rootPart; + if (rootpart != null) + { +/* physics still doesnt suport this + if (rootpart.PhysActor != null) + { + rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W); + rootpart.PhysActor.APIDStrength = strength; + rootpart.PhysActor.APIDDamping = damping; + rootpart.PhysActor.APIDActive = true; } +*/ + // so do it in rootpart + rootpart.RotLookAt(target, strength, damping); + } + } + + public void StartLookAt(Quaternion target, float strength, float damping) + { + if(IsDeleted) + return; + + // non physical is done by LSL APi + if(!UsesPhysics || IsAttachment) + return; + + if (m_rootPart != null) + m_rootPart.RotLookAt(target, strength, damping); + } + + public void StopLookAt() + { + SceneObjectPart rootpart = m_rootPart; + if (rootpart != null) + { + if (rootpart.PhysActor != null) + { + rootpart.PhysActor.APIDActive = false; + } + + rootpart.StopLookAt(); } } - /// /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. /// @@ -1952,7 +2888,15 @@ namespace OpenSim.Region.Framework.Scenes /// Number of seconds over which to reach target public void SetHoverHeight(float height, PIDHoverType hoverType, float tau) { - PhysicsActor pa = RootPart.PhysActor; + PhysicsActor pa = null; + if(IsAttachment) + { + ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); + if (avatar != null) + pa = avatar.PhysicsActor; + } + else + pa = RootPart.PhysActor; if (pa != null) { @@ -1960,7 +2904,7 @@ namespace OpenSim.Region.Framework.Scenes { pa.PIDHoverHeight = height; pa.PIDHoverType = hoverType; - pa.PIDTau = tau; + pa.PIDHoverTau = tau; pa.PIDHoverActive = true; } else @@ -1971,25 +2915,33 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Set the owner of the root part. + /// Set the owner of all linkset. /// - /// /// /// - public void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) + public void SetOwner(UUID cAgentID, UUID cGroupID) { - part.LastOwnerID = part.OwnerID; - part.OwnerID = cAgentID; - part.GroupID = cGroupID; + SceneObjectPart rpart = RootPart; + UUID oldowner = rpart.OwnerID; + ForEachPart(delegate(SceneObjectPart part) + { + if(part.GroupID != part.OwnerID) + part.LastOwnerID = part.OwnerID; + part.OwnerID = cAgentID; + part.GroupID = cGroupID; + }); - if (part.OwnerID != cAgentID) + if (oldowner != cAgentID) { // Apply Next Owner Permissions if we're not bypassing permissions if (!m_scene.Permissions.BypassPermissions()) + { ApplyNextOwnerPermissions(); + InvalidateEffectivePerms(); + } } - part.ScheduleFullUpdate(); + rpart.ScheduleFullUpdate(); } /// @@ -2001,6 +2953,9 @@ namespace OpenSim.Region.Framework.Scenes public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) { SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); +// SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed); +// newPart.LocalId = m_scene.AllocateLocalId(); + AddPart(newPart); SetPartAsNonRoot(newPart); @@ -2035,7 +2990,7 @@ namespace OpenSim.Region.Framework.Scenes public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) { remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); - + // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, @@ -2050,6 +3005,7 @@ namespace OpenSim.Region.Framework.Scenes #endregion + public override void Update() { // Check that the group was not deleted before the scheduled update @@ -2057,7 +3013,7 @@ namespace OpenSim.Region.Framework.Scenes // an object has been deleted from a scene before update was processed. // A more fundamental overhaul of the update mechanism is required to eliminate all // the race conditions. - if (IsDeleted) + if (IsDeleted || inTransit) return; // Even temporary objects take part in physics (e.g. temp-on-rez bullets) @@ -2065,31 +3021,36 @@ namespace OpenSim.Region.Framework.Scenes // return; // If we somehow got here to updating the SOG and its root part is not scheduled for update, - // check to see if the physical position or rotation warrant an update. + // check to see if the physical position or rotation warrant an update. +/* if (m_rootPart.UpdateFlag == UpdateRequired.NONE) { - bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); - - if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) - { - m_rootPart.UpdateFlag = UpdateRequired.TERSE; - lastPhysGroupPos = AbsolutePosition; - } - - if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f)) + // rootpart SendScheduledUpdates will check if a update is needed + m_rootPart.UpdateFlag = UpdateRequired.TERSE; + } +*/ + if (IsAttachment) + { + ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar); + if (sp != null) { - m_rootPart.UpdateFlag = UpdateRequired.TERSE; - lastPhysGroupRot = GroupRotation; + sp.SendAttachmentScheduleUpdate(this); + return; } } + // while physics doesn't suports LookAt, we do it in RootPart + if (!IsSelected) + RootPart.UpdateLookAt(); + + double now = Util.GetTimeStampMS(); + RootPart.SendScheduledUpdates(now); SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; - if (!IsSelected) - part.UpdateLookAt(); - part.SendScheduledUpdates(); + if(part != RootPart) + part.SendScheduledUpdates(now); } } @@ -2105,7 +3066,7 @@ namespace OpenSim.Region.Framework.Scenes { // if (IsAttachment) // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); - + checkAtTargets(); RootPart.ScheduleFullUpdate(); @@ -2144,15 +3105,24 @@ namespace OpenSim.Region.Framework.Scenes return; // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); - - RootPart.SendFullUpdateToAllClients(); + if (IsAttachment) + { + ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar); + if (sp != null) + { + sp.SendAttachmentUpdate(this,UpdateRequired.FULL); + return; + } + } + + RootPart.SendFullUpdateToAllClientsInternal(); SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; if (part != RootPart) - part.SendFullUpdateToAllClients(); + part.SendFullUpdateToAllClientsInternal(); } } @@ -2164,7 +3134,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendGroupRootTerseUpdate() { - if (IsDeleted) + if (IsDeleted || inTransit) return; RootPart.SendTerseUpdateToAllClients(); @@ -2174,7 +3144,7 @@ namespace OpenSim.Region.Framework.Scenes { if (m_scene == null) // Need to check here as it's null during object creation return; - + m_scene.SceneGraph.AddToUpdateList(this); } @@ -2183,12 +3153,22 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendGroupTerseUpdate() { - if (IsDeleted) + if (IsDeleted || inTransit) return; + if (IsAttachment) + { + ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar); + if (sp != null) + { + sp.SendAttachmentUpdate(this, UpdateRequired.TERSE); + return; + } + } + SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) - parts[i].SendTerseUpdateToAllClients(); + parts[i].SendTerseUpdateToAllClientsInternal(); } /// @@ -2296,9 +3276,41 @@ namespace OpenSim.Region.Framework.Scenes return; } + // physical prims count limit + // not very eficient :( + + if (UsesPhysics && m_scene.m_linksetPhysCapacity > 0 && (PrimCount + objectGroup.PrimCount) > + m_scene.m_linksetPhysCapacity) + { + int cntr = 0; + foreach (SceneObjectPart part in Parts) + { + if (part.PhysicsShapeType != (byte)PhysicsShapeType.None) + cntr++; + } + foreach (SceneObjectPart part in objectGroup.Parts) + { + if (part.PhysicsShapeType != (byte)PhysicsShapeType.None) + cntr++; + } + + if (cntr > m_scene.m_linksetPhysCapacity) + { + // cancel physics + RootPart.Flags &= ~PrimFlags.Physics; + ApplyPhysics(); + } + } + + // 'linkPart' == the root of the group being linked into this group SceneObjectPart linkPart = objectGroup.m_rootPart; + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = true; + if (linkPart.PhysActor != null) + linkPart.PhysActor.Building = true; + // physics flags from group to be applied to linked parts bool grpusephys = UsesPhysics; bool grptemporary = IsTemporary; @@ -2307,7 +3319,7 @@ namespace OpenSim.Region.Framework.Scenes Vector3 oldGroupPosition = linkPart.GroupPosition; Quaternion oldRootRotation = linkPart.RotationOffset; - // A linked SOP remembers its location and rotation relative to the root of a group. + // A linked SOP remembers its location and rotation relative to the root of a group. // Convert the root of the group being linked to be relative to the // root of the group being linked to. // Note: Some of the assignments have complex side effects. @@ -2315,22 +3327,24 @@ namespace OpenSim.Region.Framework.Scenes // First move the new group's root SOP's position to be relative to ours // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, // this code can be reordered to have a more logical flow.) - linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; + linkPart.setOffsetPosition(linkPart.GroupPosition - AbsolutePosition); // Assign the new parent to the root of the old group linkPart.ParentID = m_rootPart.LocalId; // Now that it's a child, it's group position is our root position - linkPart.GroupPosition = AbsolutePosition; + linkPart.setGroupPosition(AbsolutePosition); - Vector3 axPos = linkPart.OffsetPosition; // Rotate the linking root SOP's position to be relative to the new root prim Quaternion parentRot = m_rootPart.RotationOffset; - axPos *= Quaternion.Inverse(parentRot); - linkPart.OffsetPosition = axPos; // Make the linking root SOP's rotation relative to the new root prim Quaternion oldRot = linkPart.RotationOffset; - Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; - linkPart.RotationOffset = newRot; + Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot; + linkPart.setRotationOffset(newRot); + + Vector3 axPos = linkPart.OffsetPosition; + axPos *= Quaternion.Conjugate(parentRot); + linkPart.OffsetPosition = axPos; + // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. // Now that we know this SOG has at least two SOPs in it, the new root @@ -2345,10 +3359,11 @@ namespace OpenSim.Region.Framework.Scenes if (insert) { linkNum = 2; + int insertSize = objectGroup.PrimCount; foreach (SceneObjectPart part in Parts) { if (part.LinkNum > 1) - part.LinkNum++; + part.LinkNum += insertSize; } } else @@ -2360,10 +3375,12 @@ namespace OpenSim.Region.Framework.Scenes m_parts.Add(linkPart.UUID, linkPart); linkPart.SetParent(this); + m_scene.updateScenePartGroup(linkPart, this); + linkPart.CreateSelected = true; // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now - linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); + linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); // If the added SOP is physical, also tell the physics engine about the link relationship. if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) @@ -2373,15 +3390,16 @@ namespace OpenSim.Region.Framework.Scenes } linkPart.LinkNum = linkNum++; + linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); - // Get a list of the SOP's in the old group in order of their linknum's. + // Get a list of the SOP's in the source group in order of their linknum's. SceneObjectPart[] ogParts = objectGroup.Parts; Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) { return a.LinkNum - b.LinkNum; }); - // Add each of the SOP's from the old linkset to our linkset + // Add each of the SOP's from the source linkset to our linkset for (int i = 0; i < ogParts.Length; i++) { SceneObjectPart part = ogParts[i]; @@ -2391,7 +3409,7 @@ namespace OpenSim.Region.Framework.Scenes // Update the physics flags for the newly added SOP // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) - part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); + part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true); // If the added SOP is physical, also tell the physics engine about the link relationship. if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) @@ -2420,11 +3438,17 @@ namespace OpenSim.Region.Framework.Scenes AttachToBackup(); - // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the - // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and + // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the + // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and // unmoved prims! ResetChildPrimPhysicsPositions(); + InvalidBoundsRadius(); + InvalidatePartsLinkMaps(); + + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; + //HasGroupChanged = true; //ScheduleGroupForFullUpdate(); } @@ -2492,7 +3516,10 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); - + + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = true; + linkPart.ClearUndoState(); Vector3 worldPos = linkPart.GetWorldPosition(); @@ -2533,57 +3560,172 @@ namespace OpenSim.Region.Framework.Scenes // engine about the delink. Someday, linksets should be made first // class objects in the physics engine interface). if (linkPartPa != null) + { m_scene.PhysicsScene.RemovePrim(linkPartPa); + linkPart.PhysActor = null; + } // We need to reset the child part's position // ready for life as a separate object after being a part of another object - /* This commented out code seems to recompute what GetWorldPosition already does. - * Replace with a call to GetWorldPosition (before unlinking) - Quaternion parentRot = m_rootPart.RotationOffset; - Vector3 axPos = linkPart.OffsetPosition; - axPos *= parentRot; - linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); - linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; - linkPart.OffsetPosition = new Vector3(0, 0, 0); - */ - linkPart.GroupPosition = worldPos; - linkPart.OffsetPosition = Vector3.Zero; - linkPart.RotationOffset = worldRot; + /* This commented out code seems to recompute what GetWorldPosition already does. + * Replace with a call to GetWorldPosition (before unlinking) + Quaternion parentRot = m_rootPart.RotationOffset; + Vector3 axPos = linkPart.OffsetPosition; + axPos *= parentRot; + linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); + linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; + linkPart.OffsetPosition = new Vector3(0, 0, 0); + */ + linkPart.setGroupPosition(worldPos); + linkPart.setOffsetPosition(Vector3.Zero); + linkPart.setRotationOffset(worldRot); + + // Create a new SOG to go around this unlinked and unattached SOP + SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); + + m_scene.AddNewSceneObject(objectGroup, true); + + linkPart.Rezzed = RootPart.Rezzed; + + // When we delete a group, we currently have to force persist to the database if the object id has changed + // (since delete works by deleting all rows which have a given object id) + + // this is as it seems to be in sl now + if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none) + linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now + + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; + + objectGroup.HasGroupChangedDueToDelink = true; + + InvalidBoundsRadius(); + InvalidatePartsLinkMaps(); + objectGroup.InvalidateEffectivePerms(); + + if (sendEvents) + linkPart.TriggerScriptChangedEvent(Changed.LINK); + + return objectGroup; + } + +/* working on it + public void DelinkFromGroup(List linkParts, bool sendEvents) + { +// m_log.DebugFormat( +// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", +// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); + + if(PrimCount == 1) + return; + + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = true; + + bool unlinkroot = false; + foreach(SceneObjectPart linkPart in linkParts) + { + // first we only remove child parts + if(linkPart.LocalId == m_rootPart.LocalId) + { + unlinkroot = true; + continue; + } + + lock (m_parts.SyncRoot) + if(!m_parts.Remove(linkPart.UUID)) + continue; + + linkPart.ClearUndoState(); + + Vector3 worldPos = linkPart.GetWorldPosition(); + Quaternion worldRot = linkPart.GetWorldRotation(); + + linkPart.ParentID = 0; + linkPart.LinkNum = 0; + + PhysicsActor linkPartPa = linkPart.PhysActor; + + // Remove the SOP from the physical scene. + // If the new SOG is physical, it is re-created later. + // (There is a problem here in that we have not yet told the physics + // engine about the delink. Someday, linksets should be made first + // class objects in the physics engine interface). + if (linkPartPa != null) + { + m_scene.PhysicsScene.RemovePrim(linkPartPa); + linkPart.PhysActor = null; + } + + linkPart.setGroupPosition(worldPos); + linkPart.setOffsetPosition(Vector3.Zero); + linkPart.setRotationOffset(worldRot); + + // Create a new SOG to go around this unlinked and unattached SOP + SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); + + m_scene.AddNewSceneObject(objectGroup, true); + + linkPart.Rezzed = RootPart.Rezzed; + + // this is as it seems to be in sl now + if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none) + linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now + + objectGroup.HasGroupChangedDueToDelink = true; + if (sendEvents) + linkPart.TriggerScriptChangedEvent(Changed.LINK); + } - // Create a new SOG to go around this unlinked and unattached SOP - SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); + if(unlinkroot) + { + //TODO + } - m_scene.AddNewSceneObject(objectGroup, true); + lock (m_parts.SyncRoot) + { + SceneObjectPart[] parts = m_parts.GetArray(); + if (parts.Length == 1) + { + // Single prim left + m_rootPart.LinkNum = 0; + } + else + { + m_rootPart.LinkNum = 1; + int linknum = 2; + for (int i = 1; i < parts.Length; i++) + parts[i].LinkNum = linknum++; + } + } - if (sendEvents) - linkPart.TriggerScriptChangedEvent(Changed.LINK); + InvalidBoundsRadius(); - linkPart.Rezzed = RootPart.Rezzed; + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; - // We must persist the delinked group to the database immediately, for safety. The problem - // is that although in memory the new group has a new SceneGroupID, in the database it - // still has the parent group's SceneGroupID (until the next backup). This means that if the - // parent group is deleted then the delinked group will also be deleted from the database. - // This problem will disappear if the region remains alive long enough for another backup, - // since at that time the delinked group's new SceneGroupID will be written to the database. - // But if the region crashes before that then the prims will be permanently gone, and this must - // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case - // because the delinked group doesn't know when the source group is deleted.) - m_scene.ForceSceneObjectBackup(objectGroup); + // When we delete a group, we currently have to force persist to the database if the object id has changed + // (since delete works by deleting all rows which have a given object id) - return objectGroup; + Scene.SimulationDataService.RemoveObject(UUID, Scene.RegionInfo.RegionID); + HasGroupChangedDueToDelink = true; + TriggerScriptChangedEvent(Changed.LINK); + return; } - +*/ /// /// Stop this object from being persisted over server restarts. /// /// public virtual void DetachFromBackup() { - if (Backup && Scene != null) - m_scene.EventManager.OnBackup -= ProcessBackup; - + if (m_scene != null) + { + m_scene.SceneGraph.FireDetachFromBackup(this); + if (Backup) + m_scene.EventManager.OnBackup -= ProcessBackup; + } Backup = false; } @@ -2597,14 +3739,14 @@ namespace OpenSim.Region.Framework.Scenes Quaternion parentRot = oldGroupRotation; Quaternion oldRot = part.RotationOffset; - // Move our position to not be relative to the old parent + // Move our position in world Vector3 axPos = part.OffsetPosition; axPos *= parentRot; - part.OffsetPosition = axPos; - part.GroupPosition = oldGroupPosition + part.OffsetPosition; - part.OffsetPosition = Vector3.Zero; + Vector3 newPos = oldGroupPosition + axPos; + part.setGroupPosition(newPos); + part.setOffsetPosition(Vector3.Zero); - // Compution our rotation to be not relative to the old parent + // Compution our rotation in world Quaternion worldRot = parentRot * oldRot; part.RotationOffset = worldRot; @@ -2615,29 +3757,32 @@ namespace OpenSim.Region.Framework.Scenes part.LinkNum = linkNum; + m_scene.updateScenePartGroup(part, this); + // Compute the new position of this SOP relative to the group position - part.OffsetPosition = part.GroupPosition - AbsolutePosition; + part.setOffsetPosition(newPos - AbsolutePosition); // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. - // It would have the affect of setting the physics engine position multiple + // It would have the affect of setting the physics engine position multiple // times. In theory, that is not necessary but I don't have a good linkset // test to know that cleaning up this code wouldn't break things.) - // Rotate the relative position by the rotation of the group - Quaternion rootRotation = m_rootPart.RotationOffset; - Vector3 pos = part.OffsetPosition; - pos *= Quaternion.Inverse(rootRotation); - part.OffsetPosition = pos; - // Compute the SOP's rotation relative to the rotation of the group. parentRot = m_rootPart.RotationOffset; + oldRot = part.RotationOffset; - Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; - part.RotationOffset = newRot; + Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot; + part.setRotationOffset(newRot); + + Vector3 pos = part.OffsetPosition; + pos *= Quaternion.Conjugate(parentRot); + + part.OffsetPosition = pos; // update position and orientation on physics also // Since this SOP's state has changed, push those changes into the physics engine // and the simulator. - part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); + // done on caller +// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); } /// @@ -2652,30 +3797,26 @@ namespace OpenSim.Region.Framework.Scenes { if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) { + if (BlockGrabOverride) + return; + SceneObjectPart part = GetPart(partID); if (part == null) return; + if (part.BlockGrab) + return; + PhysicsActor pa = m_rootPart.PhysActor; - if (pa != null) + if (pa != null && pa.IsPhysical) { - if (pa.IsPhysical) - { - if (!BlockGrabOverride && !part.BlockGrab) - { - Vector3 llmoveforce = pos - AbsolutePosition; - Vector3 grabforce = llmoveforce; - grabforce = (grabforce / 10) * pa.Mass; - pa.AddForce(grabforce, true); - m_scene.PhysicsScene.AddPhysicsActorTaint(pa); - } - } - else - { - NonPhysicalGrabMovement(pos); - } + // empirically convert distance diference to a impulse + Vector3 grabforce = pos - AbsolutePosition; + grabforce = grabforce * (pa.Mass * 0.1f); + pa.AddForce(grabforce, false); + m_scene.PhysicsScene.AddPhysicsActorTaint(pa); } else { @@ -2704,6 +3845,8 @@ namespace OpenSim.Region.Framework.Scenes /// public void SpinStart(IClientAPI remoteClient) { + if (BlockGrabOverride || m_rootPart.BlockGrab) + return; if (m_scene.EventManager.TriggerGroupSpinStart(UUID)) { PhysicsActor pa = m_rootPart.PhysActor; @@ -2725,72 +3868,74 @@ namespace OpenSim.Region.Framework.Scenes /// public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient) { - // The incoming newOrientation, sent by the client, "seems" to be the - // desired target orientation. This needs further verification; in particular, + // The incoming newOrientation, sent by the client, "seems" to be the + // desired target orientation. This needs further verification; in particular, // one would expect that the initial incoming newOrientation should be - // fairly close to the original prim's physical orientation, + // fairly close to the original prim's physical orientation, // m_rootPart.PhysActor.Orientation. This however does not seem to be the // case (might just be an issue with different quaternions representing the // same rotation, or it might be a coordinate system issue). // // Since it's not clear what the relationship is between the PhysActor.Orientation // and the incoming orientations sent by the client, we take an alternative approach - // of calculating the delta rotation between the orientations being sent by the + // of calculating the delta rotation between the orientations being sent by the // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect // a steady stream of several new orientations coming in from the client.) // This ensures that the delta rotations are being calculated from self-consistent // pairs of old/new rotations. Given the delta rotation, we apply a torque around // the delta rotation axis, scaled by the object mass times an arbitrary scaling // factor (to ensure the resulting torque is not "too strong" or "too weak"). - // + // // Ideally we need to calculate (probably iteratively) the exact torque or series - // of torques needed to arrive exactly at the destination orientation. However, since + // of torques needed to arrive exactly at the destination orientation. However, since // it is not yet clear how to map the destination orientation (provided by the viewer) - // into PhysActor orientations (needed by the physics engine), we omit this step. - // This means that the resulting torque will at least be in the correct direction, + // into PhysActor orientations (needed by the physics engine), we omit this step. + // This means that the resulting torque will at least be in the correct direction, // but it will result in over-shoot or under-shoot of the target orientation. // For the end user, this means that ctrl+shift+drag can be used for relative, // but not absolute, adjustments of orientation for physical prims. + + if (BlockGrabOverride || m_rootPart.BlockGrab) + return; + if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation)) { PhysicsActor pa = m_rootPart.PhysActor; - if (pa != null) + if (pa != null && pa.IsPhysical) { - if (pa.IsPhysical) + if (m_rootPart.IsWaitingForFirstSpinUpdatePacket) { - if (m_rootPart.IsWaitingForFirstSpinUpdatePacket) - { - // first time initialization of "old" orientation for calculation of delta rotations - m_rootPart.SpinOldOrientation = newOrientation; - m_rootPart.IsWaitingForFirstSpinUpdatePacket = false; - } - else - { - // save and update old orientation - Quaternion old = m_rootPart.SpinOldOrientation; - m_rootPart.SpinOldOrientation = newOrientation; - //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old); - //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation); - - // compute difference between previous old rotation and new incoming rotation - Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation; - - float rotationAngle; - Vector3 rotationAxis; - minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle); - rotationAxis.Normalize(); - - //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis); - Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z); - spinforce = (spinforce/8) * pa.Mass; // 8 is an arbitrary torque scaling factor - pa.AddAngularForce(spinforce,true); - m_scene.PhysicsScene.AddPhysicsActorTaint(pa); - } + // first time initialization of "old" orientation for calculation of delta rotations + m_rootPart.SpinOldOrientation = newOrientation; + m_rootPart.IsWaitingForFirstSpinUpdatePacket = false; } else { - NonPhysicalSpinMovement(newOrientation); + // save and update old orientation + Quaternion old = m_rootPart.SpinOldOrientation; + m_rootPart.SpinOldOrientation = newOrientation; + //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old); + //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation); + + // compute difference between previous old rotation and new incoming rotation + Quaternion minimalRotationFromQ1ToQ2 = newOrientation * Quaternion.Inverse(old); + + float rotationAngle; + Vector3 spinforce; + minimalRotationFromQ1ToQ2.GetAxisAngle(out spinforce, out rotationAngle); + if(Math.Abs(rotationAngle)< 0.001) + return; + + spinforce.Normalize(); + + //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis); + if(rotationAngle > 0) + spinforce = spinforce * pa.Mass * 0.1f; // 0.1 is an arbitrary torque scaling factor + else + spinforce = spinforce * pa.Mass * -0.1f; // 0.1 is an arbitrary torque scaling + pa.AddAngularForce(spinforce,true); + m_scene.PhysicsScene.AddPhysicsActorTaint(pa); } } else @@ -2880,51 +4025,80 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) + public void UpdateFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) { - SceneObjectPart selectionPart = GetPart(localID); + if (m_scene == null || IsDeleted) + return; - if (Scene != null) - { - if (SetTemporary) - { - DetachFromBackup(); - // Remove from database and parcel prim count - // - m_scene.DeleteFromStorage(UUID); - } - else if (!Backup) - { - // Previously been temporary now switching back so make it - // available for persisting again - AttachToBackup(); - } + HasGroupChanged = true; - m_scene.EventManager.TriggerParcelPrimCountTainted(); + if (SetTemporary) + { + DetachFromBackup(); + // Remove from database and parcel prim count + // + m_scene.DeleteFromStorage(UUID); + } + else if (!Backup) + { + // Previously been temporary now switching back so make it + // available for persisting again + AttachToBackup(); } - if (selectionPart != null) + + SceneObjectPart[] parts = m_parts.GetArray(); + + if (UsePhysics) { - SceneObjectPart[] parts = m_parts.GetArray(); - - if (Scene != null) + int maxprims = m_scene.m_linksetPhysCapacity; + bool checkShape = (maxprims > 0 && + parts.Length > maxprims); + + for (int i = 0; i < parts.Length; i++) { - for (int i = 0; i < parts.Length; i++) + SceneObjectPart part = parts[i]; + + if(part.PhysicsShapeType == (byte)PhysicsShapeType.None) + continue; // assuming root type was checked elsewhere + + if (checkShape) { - SceneObjectPart part = parts[i]; - if (part.Scale.X > m_scene.m_maxPhys || - part.Scale.Y > m_scene.m_maxPhys || - part.Scale.Z > m_scene.m_maxPhys ) + if (--maxprims < 0) { - UsePhysics = false; // Reset physics + UsePhysics = false; break; } } + + if (part.Scale.X > m_scene.m_maxPhys || + part.Scale.Y > m_scene.m_maxPhys || + part.Scale.Z > m_scene.m_maxPhys ) + { + UsePhysics = false; // Reset physics + break; + } } + } + + if (parts.Length > 1) + { + m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true); for (int i = 0; i < parts.Length; i++) - parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); + { + + if (parts[i].UUID != m_rootPart.UUID) + parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true); + } + + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; } + else + m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false); + + m_scene.EventManager.TriggerParcelPrimCountTainted(); } public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data) @@ -2936,24 +4110,21 @@ namespace OpenSim.Region.Framework.Scenes } } + + /// - /// Update the texture entry for this part + /// Gets the number of parts /// - /// - /// - public void UpdateTextureEntry(uint localID, byte[] textureEntry) + /// + public int GetPartCount() { - SceneObjectPart part = GetPart(localID); - if (part != null) - { - part.UpdateTextureEntry(textureEntry); - } + return Parts.Count(); } public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive) { - uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits - uint foldedPerms = RootPart.OwnerMask & 3; + uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff0; // Mask folded bits + uint foldedPerms = RootPart.OwnerMask & (uint)PermissionMask.FoldedMask; ForEachPart(part => { @@ -2964,14 +4135,14 @@ namespace OpenSim.Region.Framework.Scenes part.Inventory.ApplyGodPermissions(part.BaseMask); }); - uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify); - uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify); + uint lockMask = ~(uint)(PermissionMask.Move); + uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move); RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask); // m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}", +// "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}", // (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name); - + InvalidateEffectivePerms(); RootPart.ScheduleFullUpdate(); } @@ -2980,7 +4151,24 @@ namespace OpenSim.Region.Framework.Scenes { RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); - AdjustChildPrimPermissions(Scene.Permissions.IsGod(AgentID)); + bool god = Scene.Permissions.IsGod(AgentID); + + if (field == 1 && god) + { + ForEachPart(part => + { + part.BaseMask = RootPart.BaseMask; + }); + } + + AdjustChildPrimPermissions(false); + + if (field == 1 && god) // Base mask was set. Update all child part inventories + { + foreach (SceneObjectPart part in Parts) + part.Inventory.ApplyGodPermissions(RootPart.BaseMask); + InvalidateEffectivePerms(); + } HasGroupChanged = true; @@ -3010,6 +4198,7 @@ namespace OpenSim.Region.Framework.Scenes if (pa != null) m_scene.PhysicsScene.AddPhysicsActorTaint(pa); } + InvalidBoundsRadius(); } #endregion @@ -3025,194 +4214,302 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); + if (Scene == null) + return; + PhysicsActor pa = m_rootPart.PhysActor; - RootPart.StoreUndoState(true); + float minsize = Scene.m_minNonphys; + float maxsize = Scene.m_maxNonphys; - if (Scene != null) + if (pa != null && pa.IsPhysical) { - scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); - scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); - scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z)); - - if (pa != null && pa.IsPhysical) - { - scale.X = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.X)); - scale.Y = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Y)); - scale.Z = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Z)); - } + minsize = Scene.m_minPhys; + maxsize = Scene.m_maxPhys; } + scale.X = Util.Clamp(scale.X, minsize, maxsize); + scale.Y = Util.Clamp(scale.Y, minsize, maxsize); + scale.Z = Util.Clamp(scale.Z, minsize, maxsize); + + // requested scaling factors float x = (scale.X / RootPart.Scale.X); float y = (scale.Y / RootPart.Scale.Y); float z = (scale.Z / RootPart.Scale.Z); SceneObjectPart[] parts = m_parts.GetArray(); - if (Scene != null & (x > 1.0f || y > 1.0f || z > 1.0f)) + // fix scaling factors so parts don't violate dimensions + for(int i = 0;i < parts.Length;i++) { - for (int i = 0; i < parts.Length; i++) + SceneObjectPart obPart = parts[i]; + if(obPart.UUID != m_rootPart.UUID) { - SceneObjectPart obPart = parts[i]; - if (obPart.UUID != m_rootPart.UUID) + Vector3 oldSize = new Vector3(obPart.Scale); + + float f = 1.0f; + float a = 1.0f; + + if(oldSize.X * x > maxsize) + { + f = maxsize / oldSize.X; + a = f / x; + x *= a; + y *= a; + z *= a; + } + else if(oldSize.X * x < minsize) { -// obPart.IgnoreUndoUpdate = true; - Vector3 oldSize = new Vector3(obPart.Scale); + f = minsize / oldSize.X; + a = f / x; + x *= a; + y *= a; + z *= a; + } - float f = 1.0f; - float a = 1.0f; + if(oldSize.Y * y > maxsize) + { + f = maxsize / oldSize.Y; + a = f / y; + x *= a; + y *= a; + z *= a; + } + else if(oldSize.Y * y < minsize) + { + f = minsize / oldSize.Y; + a = f / y; + x *= a; + y *= a; + z *= a; + } - if (pa != null && pa.IsPhysical) - { - if (oldSize.X * x > Scene.m_maxPhys) - { - f = m_scene.m_maxPhys / oldSize.X; - a = f / x; - x *= a; - y *= a; - z *= a; - } - else if (oldSize.X * x < Scene.m_minPhys) - { - f = m_scene.m_minPhys / oldSize.X; - a = f / x; - x *= a; - y *= a; - z *= a; - } + if(oldSize.Z * z > maxsize) + { + f = maxsize / oldSize.Z; + a = f / z; + x *= a; + y *= a; + z *= a; + } + else if(oldSize.Z * z < minsize) + { + f = minsize / oldSize.Z; + a = f / z; + x *= a; + y *= a; + z *= a; + } + } + } - if (oldSize.Y * y > Scene.m_maxPhys) - { - f = m_scene.m_maxPhys / oldSize.Y; - a = f / y; - x *= a; - y *= a; - z *= a; - } - else if (oldSize.Y * y < Scene.m_minPhys) - { - f = m_scene.m_minPhys / oldSize.Y; - a = f / y; - x *= a; - y *= a; - z *= a; - } + Vector3 rootScale = RootPart.Scale; + rootScale.X *= x; + rootScale.Y *= y; + rootScale.Z *= z; - if (oldSize.Z * z > Scene.m_maxPhys) - { - f = m_scene.m_maxPhys / oldSize.Z; - a = f / z; - x *= a; - y *= a; - z *= a; - } - else if (oldSize.Z * z < Scene.m_minPhys) - { - f = m_scene.m_minPhys / oldSize.Z; - a = f / z; - x *= a; - y *= a; - z *= a; - } - } - else - { - if (oldSize.X * x > Scene.m_maxNonphys) - { - f = m_scene.m_maxNonphys / oldSize.X; - a = f / x; - x *= a; - y *= a; - z *= a; - } - else if (oldSize.X * x < Scene.m_minNonphys) - { - f = m_scene.m_minNonphys / oldSize.X; - a = f / x; - x *= a; - y *= a; - z *= a; - } + RootPart.Scale = rootScale; - if (oldSize.Y * y > Scene.m_maxNonphys) - { - f = m_scene.m_maxNonphys / oldSize.Y; - a = f / y; - x *= a; - y *= a; - z *= a; - } - else if (oldSize.Y * y < Scene.m_minNonphys) - { - f = m_scene.m_minNonphys / oldSize.Y; - a = f / y; - x *= a; - y *= a; - z *= a; - } + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; - if (oldSize.Z * z > Scene.m_maxNonphys) - { - f = m_scene.m_maxNonphys / oldSize.Z; - a = f / z; - x *= a; - y *= a; - z *= a; - } - else if (oldSize.Z * z < Scene.m_minNonphys) - { - f = m_scene.m_minNonphys / oldSize.Z; - a = f / z; - x *= a; - y *= a; - z *= a; - } - } + if (obPart.UUID != m_rootPart.UUID) + { + Vector3 currentpos = new Vector3(obPart.OffsetPosition); + currentpos.X *= x; + currentpos.Y *= y; + currentpos.Z *= z; -// obPart.IgnoreUndoUpdate = false; - } + Vector3 newSize = new Vector3(obPart.Scale); + newSize.X *= x; + newSize.Y *= y; + newSize.Z *= z; + + obPart.Scale = newSize; + obPart.UpdateOffSet(currentpos); + } + } + + InvalidBoundsRadius(); + HasGroupChanged = true; + m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); + ScheduleGroupForFullUpdate(); + + } + + public bool GroupResize(double fscale) + { +// m_log.DebugFormat( +// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, fscale); + + if (Scene == null || IsDeleted || inTransit || fscale < 0) + return false; + + // ignore lsl restrictions. let them be done a LSL + PhysicsActor pa = m_rootPart.PhysActor; + + if(RootPart.KeyframeMotion != null) + RootPart.KeyframeMotion.Suspend(); + + float minsize = Scene.m_minNonphys; + float maxsize = Scene.m_maxNonphys; + + // assuming physics is more restrictive + if (pa != null && pa.IsPhysical) + { + minsize = Scene.m_minPhys; + maxsize = Scene.m_maxPhys; + } + + SceneObjectPart[] parts = m_parts.GetArray(); + float tmp; + // check scaling factor so parts don't violate dimensions + for(int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; + Vector3 oldSize = new Vector3(obPart.Scale); + tmp = (float)(oldSize.X * fscale); + if(tmp > maxsize) + return false; + if(tmp < minsize) + return false; + + tmp = (float)(oldSize.Y * fscale); + if(tmp > maxsize) + return false; + if(tmp < minsize) + return false; + + tmp = (float)(oldSize.Z * fscale); + if(tmp > maxsize) + return false; + if(tmp < minsize) + return false; + } + + Vector3 newSize = RootPart.Scale; + newSize.X = (float)(newSize.X * fscale); + newSize.Y = (float)(newSize.Y * fscale); + newSize.Z = (float)(newSize.Z * fscale); + + if(pa != null) + pa.Building = true; + + RootPart.Scale = newSize; + + Vector3 currentpos; + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; + + if (obPart.UUID != m_rootPart.UUID) + { + currentpos = obPart.OffsetPosition; + currentpos.X = (float)(currentpos.X * fscale); + currentpos.Y = (float)(currentpos.Y * fscale); + currentpos.Z = (float)(currentpos.Z * fscale); + + newSize = obPart.Scale; + newSize.X = (float)(newSize.X * fscale); + newSize.Y = (float)(newSize.Y * fscale); + newSize.Z = (float)(newSize.Z * fscale); + + obPart.Scale = newSize; + obPart.UpdateOffSet(currentpos); } } - Vector3 prevScale = RootPart.Scale; - prevScale.X *= x; - prevScale.Y *= y; - prevScale.Z *= z; + if(pa != null) + pa.Building = false; + + InvalidBoundsRadius(); + + HasGroupChanged = true; + m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); + ScheduleGroupForFullUpdate(); + + if(RootPart.KeyframeMotion != null) + RootPart.KeyframeMotion.Resume(); + + return true; + } + + public float GetMaxGroupResizeScale() + { + if (Scene == null || IsDeleted || inTransit) + return 1.0f; + + float maxsize = Scene.m_maxNonphys; + PhysicsActor pa = m_rootPart.PhysActor; + // assuming physics is more restrictive + if (pa != null && pa.IsPhysical) + maxsize = Scene.m_maxPhys; + + SceneObjectPart[] parts = m_parts.GetArray(); + float larger = float.MinValue; + + for(int i = 0; i < parts.Length; i++) + { + SceneObjectPart obPart = parts[i]; + Vector3 oldSize = new Vector3(obPart.Scale); + if(larger < oldSize.X) + larger = oldSize.X; + + if(larger < oldSize.Y) + larger = oldSize.Y; + + if(larger < oldSize.Z) + larger = oldSize.Z; + } + + if(larger >= maxsize) + return 1.0f; + + larger += 1e-3f; + float fscale = maxsize / larger; + + return fscale; + } + + public float GetMinGroupResizeScale() + { + if (Scene == null || IsDeleted || inTransit) + return 1.0f; -// RootPart.IgnoreUndoUpdate = true; - RootPart.Resize(prevScale); -// RootPart.IgnoreUndoUpdate = false; + float minsize = Scene.m_minNonphys; + PhysicsActor pa = m_rootPart.PhysActor; + // assuming physics is more restrictive + if (pa != null && pa.IsPhysical) + minsize = Scene.m_minPhys; - for (int i = 0; i < parts.Length; i++) + SceneObjectPart[] parts = m_parts.GetArray(); + float smaller = float.MaxValue; + + for(int i = 0; i < parts.Length; i++) { SceneObjectPart obPart = parts[i]; + Vector3 oldSize = new Vector3(obPart.Scale); + if(smaller > oldSize.X) + smaller = oldSize.X; - if (obPart.UUID != m_rootPart.UUID) - { - obPart.IgnoreUndoUpdate = true; - - Vector3 currentpos = new Vector3(obPart.OffsetPosition); - currentpos.X *= x; - currentpos.Y *= y; - currentpos.Z *= z; - - Vector3 newSize = new Vector3(obPart.Scale); - newSize.X *= x; - newSize.Y *= y; - newSize.Z *= z; + if(smaller > oldSize.Y) + smaller = oldSize.Y; - obPart.Resize(newSize); - obPart.UpdateOffSet(currentpos); + if(smaller > oldSize.Z) + smaller = oldSize.Z; + } - obPart.IgnoreUndoUpdate = false; - } + if(smaller <= minsize) + return 1.0f; -// obPart.IgnoreUndoUpdate = false; -// obPart.StoreUndoState(); - } + if(smaller > 2e-3f) + smaller -= 1e-3f; + float fscale = minsize / smaller; + if(fscale < 1e-8f) + fscale = 1e-8f; -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale); + return fscale; } #endregion @@ -3225,14 +4522,6 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateGroupPosition(Vector3 pos) { -// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos); - - RootPart.StoreUndoState(true); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) { if (IsAttachment) @@ -3265,21 +4554,17 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// + /// + public void UpdateSinglePosition(Vector3 pos, uint localID) { SceneObjectPart part = GetPart(localID); -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - if (part != null) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); - - part.StoreUndoState(false); - part.IgnoreUndoUpdate = true; +// unlock parts position change + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = true; if (part.UUID == m_rootPart.UUID) { @@ -3290,8 +4575,10 @@ namespace OpenSim.Region.Framework.Scenes part.UpdateOffSet(pos); } + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; + HasGroupChanged = true; - part.IgnoreUndoUpdate = false; } } @@ -3301,13 +4588,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateRootPosition(Vector3 newPos) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - + // needs to be called with phys building true Vector3 oldPos; if (IsAttachment) @@ -3328,12 +4609,19 @@ namespace OpenSim.Region.Framework.Scenes } AbsolutePosition = newPos; - + if (IsAttachment) m_rootPart.AttachedPos = newPos; HasGroupChanged = true; - ScheduleGroupForTerseUpdate(); + if (m_rootPart.Undoing) + { + ScheduleGroupForFullUpdate(); + } + else + { + ScheduleGroupForTerseUpdate(); + } } #endregion @@ -3346,24 +4634,16 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateGroupRotationR(Quaternion rot) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - - m_rootPart.StoreUndoState(true); - m_rootPart.UpdateRotation(rot); +/* this is done by rootpart RotationOffset set called by UpdateRotation PhysicsActor actor = m_rootPart.PhysActor; if (actor != null) { actor.Orientation = m_rootPart.RotationOffset; m_scene.PhysicsScene.AddPhysicsActorTaint(actor); } - +*/ HasGroupChanged = true; ScheduleGroupForTerseUpdate(); } @@ -3375,16 +4655,6 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot); - -// SceneObjectPart[] parts = m_parts.GetArray(); -// for (int i = 0; i < parts.Length; i++) -// parts[i].StoreUndoState(); - - RootPart.StoreUndoState(true); - RootPart.IgnoreUndoUpdate = true; - m_rootPart.UpdateRotation(rot); PhysicsActor actor = m_rootPart.PhysActor; @@ -3403,8 +4673,6 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; ScheduleGroupForTerseUpdate(); - - RootPart.IgnoreUndoUpdate = false; } /// @@ -3417,13 +4685,11 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = GetPart(localID); SceneObjectPart[] parts = m_parts.GetArray(); - for (int i = 0; i < parts.Length; i++) - parts[i].StoreUndoState(); if (part != null) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = true; if (part.UUID == m_rootPart.UUID) { @@ -3433,6 +4699,9 @@ namespace OpenSim.Region.Framework.Scenes { part.UpdateRotation(rot); } + + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; } } @@ -3446,12 +4715,8 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = GetPart(localID); if (part != null) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", -// part.Name, part.LocalId, rot); - - part.StoreUndoState(); - part.IgnoreUndoUpdate = true; + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = true; if (part.UUID == m_rootPart.UUID) { @@ -3464,7 +4729,8 @@ namespace OpenSim.Region.Framework.Scenes part.OffsetPosition = pos; } - part.IgnoreUndoUpdate = false; + if (m_rootPart.PhysActor != null) + m_rootPart.PhysActor.Building = false; } } @@ -3474,15 +4740,12 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateRootRotation(Quaternion rot) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}", -// Name, LocalId, rot); - + // needs to be called with phys building true Quaternion axRot = rot; Quaternion oldParentRot = m_rootPart.RotationOffset; - m_rootPart.StoreUndoState(); - m_rootPart.UpdateRotation(rot); + //Don't use UpdateRotation because it schedules an update prematurely + m_rootPart.RotationOffset = rot; PhysicsActor pa = m_rootPart.PhysActor; @@ -3498,64 +4761,203 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart prim = parts[i]; if (prim.UUID != m_rootPart.UUID) { - prim.IgnoreUndoUpdate = true; + Quaternion NewRot = oldParentRot * prim.RotationOffset; + NewRot = Quaternion.Inverse(axRot) * NewRot; + prim.RotationOffset = NewRot; + Vector3 axPos = prim.OffsetPosition; + axPos *= oldParentRot; axPos *= Quaternion.Inverse(axRot); prim.OffsetPosition = axPos; - Quaternion primsRot = prim.RotationOffset; - Quaternion newRot = oldParentRot * primsRot; - newRot = Quaternion.Inverse(axRot) * newRot; - prim.RotationOffset = newRot; - prim.ScheduleTerseUpdate(); - prim.IgnoreUndoUpdate = false; } } -// for (int i = 0; i < parts.Length; i++) -// { -// SceneObjectPart childpart = parts[i]; -// if (childpart != m_rootPart) -// { -//// childpart.IgnoreUndoUpdate = false; -//// childpart.StoreUndoState(); -// } -// } + HasGroupChanged = true; + ScheduleGroupForFullUpdate(); + } + + private enum updatetype :int + { + none = 0, + partterse = 1, + partfull = 2, + groupterse = 3, + groupfull = 4 + } - m_rootPart.ScheduleTerseUpdate(); + public void doChangeObject(SceneObjectPart part, ObjectChangeData data) + { + // TODO this still as excessive *.Schedule*Update()s -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", -// Name, LocalId, rot); + if (part != null && part.ParentGroup != null) + { + ObjectChangeType change = data.change; + bool togroup = ((change & ObjectChangeType.Group) != 0); + // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use + + SceneObjectGroup group = part.ParentGroup; + PhysicsActor pha = group.RootPart.PhysActor; + + updatetype updateType = updatetype.none; + + if (togroup) + { + // related to group + if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0) + { + if ((change & ObjectChangeType.Rotation) != 0) + { + group.RootPart.UpdateRotation(data.rotation); + updateType = updatetype.none; + } + if ((change & ObjectChangeType.Position) != 0) + { + if (IsAttachment || m_scene.Permissions.CanObjectEntry(group, false, data.position)) + UpdateGroupPosition(data.position); + updateType = updatetype.groupterse; + } + else + // ugly rotation update of all parts + { + group.ResetChildPrimPhysicsPositions(); + } + + } + if ((change & ObjectChangeType.Scale) != 0) + { + if (pha != null) + pha.Building = true; + + group.GroupResize(data.scale); + updateType = updatetype.none; + + if (pha != null) + pha.Building = false; + } + } + else + { + // related to single prim in a link-set ( ie group) + if (pha != null) + pha.Building = true; + + // root part is special + // parts offset positions or rotations need to change also + + if (part == group.RootPart) + { + if ((change & ObjectChangeType.Rotation) != 0) + group.UpdateRootRotation(data.rotation); + if ((change & ObjectChangeType.Position) != 0) + group.UpdateRootPosition(data.position); + if ((change & ObjectChangeType.Scale) != 0) + part.Resize(data.scale); + } + else + { + if ((change & ObjectChangeType.Position) != 0) + { + part.OffsetPosition = data.position; + updateType = updatetype.partterse; + } + if ((change & ObjectChangeType.Rotation) != 0) + { + part.UpdateRotation(data.rotation); + updateType = updatetype.none; + } + if ((change & ObjectChangeType.Scale) != 0) + { + part.Resize(data.scale); + updateType = updatetype.none; + } + } + + if (pha != null) + pha.Building = false; + } + + if (updateType != updatetype.none) + { + group.HasGroupChanged = true; + + switch (updateType) + { + case updatetype.partterse: + part.ScheduleTerseUpdate(); + break; + case updatetype.partfull: + part.ScheduleFullUpdate(); + break; + case updatetype.groupterse: + group.ScheduleGroupForTerseUpdate(); + break; + case updatetype.groupfull: + group.ScheduleGroupForFullUpdate(); + break; + default: + break; + } + } + } } #endregion internal void SetAxisRotation(int axis, int rotate10) { - bool setX = false; - bool setY = false; - bool setZ = false; + bool setX = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0); + bool setY = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0); + bool setZ = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0); - int xaxis = 2; - int yaxis = 4; - int zaxis = 8; + if (setX || setY || setZ) + { + bool lockaxis = (rotate10 == 0); // zero means axis locked - setX = ((axis & xaxis) != 0) ? true : false; - setY = ((axis & yaxis) != 0) ? true : false; - setZ = ((axis & zaxis) != 0) ? true : false; + byte locks = RootPart.RotationAxisLocks; + + if (setX) + { + if(lockaxis) + locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X; + else + locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_X; + } - float setval = (rotate10 > 0) ? 1f : 0f; + if (setY) + { + if(lockaxis) + locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y; + else + locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Y; + } - if (setX) - RootPart.RotationAxis.X = setval; - if (setY) - RootPart.RotationAxis.Y = setval; - if (setZ) - RootPart.RotationAxis.Z = setval; + if (setZ) + { + if(lockaxis) + locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z; + else + locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Z; + } - if (setX || setY || setZ) + RootPart.RotationAxisLocks = locks; RootPart.SetPhysicsAxisRotation(); + } + } + + public int GetAxisRotation(int axis) + { + byte rotAxislocks = RootPart.RotationAxisLocks; + + // if multiple return the one with higher id + if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) + return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) == 0 ? 1:0; + if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) + return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) == 0 ? 1:0; + if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) + return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) == 0 ? 1:0; + + return 0; } public int registerRotTargetWaypoint(Quaternion target, float tolerance) @@ -3567,6 +4969,8 @@ namespace OpenSim.Region.Framework.Scenes waypoint.handle = handle; lock (m_rotTargets) { + if (m_rotTargets.Count >= 8) + m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key); m_rotTargets.Add(handle, waypoint); } m_scene.AddGroupTarget(this); @@ -3592,12 +4996,14 @@ namespace OpenSim.Region.Framework.Scenes waypoint.handle = handle; lock (m_targets) { + if (m_targets.Count >= 8) + m_targets.Remove(m_targets.ElementAt(0).Key); m_targets.Add(handle, waypoint); } m_scene.AddGroupTarget(this); return (int)handle; } - + public void unregisterTargetWaypoint(int handle) { lock (m_targets) @@ -3625,10 +5031,11 @@ namespace OpenSim.Region.Framework.Scenes scriptPosTarget target = m_targets[idx]; if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) { + at_target = true; + // trigger at_target if (m_scriptListens_atTarget) { - at_target = true; scriptPosTarget att = new scriptPosTarget(); att.targetPos = target.targetPos; att.tolerance = target.tolerance; @@ -3638,14 +5045,14 @@ namespace OpenSim.Region.Framework.Scenes } } } - + if (atTargets.Count > 0) { SceneObjectPart[] parts = m_parts.GetArray(); uint[] localids = new uint[parts.Length]; for (int i = 0; i < parts.Length; i++) localids[i] = parts[i].LocalId; - + for (int ctr = 0; ctr < localids.Length; ctr++) { foreach (uint target in atTargets.Keys) @@ -3655,10 +5062,10 @@ namespace OpenSim.Region.Framework.Scenes localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition); } } - + return; } - + if (m_scriptListens_notAtTarget && !at_target) { //trigger not_at_target @@ -3666,7 +5073,7 @@ namespace OpenSim.Region.Framework.Scenes uint[] localids = new uint[parts.Length]; for (int i = 0; i < parts.Length; i++) localids[i] = parts[i].LocalId; - + for (int ctr = 0; ctr < localids.Length; ctr++) { m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); @@ -3746,11 +5153,35 @@ namespace OpenSim.Region.Framework.Scenes } } } - + + public Vector3 GetGeometricCenter() + { + // this is not real geometric center but a average of positions relative to root prim acording to + // http://wiki.secondlife.com/wiki/llGetGeometricCenter + // ignoring tortured prims details since sl also seems to ignore + // so no real use in doing it on physics + + Vector3 gc = Vector3.Zero; + + SceneObjectPart[] parts = m_parts.GetArray(); + int nparts = parts.Length; + if (nparts < 2) + return gc; + + // average all parts positions + for (int i = 0; i < nparts; i++) + { + if (parts[i] != RootPart) + gc += parts[i].OffsetPosition; + } + gc /= nparts; + + return gc; + } + public float GetMass() { float retmass = 0f; - SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) retmass += parts[i].GetMass(); @@ -3758,30 +5189,82 @@ namespace OpenSim.Region.Framework.Scenes return retmass; } - /// - /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that - /// the physics engine can use it. - /// - /// - /// When the physics engine has finished with it, the sculpt data is discarded to save memory. - /// -/* - public void CheckSculptAndLoad() + // center of mass of full object + public Vector3 GetCenterOfMass() { - if (IsDeleted) - return; + PhysicsActor pa = RootPart.PhysActor; - if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) - return; + if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null) + { + // physics knows better about center of mass of physical prims + Vector3 tmp = pa.CenterOfMass; + return tmp; + } -// m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); + Vector3 Ptot = Vector3.Zero; + float totmass = 0f; + float m; SceneObjectPart[] parts = m_parts.GetArray(); - for (int i = 0; i < parts.Length; i++) - parts[i].CheckSculptAndLoad(); + { + m = parts[i].GetMass(); + Ptot += parts[i].GetPartCenterOfMass() * m; + totmass += m; + } + + if (totmass == 0) + totmass = 0; + else + totmass = 1 / totmass; + Ptot *= totmass; + + return Ptot; } -*/ + + public void GetInertiaData(out float TotalMass, out Vector3 CenterOfMass, out Vector3 Inertia, out Vector4 aux ) + { + PhysicsActor pa = RootPart.PhysActor; + + if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null) + { + PhysicsInertiaData inertia; + + inertia = pa.GetInertiaData(); + + TotalMass = inertia.TotalMass; + CenterOfMass = inertia.CenterOfMass; + Inertia = inertia.Inertia; + aux = inertia.InertiaRotation; + + return; + } + + TotalMass = GetMass(); + CenterOfMass = GetCenterOfMass() - AbsolutePosition; + CenterOfMass *= Quaternion.Conjugate(RootPart.RotationOffset); + Inertia = Vector3.Zero; + aux = Vector4.Zero; + } + + public void SetInertiaData(float TotalMass, Vector3 CenterOfMass, Vector3 Inertia, Vector4 aux ) + { + PhysicsInertiaData inertia = new PhysicsInertiaData(); + inertia.TotalMass = TotalMass; + inertia.CenterOfMass = CenterOfMass; + inertia.Inertia = Inertia; + inertia.InertiaRotation = aux; + + if(TotalMass < 0) + RootPart.PhysicsInertia = null; + else + RootPart.PhysicsInertia = new PhysicsInertiaData(inertia); + + PhysicsActor pa = RootPart.PhysActor; + if(pa !=null) + pa.SetInertiaData(inertia); + } + /// /// Set the user group to which this scene object belongs. /// @@ -3798,7 +5281,7 @@ namespace OpenSim.Region.Framework.Scenes } HasGroupChanged = true; - + // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled // for the same object with very different properties. The caller must schedule the update. //ScheduleGroupForFullUpdate(); @@ -3937,6 +5420,133 @@ namespace OpenSim.Region.Framework.Scenes FromItemID = uuid; } + public void ResetOwnerChangeFlag() + { + ForEachPart(delegate(SceneObjectPart part) + { + part.ResetOwnerChangeFlag(); + }); + InvalidateEffectivePerms(); + } + + // clear some references to easy cg + public void Clear() + { + m_parts.Clear(); + m_sittingAvatars.Clear(); +// m_rootPart = null; + + m_PlaySoundMasterPrim = null; + m_PlaySoundSlavePrims.Clear(); + m_LoopSoundMasterPrim = null; + m_targets.Clear(); + m_partsNameToLinkMap.Clear(); + } + + private Dictionary m_partsNameToLinkMap = new Dictionary(); + private string GetLinkNumber_lastname; + private int GetLinkNumber_lastnumber; + + // this scales bad but so does GetLinkNumPart + public int GetLinkNumber(string name) + { + if(String.IsNullOrEmpty(name) || name == "Object") + return -1; + + lock(m_partsNameToLinkMap) + { + if(m_partsNameToLinkMap.Count == 0) + { + GetLinkNumber_lastname = String.Empty; + GetLinkNumber_lastnumber = -1; + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + string s = parts[i].Name; + if(String.IsNullOrEmpty(s) || s == "Object" || s == "Primitive") + continue; + + if(m_partsNameToLinkMap.ContainsKey(s)) + { + int ol = parts[i].LinkNum; + if(ol < m_partsNameToLinkMap[s]) + m_partsNameToLinkMap[s] = ol; + } + else + m_partsNameToLinkMap[s] = parts[i].LinkNum; + } + } + + if(name == GetLinkNumber_lastname) + return GetLinkNumber_lastnumber; + + if(m_partsNameToLinkMap.ContainsKey(name)) + { + lock(m_partsNameToLinkMap) + { + GetLinkNumber_lastname = name; + GetLinkNumber_lastnumber = m_partsNameToLinkMap[name]; + return GetLinkNumber_lastnumber; + } + } + } + + if(m_sittingAvatars.Count > 0) + { + int j = m_parts.Count + 1; + + ScenePresence[] avs = m_sittingAvatars.ToArray(); + for (int i = 0; i < avs.Length; i++, j++) + { + if (avs[i].Name == name) + { + GetLinkNumber_lastname = name; + GetLinkNumber_lastnumber = j; + return j; + } + } + } + + return -1; + } + + public void InvalidatePartsLinkMaps() + { + lock(m_partsNameToLinkMap) + { + m_partsNameToLinkMap.Clear(); + GetLinkNumber_lastname = String.Empty; + GetLinkNumber_lastnumber = -1; + } + } + + public bool CollisionSoundThrottled(int collisionSoundType) + { + double time = m_lastCollisionSoundMS; +// m_lastCollisionSoundMS = Util.GetTimeStampMS(); +// time = m_lastCollisionSoundMS - time; + double now = Util.GetTimeStampMS(); + time = now - time; + switch (collisionSoundType) + { + case 0: // default sounds + case 2: // default sounds with volume set by script + if(time < 300.0) + return true; + break; + case 1: // selected sound + if(time < 200.0) + return true; + break; + default: + break; + } + m_lastCollisionSoundMS = now; + return false; + } + #endregion } + + } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index d1c5f72..2c183ad 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -64,7 +64,8 @@ namespace OpenSim.Region.Framework.Scenes TELEPORT = 512, REGION_RESTART = 1024, MEDIA = 2048, - ANIMATION = 16384 + ANIMATION = 16384, + POSITION = 32768 } // I don't really know where to put this except here. @@ -123,7 +124,18 @@ namespace OpenSim.Region.Framework.Scenes /// Denote all sides of the prim /// public const int ALL_SIDES = -1; - + + private const scriptEvents PhysicsNeededSubsEvents = ( + scriptEvents.collision | scriptEvents.collision_start | scriptEvents.collision_end | + scriptEvents.land_collision | scriptEvents.land_collision_start | scriptEvents.land_collision_end + ); + private const scriptEvents PhyscicsPhantonSubsEvents = ( + scriptEvents.land_collision | scriptEvents.land_collision_start | scriptEvents.land_collision_end + ); + private const scriptEvents PhyscicsVolumeDtcSubsEvents = ( + scriptEvents.collision_start | scriptEvents.collision_end + ); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// @@ -136,8 +148,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// Dynamic objects that can be created and deleted as required. /// - public DOMap DynObjs - { + public DOMap DynObjs + { get { if (m_dynObjs == null) @@ -151,16 +163,16 @@ namespace OpenSim.Region.Framework.Scenes m_dynObjs = value; } } - + /// /// Is this a root part? /// /// /// This will return true even if the whole object is attached to an avatar. /// - public bool IsRoot + public bool IsRoot { - get { return ParentGroup.RootPart == this; } + get { return Object.ReferenceEquals(ParentGroup.RootPart, this); } } /// @@ -173,19 +185,18 @@ namespace OpenSim.Region.Framework.Scenes return !(SitTargetPosition == Vector3.Zero && (SitTargetOrientation == Quaternion.Identity // Valid Zero Rotation quaternion - || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 1f && SitTargetOrientation.W == 0f // W-Z Mapping was invalid at one point - || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 0f && SitTargetOrientation.W == 0f)); // Invalid Quaternion + || (SitTargetOrientation.W == 0f && SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 0f ))); // Invalid Quaternion } } #region Fields public bool AllowedDrop; - + public bool DIE_AT_EDGE; - + public bool RETURN_AT_EDGE; - + public bool BlockGrab { get; set; } public bool StatusSandbox; @@ -210,7 +221,7 @@ namespace OpenSim.Region.Framework.Scenes // Note: This isn't persisted in the database right now, as the fields for that aren't just there yet. // Not a big problem as long as the script that sets it remains in the prim on startup. // for SL compatibility it should be persisted though (set sound / displaytext / particlesystem, kill script) - + public UUID Sound; public byte SoundFlags; @@ -227,26 +238,26 @@ namespace OpenSim.Region.Framework.Scenes /// public bool SoundQueueing { get; set; } - public uint TimeStampFull; - - public uint TimeStampLastActivity; // Will be used for AutoReturn - - public uint TimeStampTerse; + [XmlIgnore] + public Quaternion AttachRotation = Quaternion.Identity; - public int STATUS_ROTATE_X; + [XmlIgnore] + public int STATUS_ROTATE_X; // this should not be used - public int STATUS_ROTATE_Y; + [XmlIgnore] + public int STATUS_ROTATE_Y; // this should not be used - public int STATUS_ROTATE_Z; + [XmlIgnore] + public int STATUS_ROTATE_Z; // this should not be used private Dictionary m_CollisionFilter = new Dictionary(); - + /// /// The UUID of the user inventory item from which this object was rezzed if this is a root part. /// If UUID.Zero then either this is not a root part or there is no connection with a user inventory item. /// private UUID m_fromUserInventoryItemID; - + public UUID FromUserInventoryItemID { get { return m_fromUserInventoryItemID; } @@ -255,12 +266,34 @@ namespace OpenSim.Region.Framework.Scenes public scriptEvents AggregateScriptEvents; - public Vector3 AttachedPos; + public Vector3 AttachedPos + { + get; + set; + } + + // rotation locks on local X,Y and or Z axis bit flags + // bits are as in llSetStatus defined in SceneObjectGroup.axisSelect enum + // but reversed logic: bit cleared means free to rotate + public byte RotationAxisLocks = 0; - public Vector3 RotationAxis = Vector3.One; + // WRONG flag in libOmvPrimFlags + private const uint primFlagVolumeDetect = (uint)PrimFlags.JointLP2P; - public bool VolumeDetectActive; // XmlIgnore set to avoid problems with persistance until I come to care for this - // Certainly this must be a persistant setting finally + public bool VolumeDetectActive + { + get + { + return (Flags & (PrimFlags)primFlagVolumeDetect) != 0; + } + set + { + if(value) + Flags |= (PrimFlags)primFlagVolumeDetect; + else + Flags &= (PrimFlags)(~primFlagVolumeDetect); + } + } public bool IsWaitingForFirstSpinUpdatePacket; @@ -273,7 +306,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// This part's inventory - /// + /// public IEntityInventory Inventory { get { return m_inventory; } @@ -281,29 +314,31 @@ namespace OpenSim.Region.Framework.Scenes protected SceneObjectPartInventory m_inventory; public bool Undoing; - + public bool IgnoreUndoUpdate = false; - + public PrimFlags LocalFlags; - + private float m_damage = -1.0f; private byte[] m_TextureAnimation; private byte m_clickAction; private Color m_color = Color.Black; - private readonly List m_lastColliders = new List(); + private List m_lastColliders = new List(); + private bool m_lastLandCollide; private int m_linkNum; - + private int m_scriptAccessPin; - + private readonly Dictionary m_scriptEvents = new Dictionary(); private string m_sitName = String.Empty; private Quaternion m_sitTargetOrientation = Quaternion.Identity; private Vector3 m_sitTargetPosition; private string m_sitAnimation = "SIT"; + private bool m_occupied; // KF if any av is sitting on this prim private string m_text = String.Empty; private string m_touchName = String.Empty; - private readonly List m_undo = new List(5); - private readonly List m_redo = new List(5); + private UndoRedoState m_UndoRedo = null; + private object m_UndoLock = new object(); private bool m_passTouches = false; private bool m_passCollisions = false; @@ -329,16 +364,22 @@ namespace OpenSim.Region.Framework.Scenes protected Vector3 m_lastPosition; protected Quaternion m_lastRotation; protected Vector3 m_lastVelocity; - protected Vector3 m_lastAcceleration; + protected Vector3 m_lastAcceleration; // acceleration is a derived var with high noise protected Vector3 m_lastAngularVelocity; - protected int m_lastTerseSent; + protected double m_lastUpdateSentTime; + protected float m_buoyancy = 0.0f; + protected Vector3 m_force; + protected Vector3 m_torque; protected byte m_physicsShapeType = (byte)PhysShapeType.prim; protected float m_density = 1000.0f; // in kg/m^3 protected float m_gravitymod = 1.0f; protected float m_friction = 0.6f; // wood protected float m_bounce = 0.5f; // wood - + + + protected bool m_isSelected = false; + /// /// Stores media texture data /// @@ -350,15 +391,24 @@ namespace OpenSim.Region.Framework.Scenes private Vector3 m_cameraAtOffset; private bool m_forceMouselook; - // TODO: Collision sound should have default. + + // 0 for default collision sounds, -1 for script disabled sound 1 for script defined sound + private sbyte m_collisionSoundType = 0; private UUID m_collisionSound; private float m_collisionSoundVolume; + private int LastColSoundSentTime; + + private SOPVehicle m_vehicleParams = null; + + private PhysicsInertiaData m_physicsInertia; + public KeyframeMotion KeyframeMotion { get; set; } + #endregion Fields // ~SceneObjectPart() @@ -388,6 +438,7 @@ namespace OpenSim.Region.Framework.Scenes // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from // the prim into an agent inventory (Linden client reports that the "Object not found for drop" in its log m_inventory = new SceneObjectPartInventory(this); + LastColSoundSentTime = Util.EnvironmentTickCount(); } /// @@ -399,13 +450,13 @@ namespace OpenSim.Region.Framework.Scenes /// /// public SceneObjectPart( - UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, + UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, Quaternion rotationOffset, Vector3 offsetPosition) : this() { - m_name = "Primitive"; + m_name = "Object"; CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed); - LastOwnerID = CreatorID = OwnerID = ownerID; + RezzerID = LastOwnerID = CreatorID = OwnerID = ownerID; UUID = UUID.Random(); Shape = shape; OwnershipCost = 0; @@ -418,16 +469,18 @@ namespace OpenSim.Region.Framework.Scenes Velocity = Vector3.Zero; AngularVelocity = Vector3.Zero; Acceleration = Vector3.Zero; + APIDActive = false; Flags = 0; CreateSelected = true; - TrimPermissions(); + AggregateInnerPerms(); } #endregion Constructors #region XML Schema + private UUID _rezzerID; private UUID _lastOwnerID; private UUID _ownerID; private UUID _groupID; @@ -441,14 +494,14 @@ namespace OpenSim.Region.Framework.Scenes private uint _ownerMask = (uint)(PermissionMask.All | PermissionMask.Export); private uint _groupMask = (uint)PermissionMask.None; private uint _everyoneMask = (uint)PermissionMask.None; - private uint _nextOwnerMask = (uint)PermissionMask.All; + private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Transfer); private PrimFlags _flags = PrimFlags.None; private DateTime m_expires; private DateTime m_rezzed; private bool m_createSelected = false; private UUID _creatorID; - public UUID CreatorID + public UUID CreatorID { get { return _creatorID; } set { _creatorID = value; } @@ -458,7 +511,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Data about the creator in the form home_url;name /// - public string CreatorData + public string CreatorData { get { return m_creatorData; } set { m_creatorData = value; } @@ -480,45 +533,35 @@ namespace OpenSim.Region.Framework.Scenes } set { + CreatorData = string.Empty; if ((value == null) || (value != null && value == string.Empty)) - { - CreatorData = string.Empty; return; - } - if (!value.Contains(";")) // plain UUID + // value is uuid or uuid;homeuri;firstname lastname + string[] parts = value.Split(';'); + if (parts.Length > 0) { + UUID uuid = UUID.Zero; - UUID.TryParse(value, out uuid); + UUID.TryParse(parts[0], out uuid); CreatorID = uuid; - } - else // [;[;name]] - { - string name = "Unknown User"; - string[] parts = value.Split(';'); - if (parts.Length >= 1) - { - UUID uuid = UUID.Zero; - UUID.TryParse(parts[0], out uuid); - CreatorID = uuid; - } - if (parts.Length >= 2) + + if (parts.Length > 1) { CreatorData = parts[1]; if (!CreatorData.EndsWith("/")) CreatorData += "/"; + if (parts.Length > 2) + CreatorData += ';' + parts[2]; + else + CreatorData += ";Unknown User"; } - if (parts.Length >= 3) - name = parts[2]; - - CreatorData += ';' + name; - } } } /// - /// A relic from when we we thought that prims contained folder objects. In + /// A relic from when we we thought that prims contained folder objects. In /// reality, prim == folder /// Exposing this is not particularly good, but it's one of the least evils at the moment to see /// folder id from prim inventory item data, since it's not (yet) actually stored with the prim. @@ -539,12 +582,16 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes + /// Get the inventory list /// public TaskInventoryDictionary TaskInventory { - get { return m_inventory.Items; } - set { m_inventory.Items = value; } + get { + return m_inventory.Items; + } + set { + m_inventory.Items = value; + } } /// @@ -560,10 +607,10 @@ namespace OpenSim.Region.Framework.Scenes public UUID UUID { get { return m_uuid; } - set - { - m_uuid = value; - + set + { + m_uuid = value; + // This is necessary so that TaskInventoryItem parent ids correctly reference the new uuid of this part if (Inventory != null) Inventory.ResetObjectID(); @@ -583,28 +630,16 @@ namespace OpenSim.Region.Framework.Scenes public virtual string Name { get { return m_name; } - set - { - m_name = value; - - PhysicsActor pa = PhysActor; - - if (pa != null) - pa.SOPName = value; - } - } - - public byte Material - { - get { return (byte) m_material; } set { - m_material = (Material)value; + m_name = value; + if(ParentGroup != null) + ParentGroup.InvalidatePartsLinkMaps(); PhysicsActor pa = PhysActor; if (pa != null) - pa.SetMaterial((int)value); + pa.SOPName = value; } } @@ -633,6 +668,19 @@ namespace OpenSim.Region.Framework.Scenes } } + public bool IsSelected + { + get { return m_isSelected; } + set + { + m_isSelected = value; + if (ParentGroup != null) + ParentGroup.PartSelectChanged(value); + + } + } + + public Dictionary CollisionFilter { get { return m_CollisionFilter; } @@ -654,14 +702,14 @@ namespace OpenSim.Region.Framework.Scenes set { m_APIDTarget = value; } } - + protected float APIDDamp { get { return m_APIDDamp; } set { m_APIDDamp = value; } } - + protected float APIDStrength { get { return m_APIDStrength; } @@ -707,53 +755,61 @@ namespace OpenSim.Region.Framework.Scenes set { m_LoopSoundSlavePrims = value; } } - public Byte[] TextureAnimation { get { return m_TextureAnimation; } set { m_TextureAnimation = value; } } - public Byte[] ParticleSystem { get { return m_particleSystem; } set { m_particleSystem = value; } } - + public DateTime Expires { get { return m_expires; } set { m_expires = value; } } - + public DateTime Rezzed { get { return m_rezzed; } set { m_rezzed = value; } } - + public float Damage { get { return m_damage; } set { m_damage = value; } } + public void setGroupPosition(Vector3 pos) + { + m_groupPosition = pos; + } + /// /// The position of the entire group that this prim belongs to. /// + /// + public Vector3 GroupPosition { get { // If this is a linkset, we don't want the physics engine mucking up our group position here. PhysicsActor actor = PhysActor; - // If physical and the root prim of a linkset, the position of the group is what physics thinks. - if (actor != null && ParentID == 0) - m_groupPosition = actor.Position; + if (_parentID == 0) + { + if (actor != null) + m_groupPosition = actor.Position; + return m_groupPosition; + } // If I'm an attachment, my position is reported as the position of who I'm attached to if (ParentGroup.IsAttachment) @@ -763,19 +819,21 @@ namespace OpenSim.Region.Framework.Scenes return sp.AbsolutePosition; } + // use root prim's group position. Physics may have updated it + if (ParentGroup.RootPart != this) + m_groupPosition = ParentGroup.RootPart.GroupPosition; return m_groupPosition; } set { m_groupPosition = value; - PhysicsActor actor = PhysActor; - if (actor != null) + if (actor != null && ParentGroup.Scene.PhysicsScene != null) { try { // Root prim actually goes at Position - if (ParentID == 0) + if (_parentID == 0) { actor.Position = value; } @@ -798,27 +856,51 @@ namespace OpenSim.Region.Framework.Scenes } } + public void setOffsetPosition(Vector3 pos) + { + m_offsetPosition = pos; + } + public Vector3 OffsetPosition { get { return m_offsetPosition; } set { -// StoreUndoState(); + Vector3 oldpos = m_offsetPosition; m_offsetPosition = value; if (ParentGroup != null && !ParentGroup.IsDeleted) { + if((oldpos - m_offsetPosition).LengthSquared() > 1.0f) + ParentGroup.InvalidBoundsRadius(); + PhysicsActor actor = PhysActor; - if (ParentID != 0 && actor != null) + if (_parentID != 0 && actor != null) { actor.Position = GetWorldPosition(); actor.Orientation = GetWorldRotation(); // Tell the physics engines that this prim changed. - if (ParentGroup.Scene != null) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null) ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); } + + if (!m_parentGroup.m_dupeInProgress) + { + List avs = ParentGroup.GetSittingAvatars(); + foreach (ScenePresence av in avs) + { + if (av.ParentID == m_localId) + { + Vector3 offset = (m_offsetPosition - oldpos); + av.AbsolutePosition += offset; +// av.SendAvatarDataToAllAgents(); + av.SendTerseUpdateToAllClients(); + } + } + } } + TriggerScriptChangedEvent(Changed.POSITION); } } @@ -840,6 +922,11 @@ namespace OpenSim.Region.Framework.Scenes } } + public void setRotationOffset(Quaternion q) + { + m_rotationOffset = q; + } + public Quaternion RotationOffset { get @@ -848,28 +935,15 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor actor = PhysActor; // If this is a root of a linkset, the real rotation is what the physics engine thinks. // If not a root prim, the offset rotation is computed by SOG and is relative to the root. - if (ParentID == 0 && (Shape.PCode != 9 || Shape.State == 0) && actor != null) - { - if (actor.Orientation.X != 0f || actor.Orientation.Y != 0f - || actor.Orientation.Z != 0f || actor.Orientation.W != 0f) - { - m_rotationOffset = actor.Orientation; - } - } - -// float roll, pitch, yaw = 0; -// m_rotationOffset.GetEulerAngles(out roll, out pitch, out yaw); -// -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Got euler {0} for RotationOffset on {1} {2}", -// new Vector3(roll, pitch, yaw), Name, LocalId); + if (_parentID == 0 && (Shape.PCode != 9 || Shape.State == 0) && actor != null) + m_rotationOffset = actor.Orientation; return m_rotationOffset; } - + set { - StoreUndoState(); +// StoreUndoState(); m_rotationOffset = value; PhysicsActor actor = PhysActor; @@ -878,7 +952,7 @@ namespace OpenSim.Region.Framework.Scenes try { // Root prim gets value directly - if (ParentID == 0) + if (_parentID == 0) { actor.Orientation = value; //m_log.Info("[PART]: RO1:" + actor.Orientation.ToString()); @@ -960,7 +1034,7 @@ namespace OpenSim.Region.Framework.Scenes get { PhysicsActor actor = PhysActor; - if ((actor != null) && actor.IsPhysical) + if ((actor != null) && actor.IsPhysical && ParentGroup.RootPart == this) { m_angularVelocity = actor.RotationalVelocity; } @@ -974,21 +1048,38 @@ namespace OpenSim.Region.Framework.Scenes m_angularVelocity = value; PhysicsActor actor = PhysActor; - if ((actor != null) && actor.IsPhysical) + if ((actor != null) && actor.IsPhysical && ParentGroup.RootPart == this) + { actor.RotationalVelocity = m_angularVelocity; + } } } /// public Vector3 Acceleration { - get { return m_acceleration; } - set + get + { + PhysicsActor actor = PhysActor; + if (actor != null) + { + m_acceleration = actor.Acceleration; + } + return m_acceleration; + } + + set { if (Util.IsNanOrInfinity(value)) m_acceleration = Vector3.Zero; else m_acceleration = value; + + PhysicsActor actor = PhysActor; + if ((actor != null) && actor.IsPhysical && ParentGroup.RootPart == this) + { + actor.Acceleration = m_acceleration; + } } } @@ -1007,8 +1098,8 @@ namespace OpenSim.Region.Framework.Scenes { get { - if (m_text.Length > 255) - return m_text.Substring(0, 254); + if (m_text.Length > 256) // yes > 254 + return m_text.Substring(0, 256); return m_text; } set { m_text = value; } @@ -1056,7 +1147,10 @@ namespace OpenSim.Region.Framework.Scenes public PrimitiveBaseShape Shape { get { return m_shape; } - set { m_shape = value;} + set + { + m_shape = value; + } } /// @@ -1069,10 +1163,10 @@ namespace OpenSim.Region.Framework.Scenes { if (m_shape != null) { - StoreUndoState(); - + Vector3 oldscale = m_shape.Scale; m_shape.Scale = value; - + if (ParentGroup != null && ((value - oldscale).LengthSquared() >1.0f)) + ParentGroup.InvalidBoundsRadius(); PhysicsActor actor = PhysActor; if (actor != null) { @@ -1081,11 +1175,7 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup.Scene.PhysicsScene != null) { actor.Size = m_shape.Scale; - -// if (Shape.SculptEntry) -// CheckSculptAndLoad(); -// else - ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); + ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); } } } @@ -1095,20 +1185,47 @@ namespace OpenSim.Region.Framework.Scenes } } + public float maxSimpleArea() + { + float a,b; + float sx = m_shape.Scale.X; + float sy = m_shape.Scale.Y; + float sz = m_shape.Scale.Z; + + if( sx > sy) + { + a = sx; + if(sy > sz) + b = sy; + else + b = sz; + } + else + { + a = sy; + if(sx > sz) + b = sx; + else + b = sz; + } + + return a * b; + } + public UpdateRequired UpdateFlag { get; set; } - public bool UpdatePhysRequired { get; set; } - + private object UpdateFlagLock = new object(); + /// /// Used for media on a prim. /// /// Do not change this value directly - always do it through an IMoapModule. - public string MediaUrl - { + public string MediaUrl + { get { - return m_mediaUrl; + return m_mediaUrl; } - + set { m_mediaUrl = value; @@ -1121,10 +1238,10 @@ namespace OpenSim.Region.Framework.Scenes public bool CreateSelected { get { return m_createSelected; } - set - { + set + { // m_log.DebugFormat("[SOP]: Setting CreateSelected to {0} for {1} {2}", value, Name, UUID); - m_createSelected = value; + m_createSelected = value; } } @@ -1137,10 +1254,10 @@ namespace OpenSim.Region.Framework.Scenes { get { - if (ParentGroup.IsAttachment) + if (_parentID == 0) return GroupPosition; - return m_offsetPosition + m_groupPosition; + return GroupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset); } } @@ -1261,7 +1378,14 @@ namespace OpenSim.Region.Framework.Scenes public UUID LastOwnerID { get { return _lastOwnerID; } - set { _lastOwnerID = value; } + set { + _lastOwnerID = value; } + } + + public UUID RezzerID + { + get { return _rezzerID; } + set { _rezzerID = value; } } public uint BaseMask @@ -1295,7 +1419,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Property flags. See OpenMetaverse.PrimFlags + /// Property flags. See OpenMetaverse.PrimFlags /// /// /// Example properties are PrimFlags.Phantom and PrimFlags.DieAtEdge @@ -1303,13 +1427,20 @@ namespace OpenSim.Region.Framework.Scenes public PrimFlags Flags { get { return _flags; } - set - { + set + { // m_log.DebugFormat("[SOP]: Setting flags for {0} {1} to {2}", UUID, Name, value); - _flags = value; + _flags = value; } } + [XmlIgnore] + public bool IsOccupied // KF If an av is sittingon this prim + { + get { return m_occupied; } + set { m_occupied = value; } + } + /// /// ID of the avatar that is sat on us if we have a sit target. If there is no such avatar then is UUID.Zero /// @@ -1339,7 +1470,7 @@ namespace OpenSim.Region.Framework.Scenes } private UUID _parentUUID = UUID.Zero; - + public UUID ParentUUID { get @@ -1352,20 +1483,48 @@ namespace OpenSim.Region.Framework.Scenes set { _parentUUID = value; } } - + public string SitAnimation { get { return m_sitAnimation; } set { m_sitAnimation = value; } } + public UUID invalidCollisionSoundUUID = new UUID("ffffffff-ffff-ffff-ffff-ffffffffffff"); + + // 0 for default collision sounds, -1 for script disabled sound 1 for script defined sound + // runtime thing.. do not persist + [XmlIgnore] + public sbyte CollisionSoundType + { + get + { + return m_collisionSoundType; + } + set + { + m_collisionSoundType = value; + if (value == -1) + m_collisionSound = invalidCollisionSoundUUID; + else if (value == 0) + m_collisionSound = UUID.Zero; + } + } + public UUID CollisionSound { get { return m_collisionSound; } set { m_collisionSound = value; - aggregateScriptEvents(); + + if (value == invalidCollisionSoundUUID) + m_collisionSoundType = -1; + else if (value == UUID.Zero) + m_collisionSoundType = 0; + else + m_collisionSoundType = 1; + } } @@ -1375,65 +1534,242 @@ namespace OpenSim.Region.Framework.Scenes set { m_collisionSoundVolume = value; } } - public byte DefaultPhysicsShapeType() + public float Buoyancy { - byte type; - - if (Shape != null && (Shape.SculptType == (byte)SculptType.Mesh)) - type = (byte)PhysShapeType.convex; - else - type = (byte)PhysShapeType.prim; + get + { + if (ParentGroup.RootPart == this) + return m_buoyancy; - return type; + return ParentGroup.RootPart.Buoyancy; + } + set + { + if (ParentGroup != null && ParentGroup.RootPart != null && ParentGroup.RootPart != this) + { + ParentGroup.RootPart.Buoyancy = value; + return; + } + m_buoyancy = value; + if (PhysActor != null) + PhysActor.Buoyancy = value; + } } - public byte PhysicsShapeType + public Vector3 Force { - get { return m_physicsShapeType; } - set + get { - byte oldv = m_physicsShapeType; + if (ParentGroup.RootPart == this) + return m_force; - if (value >= 0 && value <= (byte)PhysShapeType.convex) + return ParentGroup.RootPart.Force; + } + + set + { + if (ParentGroup != null && ParentGroup.RootPart != null && ParentGroup.RootPart != this) { - if (value == (byte)PhysShapeType.none && ParentGroup != null && ParentGroup.RootPart == this) - m_physicsShapeType = DefaultPhysicsShapeType(); - else - m_physicsShapeType = value; + ParentGroup.RootPart.Force = value; + return; } - else - m_physicsShapeType = DefaultPhysicsShapeType(); + m_force = value; + if (PhysActor != null) + PhysActor.Force = value; + } + } - if (m_physicsShapeType != oldv && ParentGroup != null) - { - if (m_physicsShapeType == (byte)PhysShapeType.none) - { - if (PhysActor != null) + public Vector3 Torque + { + get + { + if (ParentGroup.RootPart == this) + return m_torque; + + return ParentGroup.RootPart.Torque; + } + + set + { + if (ParentGroup != null && ParentGroup.RootPart != null && ParentGroup.RootPart != this) + { + ParentGroup.RootPart.Torque = value; + return; + } + m_torque = value; + if (PhysActor != null) + PhysActor.Torque = value; + } + } + + public byte Material + { + get { return (byte)m_material; } + set + { + if (value >= 0 && value <= (byte)SOPMaterialData.MaxMaterial) + { + bool update = false; + + if (m_material != (Material)value) + { + update = true; + m_material = (Material)value; + } + + if (m_friction != SOPMaterialData.friction(m_material)) + { + update = true; + m_friction = SOPMaterialData.friction(m_material); + } + + if (m_bounce != SOPMaterialData.bounce(m_material)) + { + update = true; + m_bounce = SOPMaterialData.bounce(m_material); + } + + if (update) + { + if (PhysActor != null) + { + PhysActor.SetMaterial((int)value); + } + if(ParentGroup != null) + { + ParentGroup.HasGroupChanged = true; + ScheduleFullUpdate(); + } + } + } + } + } + + // not a propriety to move to methods place later + private bool HasMesh() + { + if (Shape != null && (Shape.SculptType == (byte)SculptType.Mesh)) + return true; + return false; + } + + // not a propriety to move to methods place later + public byte DefaultPhysicsShapeType() + { + byte type; + + if (Shape != null && (Shape.SculptType == (byte)SculptType.Mesh)) + type = (byte)PhysShapeType.convex; + else + type = (byte)PhysShapeType.prim; + + return type; + } + + [XmlIgnore] + public bool UsesComplexCost + { + get + { + byte pst = PhysicsShapeType; + if(pst == (byte) PhysShapeType.none || HasMesh()) + return true; + return false; + } + } + + [XmlIgnore] + public float PhysicsCost + { + get + { + if(PhysicsShapeType == (byte)PhysShapeType.none) + return 0; + + float cost = 0.1f; + if (PhysActor != null) + cost = PhysActor.PhysicsCost; + else + cost = 0.1f; + + if ((Flags & PrimFlags.Physics) != 0) + cost *= (1.0f + 0.01333f * Scale.LengthSquared()); // 0.01333 == 0.04/3 + return cost; + } + } + + [XmlIgnore] + public float StreamingCost + { + get + { + float cost; + if (PhysActor != null) + cost = PhysActor.StreamCost; + else + cost = 1.0f; + return 1.0f; + } + } + + [XmlIgnore] + public float SimulationCost + { + get + { + // ignoring scripts. Don't like considering them for this + if((Flags & PrimFlags.Physics) != 0) + return 1.0f; + + return 0.5f; + } + } + + public byte PhysicsShapeType + { + get + { +// if (PhysActor != null) +// m_physicsShapeType = PhysActor.PhysicsShapeType; + return m_physicsShapeType; + } + set + { + byte oldv = m_physicsShapeType; + + if (value >= 0 && value <= (byte)PhysShapeType.convex) + { + if (value == (byte)PhysShapeType.none && ParentGroup != null && ParentGroup.RootPart == this) + m_physicsShapeType = DefaultPhysicsShapeType(); + else + m_physicsShapeType = value; + } + else + m_physicsShapeType = DefaultPhysicsShapeType(); + + if (m_physicsShapeType != oldv && ParentGroup != null) + { + if (m_physicsShapeType == (byte)PhysShapeType.none) + { + if (PhysActor != null) { - Velocity = new Vector3(0, 0, 0); - Acceleration = new Vector3(0, 0, 0); - if (ParentGroup.RootPart == this) - AngularVelocity = new Vector3(0, 0, 0); ParentGroup.Scene.RemovePhysicalPrim(1); RemoveFromPhysics(); +// Stop(); } } else if (PhysActor == null) { - ApplyPhysics((uint)Flags, VolumeDetectActive); + if(oldv == (byte)PhysShapeType.none) + { + ApplyPhysics((uint)Flags, VolumeDetectActive, false); + UpdatePhysicsSubscribedEvents(); + } } else - { PhysActor.PhysicsShapeType = m_physicsShapeType; - } - - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; - } - if (m_physicsShapeType != value) - { - UpdatePhysRequired = true; + ParentGroup.HasGroupChanged = true; } } } @@ -1446,17 +1782,18 @@ namespace OpenSim.Region.Framework.Scenes if (value >=1 && value <= 22587.0) { m_density = value; - UpdatePhysRequired = true; - } - ScheduleFullUpdateIfNone(); - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; + if (ParentGroup != null) + { + ParentGroup.HasGroupChanged = true; + ScheduleFullUpdate(); + } - PhysicsActor pa = PhysActor; - if (pa != null) - pa.Density = Density; + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Density = m_density; + } } } @@ -1468,17 +1805,17 @@ namespace OpenSim.Region.Framework.Scenes if( value >= -1 && value <=28.0f) { m_gravitymod = value; - UpdatePhysRequired = true; - } - - ScheduleFullUpdateIfNone(); - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; + if (ParentGroup != null) + { + ParentGroup.HasGroupChanged = true; + ScheduleFullUpdate(); + } - PhysicsActor pa = PhysActor; - if (pa != null) - pa.GravModifier = GravityModifier; + PhysicsActor pa = PhysActor; + if (pa != null) + pa.GravModifier = m_gravitymod; + } } } @@ -1490,17 +1827,17 @@ namespace OpenSim.Region.Framework.Scenes if (value >= 0 && value <= 255.0f) { m_friction = value; - UpdatePhysRequired = true; - } - ScheduleFullUpdateIfNone(); - - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; + if (ParentGroup != null) + { + ParentGroup.HasGroupChanged = true; + ScheduleFullUpdate(); + } - PhysicsActor pa = PhysActor; - if (pa != null) - pa.Friction = Friction; + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Friction = m_friction; + } } } @@ -1512,20 +1849,21 @@ namespace OpenSim.Region.Framework.Scenes if (value >= 0 && value <= 1.0f) { m_bounce = value; - UpdatePhysRequired = true; - } - - ScheduleFullUpdateIfNone(); - if (ParentGroup != null) - ParentGroup.HasGroupChanged = true; + if (ParentGroup != null) + { + ParentGroup.HasGroupChanged = true; + ScheduleFullUpdate(); + } - PhysicsActor pa = PhysActor; - if (pa != null) - pa.Restitution = Restitution; + PhysicsActor pa = PhysActor; + if (pa != null) + pa.Restitution = m_bounce; + } } } + #endregion Public Properties with only Get private uint ApplyMask(uint val, bool set, uint mask) @@ -1545,7 +1883,8 @@ namespace OpenSim.Region.Framework.Scenes /// public void ClearUpdateSchedule() { - UpdateFlag = UpdateRequired.NONE; + lock(UpdateFlagLock) + UpdateFlag = UpdateRequired.NONE; } /// @@ -1585,7 +1924,7 @@ namespace OpenSim.Region.Framework.Scenes public void ResetExpire() { - Expires = DateTime.Now + new TimeSpan(600000000); + Expires = DateTime.UtcNow + new TimeSpan(600000000); } public void AddFlag(PrimFlags flag) @@ -1636,8 +1975,8 @@ namespace OpenSim.Region.Framework.Scenes Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos); Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4); Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8); - } + } m_TextureAnimation = data; } @@ -1680,6 +2019,61 @@ namespace OpenSim.Region.Framework.Scenes } } + // SetVelocity for LSL llSetVelocity.. may need revision if having other uses in future + public void SetVelocity(Vector3 pVel, bool localGlobalTF) + { + if (ParentGroup == null || ParentGroup.IsDeleted || ParentGroup.inTransit) + return; + + if (ParentGroup.IsAttachment) + return; // don't work on attachments (for now ??) + + SceneObjectPart root = ParentGroup.RootPart; + + if (root.VehicleType != (int)Vehicle.TYPE_NONE) // don't mess with vehicles + return; + + PhysicsActor pa = root.PhysActor; + + if (pa == null || !pa.IsPhysical) + return; + + if (localGlobalTF) + { + pVel = pVel * GetWorldRotation(); + } + + ParentGroup.Velocity = pVel; + } + + // SetAngularVelocity for LSL llSetAngularVelocity.. may need revision if having other uses in future + public void SetAngularVelocity(Vector3 pAngVel, bool localGlobalTF) + { + if (ParentGroup == null || ParentGroup.IsDeleted || ParentGroup.inTransit) + return; + + if (ParentGroup.IsAttachment) + return; // don't work on attachments (for now ??) + + SceneObjectPart root = ParentGroup.RootPart; + + if (root.VehicleType != (int)Vehicle.TYPE_NONE) // don't mess with vehicles + return; + + PhysicsActor pa = root.PhysActor; + + if (pa == null || !pa.IsPhysical) + return; + + if (localGlobalTF) + { + pAngVel = pAngVel * GetWorldRotation(); + } + + root.AngularVelocity = pAngVel; + } + + /// /// hook to the physics scene to apply angular impulse /// This is sent up to the group, which then finds the root prim @@ -1689,6 +2083,9 @@ namespace OpenSim.Region.Framework.Scenes /// true for the local frame, false for the global frame public void ApplyAngularImpulse(Vector3 impulsei, bool localGlobalTF) { + if (ParentGroup == null || ParentGroup.IsDeleted || ParentGroup.inTransit) + return; + Vector3 impulse = impulsei; if (localGlobalTF) @@ -1700,7 +2097,7 @@ namespace OpenSim.Region.Framework.Scenes impulse = newimpulse; } - ParentGroup.applyAngularImpulse(impulse); + ParentGroup.ApplyAngularImpulse(impulse); } /// @@ -1710,20 +2107,18 @@ namespace OpenSim.Region.Framework.Scenes /// /// Vector force /// true for the local frame, false for the global frame - public void SetAngularImpulse(Vector3 impulsei, bool localGlobalTF) + + // this is actualy Set Torque.. keeping naming so not to edit lslapi also + public void SetAngularImpulse(Vector3 torquei, bool localGlobalTF) { - Vector3 impulse = impulsei; + Vector3 torque = torquei; if (localGlobalTF) { - Quaternion grot = GetWorldRotation(); - Quaternion AXgrot = grot; - Vector3 AXimpulsei = impulsei; - Vector3 newimpulse = AXimpulsei * AXgrot; - impulse = newimpulse; + torque *= GetWorldRotation(); } - ParentGroup.setAngularImpulse(impulse); + Torque = torque; } /// @@ -1731,7 +2126,9 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public void ApplyPhysics(uint rootObjectFlags, bool _VolumeDetectActive) + /// + + public void ApplyPhysics(uint _ObjectFlags, bool _VolumeDetectActive, bool building) { VolumeDetectActive = _VolumeDetectActive; @@ -1741,8 +2138,8 @@ namespace OpenSim.Region.Framework.Scenes if (PhysicsShapeType == (byte)PhysShapeType.none) return; - bool isPhysical = (rootObjectFlags & (uint) PrimFlags.Physics) != 0; - bool isPhantom = (rootObjectFlags & (uint) PrimFlags.Phantom) != 0; + bool isPhysical = (_ObjectFlags & (uint) PrimFlags.Physics) != 0; + bool isPhantom = (_ObjectFlags & (uint)PrimFlags.Phantom) != 0; if (_VolumeDetectActive) isPhantom = true; @@ -1757,10 +2154,14 @@ namespace OpenSim.Region.Framework.Scenes && !ParentGroup.IsAttachmentCheckFull() && !(Shape.PathCurve == (byte)Extrusion.Flexible)) { - AddToPhysics(isPhysical, isPhantom, isPhysical); + AddToPhysics(isPhysical, isPhantom, building, isPhysical); + UpdatePhysicsSubscribedEvents(); // not sure if appliable here } else + { PhysActor = null; // just to be sure + RemFlag(PrimFlags.CameraDecoupled); + } } } @@ -1786,9 +2187,9 @@ namespace OpenSim.Region.Framework.Scenes /// /// True if the duplicate will immediately be in the scene, false otherwise /// - public SceneObjectPart Copy(uint localID, UUID AgentID, UUID GroupID, int linkNum, bool userExposed) + public SceneObjectPart Copy(uint plocalID, UUID AgentID, UUID GroupID, int linkNum, bool userExposed) { - // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up + // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator // but not between regions on different simulators). Really, all copying should be done explicitly. SceneObjectPart dupe = (SceneObjectPart)MemberwiseClone(); @@ -1816,6 +2217,12 @@ namespace OpenSim.Region.Framework.Scenes dupe.Category = Category; dupe.m_rezzed = m_rezzed; + dupe.m_UndoRedo = null; + dupe.m_isSelected = false; + + dupe.IgnoreUndoUpdate = false; + dupe.Undoing = false; + dupe.m_inventory = new SceneObjectPartInventory(dupe); dupe.m_inventory.Items = (TaskInventoryDictionary)m_inventory.Items.Clone(); @@ -1830,60 +2237,45 @@ namespace OpenSim.Region.Framework.Scenes } // Move afterwards ResetIDs as it clears the localID - dupe.LocalId = localID; + dupe.LocalId = plocalID; + // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. - dupe.LastOwnerID = OwnerID; + if(OwnerID != GroupID) + dupe.LastOwnerID = OwnerID; + else + dupe.LastOwnerID = LastOwnerID; // redundant ? + + dupe.RezzerID = RezzerID; byte[] extraP = new byte[Shape.ExtraParams.Length]; Array.Copy(Shape.ExtraParams, extraP, extraP.Length); dupe.Shape.ExtraParams = extraP; dupe.m_sittingAvatars = new HashSet(); - + dupe.SitTargetAvatar = UUID.Zero; // safeguard actual copy is done in sog.copy dupe.KeyframeMotion = null; dupe.PayPrice = (int[])PayPrice.Clone(); dupe.DynAttrs.CopyFrom(DynAttrs); - + if (userExposed) { -/* - if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero) - { - ParentGroup.Scene.AssetService.Get( - dupe.m_shape.SculptTexture.ToString(), dupe, dupe.AssetReceived); - } -*/ bool UsePhysics = ((dupe.Flags & PrimFlags.Physics) != 0); dupe.DoPhysicsPropertyUpdate(UsePhysics, true); } - + + if (dupe.PhysActor != null) + dupe.PhysActor.LocalID = plocalID; + ParentGroup.Scene.EventManager.TriggerOnSceneObjectPartCopy(dupe, this, userExposed); // m_log.DebugFormat("[SCENE OBJECT PART]: Clone of {0} {1} finished", Name, UUID); - + return dupe; } /// - /// Called back by asynchronous asset fetch. - /// - /// ID of asset received - /// Register - /// -/* - protected void AssetReceived(string id, Object sender, AssetBase asset) - { - if (asset != null) - SculptTextureCallback(asset); - else - m_log.WarnFormat( - "[SCENE OBJECT PART]: Part {0} {1} requested mesh/sculpt data for asset id {2} from asset service but received no data", - Name, UUID, id); - } -*/ - /// /// Do a physics property update for a NINJA joint. /// /// @@ -1970,15 +2362,14 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.Scene.PhysicsScene.RequestJointDeletion(Name); // FIXME: what if the name changed? // make sure client isn't interpolating the joint proxy object - Velocity = Vector3.Zero; - AngularVelocity = Vector3.Zero; - Acceleration = Vector3.Zero; + Stop(); } } } /// /// Do a physics propery update for this part. + /// now also updates phantom and volume detector /// /// /// @@ -2004,66 +2395,71 @@ namespace OpenSim.Region.Framework.Scenes { if (pa.IsPhysical) // implies UsePhysics==false for this block { - if (!isNew) + if (!isNew) // implies UsePhysics==false for this block + { ParentGroup.Scene.RemovePhysicalPrim(1); - pa.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate; - pa.OnOutOfBounds -= PhysicsOutOfBounds; - pa.delink(); + Velocity = new Vector3(0, 0, 0); + Acceleration = new Vector3(0, 0, 0); + AngularVelocity = new Vector3(0, 0, 0); + APIDActive = false; - if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints && (!isNew)) - { - // destroy all joints connected to this now deactivated body - ParentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(pa); - } + if (pa.Phantom && !VolumeDetectActive) + { + RemoveFromPhysics(); + return; + } - // stop client-side interpolation of all joint proxy objects that have just been deleted - // this is done because RemoveAllJointsConnectedToActor invokes the OnJointDeactivated callback, - // which stops client-side interpolation of deactivated joint proxy objects. + pa.IsPhysical = UsePhysics; + pa.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate; + pa.OnOutOfBounds -= PhysicsOutOfBounds; + pa.delink(); + if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + { + // destroy all joints connected to this now deactivated body + ParentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(pa); + } + } } - if (!UsePhysics && !isNew) - { - // reset velocity to 0 on physics switch-off. Without that, the client thinks the - // prim still has velocity and continues to interpolate its position along the old - // velocity-vector. - Velocity = new Vector3(0, 0, 0); - Acceleration = new Vector3(0, 0, 0); - AngularVelocity = new Vector3(0, 0, 0); - //RotationalVelocity = new Vector3(0, 0, 0); - } + if (pa.IsPhysical != UsePhysics) + pa.IsPhysical = UsePhysics; - pa.IsPhysical = UsePhysics; + if (UsePhysics) + { + if (ParentGroup.RootPart.KeyframeMotion != null) + ParentGroup.RootPart.KeyframeMotion.Stop(); + ParentGroup.RootPart.KeyframeMotion = null; + ParentGroup.Scene.AddPhysicalPrim(1); - // If we're not what we're supposed to be in the physics scene, recreate ourselves. - //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); - /// that's not wholesome. Had to make Scene public - //PhysActor = null; + PhysActor.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; + PhysActor.OnOutOfBounds += PhysicsOutOfBounds; - if ((Flags & PrimFlags.Phantom) == 0) - { - if (UsePhysics) + if (_parentID != 0 && _parentID != LocalId) { - if (ParentGroup.RootPart.KeyframeMotion != null) - ParentGroup.RootPart.KeyframeMotion.Stop(); - ParentGroup.RootPart.KeyframeMotion = null; - ParentGroup.Scene.AddPhysicalPrim(1); - - pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; - pa.OnOutOfBounds += PhysicsOutOfBounds; - if (ParentID != 0 && ParentID != LocalId) - { - PhysicsActor parentPa = ParentGroup.RootPart.PhysActor; + PhysicsActor parentPa = ParentGroup.RootPart.PhysActor; - if (parentPa != null) - { - pa.link(parentPa); - } + if (parentPa != null) + { + pa.link(parentPa); } } } } + bool phan = ((Flags & PrimFlags.Phantom) != 0); + if (pa.Phantom != phan) + pa.Phantom = phan; + +// some engines dont' have this check still +// if (VolumeDetectActive != pa.IsVolumeDtc) + { + if (VolumeDetectActive) + pa.SetVolumeDetect(1); + else + pa.SetVolumeDetect(0); + } + // If this part is a sculpt then delay the physics update until we've asynchronously loaded the // mesh data. // if (Shape.SculptEntry) @@ -2132,13 +2528,8 @@ namespace OpenSim.Region.Framework.Scenes public int GetAxisRotation(int axis) { - //Cannot use ScriptBaseClass constants as no referance to it currently. - if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) - return STATUS_ROTATE_X; - if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) - return STATUS_ROTATE_Y; - if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) - return STATUS_ROTATE_Z; + if (!ParentGroup.IsDeleted) + return ParentGroup.GetAxisRotation(axis); return 0; } @@ -2153,7 +2544,7 @@ namespace OpenSim.Region.Framework.Scenes public uint GetEffectiveObjectFlags() { - // Commenting this section of code out since it doesn't actually do anything, as enums are handled by + // Commenting this section of code out since it doesn't actually do anything, as enums are handled by // value rather than reference // PrimFlags f = _flags; // if (m_parentGroup == null || m_parentGroup.RootPart == this) @@ -2162,44 +2553,118 @@ namespace OpenSim.Region.Framework.Scenes return (uint)Flags | (uint)LocalFlags; } + // some of this lines need be moved to other place later + + // effective permitions considering only this part inventory contents perms + public uint AggregatedInnerOwnerPerms {get; private set; } + public uint AggregatedInnerGroupPerms {get; private set; } + public uint AggregatedInnerEveryonePerms {get; private set; } + private object InnerPermsLock = new object(); + + public void AggregateInnerPerms() + { + // assuming child prims permissions masks are irrelevant on a linkset + // root part is handle at SOG since its masks are the sog masks + const uint mask = (uint)PermissionMask.AllEffective; + + uint owner = mask; + uint group = mask; + uint everyone = mask; + + lock(InnerPermsLock) // do we really need this? + { + if(Inventory != null) + Inventory.AggregateInnerPerms(ref owner, ref group, ref everyone); + + AggregatedInnerOwnerPerms = owner & mask; + AggregatedInnerGroupPerms = group & mask; + AggregatedInnerEveryonePerms = everyone & mask; + } + if(ParentGroup != null) + ParentGroup.InvalidateEffectivePerms(); + } + + // same as above but called during group Effective Permission validation + public void AggregatedInnerPermsForGroup() + { + // assuming child prims permissions masks are irrelevant on a linkset + // root part is handle at SOG since its masks are the sog masks + const uint mask = (uint)PermissionMask.AllEffective; + + uint owner = mask; + uint group = mask; + uint everyone = mask; + + lock(InnerPermsLock) // do we really need this? + { + if(Inventory != null) + Inventory.AggregateInnerPerms(ref owner, ref group, ref everyone); + + AggregatedInnerOwnerPerms = owner & mask; + AggregatedInnerGroupPerms = group & mask; + AggregatedInnerEveryonePerms = everyone & mask; + } + } + public Vector3 GetGeometricCenter() { + // this is not real geometric center but a average of positions relative to root prim acording to + // http://wiki.secondlife.com/wiki/llGetGeometricCenter + // ignoring tortured prims details since sl also seems to ignore + // so no real use in doing it on physics + if (ParentGroup.IsDeleted) + return new Vector3(0, 0, 0); + + return ParentGroup.GetGeometricCenter(); + } + + public float GetMass() + { PhysicsActor pa = PhysActor; if (pa != null) - return pa.GeometricCenter; + return pa.Mass; else - return Vector3.Zero; + return 0; } public Vector3 GetCenterOfMass() { + if (ParentGroup.RootPart == this) + { + if (ParentGroup.IsDeleted) + return AbsolutePosition; + return ParentGroup.GetCenterOfMass(); + } + PhysicsActor pa = PhysActor; if (pa != null) - return pa.CenterOfMass; + { + Vector3 tmp = pa.CenterOfMass; + return tmp; + } else - return Vector3.Zero; + return AbsolutePosition; } - public float GetMass() + public Vector3 GetPartCenterOfMass() { PhysicsActor pa = PhysActor; if (pa != null) - return pa.Mass; + { + Vector3 tmp = pa.CenterOfMass; + return tmp; + } else - return 0; + return AbsolutePosition; } + public Vector3 GetForce() { - PhysicsActor pa = PhysActor; - - if (pa != null) - return pa.Force; - else - return Vector3.Zero; + return Force; } /// @@ -2314,7 +2779,7 @@ namespace OpenSim.Region.Framework.Scenes detobj.velVector = obj.Velocity; detobj.colliderType = 0; detobj.groupUUID = obj.GroupID; - + detobj.linkNumber = LinkNum; return detobj; } @@ -2327,8 +2792,13 @@ namespace OpenSim.Region.Framework.Scenes detobj.posVector = av.AbsolutePosition; detobj.rotQuat = av.Rotation; detobj.velVector = av.Velocity; - detobj.colliderType = 0; + detobj.colliderType = av.IsNPC ? 0x20 : 0x1; // OpenSim\Region\ScriptEngine\Shared\Helpers.cs + if(av.IsSatOnObject) + detobj.colliderType |= 0x4; //passive + else if(detobj.velVector != Vector3.Zero) + detobj.colliderType |= 0x2; //active detobj.groupUUID = av.ControllingClient.ActiveGroupId; + detobj.linkNumber = LinkNum; return detobj; } @@ -2344,6 +2814,7 @@ namespace OpenSim.Region.Framework.Scenes detobj.velVector = Vector3.Zero; detobj.colliderType = 0; detobj.groupUUID = UUID.Zero; + detobj.linkNumber = LinkNum; // pass my link number not sure needed.. but no harm return detobj; } @@ -2352,12 +2823,13 @@ namespace OpenSim.Region.Framework.Scenes { ColliderArgs colliderArgs = new ColliderArgs(); List colliding = new List(); + Scene parentScene = ParentGroup.Scene; foreach (uint localId in colliders) { if (localId == 0) continue; - SceneObjectPart obj = ParentGroup.Scene.GetSceneObjectPart(localId); + SceneObjectPart obj = parentScene.GetSceneObjectPart(localId); if (obj != null) { if (!dest.CollisionFilteredOut(obj.UUID, obj.Name)) @@ -2365,7 +2837,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - ScenePresence av = ParentGroup.Scene.GetScenePresence(localId); + ScenePresence av = parentScene.GetScenePresence(localId); if (av != null && (!av.IsChildAgent)) { if (!dest.CollisionFilteredOut(av.UUID, av.Name)) @@ -2393,7 +2865,7 @@ namespace OpenSim.Region.Framework.Scenes CollidingMessage = CreateColliderArgs(this, colliders); if (CollidingMessage.Colliders.Count > 0) - DoNotify(notify, LocalId, CollidingMessage); + notify(LocalId, CollidingMessage); if (PassCollisions) sendToRoot = true; @@ -2407,109 +2879,205 @@ namespace OpenSim.Region.Framework.Scenes { CollidingMessage = CreateColliderArgs(ParentGroup.RootPart, colliders); if (CollidingMessage.Colliders.Count > 0) - DoNotify(notify, ParentGroup.RootPart.LocalId, CollidingMessage); + notify(ParentGroup.RootPart.LocalId, CollidingMessage); } } } private void SendLandCollisionEvent(scriptEvents ev, ScriptCollidingNotification notify) { - if ((ParentGroup.RootPart.ScriptEvents & ev) != 0) - { - ColliderArgs LandCollidingMessage = new ColliderArgs(); - List colliding = new List(); - - colliding.Add(CreateDetObjectForGround()); - LandCollidingMessage.Colliders = colliding; + bool sendToRoot = true; - DoNotify(notify, LocalId, LandCollidingMessage); - } - } + ColliderArgs LandCollidingMessage = new ColliderArgs(); + List colliding = new List(); - private void DoNotify(ScriptCollidingNotification notify, uint id, ColliderArgs collargs) - { - if (m_parentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.ShouldUseFireAndForgetForCollisions) - { - // For those learning C#, FireAndForget takes a function, an object to pass - // to that function and an ID string. The "oo => {}" construct is a lambda expression - // for a function with one arguement ('oo'). The 'new Object[] {}" construct creates an Object - // that is an object array and initializes it with three items (the parameters - // being passed). The parameters passed are the function to call ('notify') and - // its two arguements. Finally, once in the function (called later by the FireAndForget - // thread scheduler), the passed object is cast to an object array and then each - // of its items (aoo[0] to aoo[2]) are individually cast to what they are and - // then used in a call of the passed ScriptCollidingNotification function. - Util.FireAndForget(oo => - { - Object[] aoo = (Object[])oo; - ((ScriptCollidingNotification)aoo[0])((uint)aoo[1], (ColliderArgs)aoo[2]); + colliding.Add(CreateDetObjectForGround()); + LandCollidingMessage.Colliders = colliding; - }, new Object[] { notify, id, collargs }, "SOP.Collision"); + if (Inventory.ContainsScripts()) + { + if (!PassCollisions) + sendToRoot = false; } - else + if ((ScriptEvents & ev) != 0) + notify(LocalId, LandCollidingMessage); + + if ((ParentGroup.RootPart.ScriptEvents & ev) != 0 && sendToRoot) { - notify(id, collargs); + notify(ParentGroup.RootPart.LocalId, LandCollidingMessage); } } public void PhysicsCollision(EventArgs e) { - if (ParentGroup.Scene == null || ParentGroup.IsDeleted) + if (ParentGroup.Scene == null || ParentGroup.IsDeleted || ParentGroup.inTransit) return; - // single threaded here + // this a thread from physics ( heartbeat ) + bool thisHitLand = false; + bool startLand = false; + bool endedLand = false; + CollisionEventUpdate a = (CollisionEventUpdate)e; Dictionary collissionswith = a.m_objCollisionList; List thisHitColliders = new List(); List endedColliders = new List(); List startedColliders = new List(); - // calculate things that started colliding this time - // and build up list of colliders this time - foreach (uint localid in collissionswith.Keys) + if (collissionswith.Count == 0) { - thisHitColliders.Add(localid); - if (!m_lastColliders.Contains(localid)) - startedColliders.Add(localid); - } + if (m_lastColliders.Count == 0 && !m_lastLandCollide) + return; // nothing to do - // calculate things that ended colliding - foreach (uint localID in m_lastColliders) - { - if (!thisHitColliders.Contains(localID)) + endedLand = m_lastLandCollide; + m_lastLandCollide = false; + + foreach (uint localID in m_lastColliders) + { endedColliders.Add(localID); + } + + m_lastColliders.Clear(); } + else + { + List soundinfolist = new List(); - //add the items that started colliding this time to the last colliders list. - foreach (uint localID in startedColliders) - m_lastColliders.Add(localID); + // calculate things that started colliding this time + // and build up list of colliders this time + if (!VolumeDetectActive && CollisionSoundType >= 0) + { + CollisionForSoundInfo soundinfo; + ContactPoint curcontact; - // remove things that ended colliding from the last colliders list - foreach (uint localID in endedColliders) - m_lastColliders.Remove(localID); + foreach (uint id in collissionswith.Keys) + { + if(id == 0) + { + thisHitLand = true; + if (!m_lastLandCollide) + { + startLand = true; + curcontact = collissionswith[id]; + if (Math.Abs(curcontact.RelativeSpeed) > 0.2) + { + soundinfo = new CollisionForSoundInfo(); + soundinfo.colliderID = id; + soundinfo.position = curcontact.Position; + soundinfo.relativeVel = curcontact.RelativeSpeed; + soundinfolist.Add(soundinfo); + } + } + } + else + { + thisHitColliders.Add(id); + if (!m_lastColliders.Contains(id)) + { + startedColliders.Add(id); - // play the sound. - if (startedColliders.Count > 0 && CollisionSound != UUID.Zero && CollisionSoundVolume > 0.0f) - { - ISoundModule soundModule = ParentGroup.Scene.RequestModuleInterface(); - if (soundModule != null) + curcontact = collissionswith[id]; + if (Math.Abs(curcontact.RelativeSpeed) > 0.2) + { + soundinfo = new CollisionForSoundInfo(); + soundinfo.colliderID = id; + soundinfo.position = curcontact.Position; + soundinfo.relativeVel = curcontact.RelativeSpeed; + soundinfolist.Add(soundinfo); + } + } + } + } + } + else + { + foreach (uint id in collissionswith.Keys) + { + if(id == 0) + { + thisHitLand = true; + if (!m_lastLandCollide) + startLand = true; + } + else + { + thisHitColliders.Add(id); + if (!m_lastColliders.Contains(id)) + startedColliders.Add(id); + } + } + } + + // calculate things that ended colliding + foreach (uint localID in m_lastColliders) { - soundModule.SendSound(UUID, CollisionSound, - CollisionSoundVolume, true, 0, 0, false, - false); + if (!thisHitColliders.Contains(localID)) + endedColliders.Add(localID); } + + //add the items that started colliding this time to the last colliders list. + foreach (uint localID in startedColliders) + m_lastColliders.Add(localID); + + // remove things that ended colliding from the last colliders list + foreach (uint localID in endedColliders) + m_lastColliders.Remove(localID); + + if(m_lastLandCollide && !thisHitLand) + endedLand = true; + + m_lastLandCollide = thisHitLand; + + // play sounds. + if (soundinfolist.Count > 0) + CollisionSounds.PartCollisionSound(this, soundinfolist); + } + + EventManager eventmanager = ParentGroup.Scene.EventManager; + + SendCollisionEvent(scriptEvents.collision_start, startedColliders, eventmanager.TriggerScriptCollidingStart); + if (!VolumeDetectActive) + SendCollisionEvent(scriptEvents.collision , m_lastColliders , eventmanager.TriggerScriptColliding); + SendCollisionEvent(scriptEvents.collision_end , endedColliders , eventmanager.TriggerScriptCollidingEnd); + + if (!VolumeDetectActive) + { + if (startLand) + SendLandCollisionEvent(scriptEvents.land_collision_start, eventmanager.TriggerScriptLandCollidingStart); + if (m_lastLandCollide) + SendLandCollisionEvent(scriptEvents.land_collision, eventmanager.TriggerScriptLandColliding); + if (endedLand) + SendLandCollisionEvent(scriptEvents.land_collision_end, eventmanager.TriggerScriptLandCollidingEnd); } + } + + // The Collision sounds code calls this + public void SendCollisionSound(UUID soundID, double volume, Vector3 position) + { + if (soundID == UUID.Zero) + return; + + ISoundModule soundModule = ParentGroup.Scene.RequestModuleInterface(); + if (soundModule == null) + return; + + if (volume > 1) + volume = 1; + if (volume < 0) + volume = 0; - SendCollisionEvent(scriptEvents.collision_start, startedColliders, ParentGroup.Scene.EventManager.TriggerScriptCollidingStart); - SendCollisionEvent(scriptEvents.collision , m_lastColliders , ParentGroup.Scene.EventManager.TriggerScriptColliding); - SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd); + int now = Util.EnvironmentTickCount(); + if(Util.EnvironmentTickCountSubtract(now, LastColSoundSentTime) < 200) + return; + + LastColSoundSentTime = now; - if (startedColliders.Contains(0)) - SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart); - if (m_lastColliders.Contains(0)) - SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding); - if (endedColliders.Contains(0)) - SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd); + UUID ownerID = OwnerID; + UUID objectID = ParentGroup.RootPart.UUID; + UUID parentID = ParentGroup.UUID; + ulong regionHandle = ParentGroup.Scene.RegionInfo.RegionHandle; + + soundModule.TriggerSound(soundID, ownerID, objectID, parentID, volume, position, regionHandle, 0 ); } public void PhysicsOutOfBounds(Vector3 pos) @@ -2517,9 +3085,9 @@ namespace OpenSim.Region.Framework.Scenes // Note: This is only being called on the root prim at this time. m_log.ErrorFormat( - "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.", + "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.", Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition); - + RemFlag(PrimFlags.Physics); DoPhysicsPropertyUpdate(false, true); } @@ -2539,8 +3107,8 @@ namespace OpenSim.Region.Framework.Scenes } //ParentGroup.RootPart.m_groupPosition = newpos; } - - if (pa != null && ParentID != 0 && ParentGroup != null) +/* + if (pa != null && _parentID != 0 && ParentGroup != null) { // Special case where a child object is requesting property updates. // This happens when linksets are modified to use flexible links rather than @@ -2559,7 +3127,7 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("{0} PhysicsRequestingTerseUpdate child: pos={1}, rot={2}, offPos={3}, offRot={4}", // "[SCENE OBJECT PART]", pa.Position, pa.Orientation, m_offsetPosition, RotationOffset); } - +*/ ScheduleTerseUpdate(); } @@ -2574,7 +3142,7 @@ namespace OpenSim.Region.Framework.Scenes //m_log.Debug("prev: " + prevflag.ToString() + " curr: " + Flags.ToString()); //ScheduleFullUpdate(); } - + public void RemoveScriptEvents(UUID scriptid) { lock (m_scriptEvents) @@ -2619,18 +3187,17 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup.Scene != null) { - scale.X = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.X)); - scale.Y = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Y)); - scale.Z = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Z)); - + float minsize = ParentGroup.Scene.m_minNonphys; + float maxsize = ParentGroup.Scene.m_maxNonphys; if (pa != null && pa.IsPhysical) - { - scale.X = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.X)); - scale.Y = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Y)); - scale.Z = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Z)); - } + { + minsize = ParentGroup.Scene.m_minPhys; + maxsize = ParentGroup.Scene.m_maxPhys; + } + scale.X = Util.Clamp(scale.X, minsize, maxsize); + scale.Y = Util.Clamp(scale.Y, minsize, maxsize); + scale.Z = Util.Clamp(scale.Z, minsize, maxsize); } - // m_log.DebugFormat("[SCENE OBJECT PART]: Resizing {0} {1} to {2}", Name, LocalId, scale); Scale = scale; @@ -2638,58 +3205,68 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.HasGroupChanged = true; ScheduleFullUpdate(); } - + public void RotLookAt(Quaternion target, float strength, float damping) { - if (ParentGroup.IsAttachment) + if(ParentGroup.IsDeleted) + return; + + // for now we only handle physics case + if(!ParentGroup.UsesPhysics || ParentGroup.IsAttachment) + return; + + // physical is SOG + if(ParentGroup.RootPart != this) { - /* - ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar); - if (avatar != null) - { - Rotate the Av? - } */ + ParentGroup.RotLookAt(target, strength, damping); + return; } - else - { - APIDDamp = damping; - APIDStrength = strength; - APIDTarget = target; - if (APIDStrength <= 0) - { - m_log.WarnFormat("[SceneObjectPart] Invalid rotation strength {0}",APIDStrength); - return; - } - - APIDActive = true; + APIDDamp = damping; + APIDStrength = strength; + APIDTarget = target; + + if (APIDStrength <= 0) + { + m_log.WarnFormat("[SceneObjectPart] Invalid rotation strength {0}",APIDStrength); + return; } + APIDActive = true; + // Necessary to get the lookat deltas applied ParentGroup.QueueForUpdateCheck(); } public void StartLookAt(Quaternion target, float strength, float damping) { - RotLookAt(target,strength,damping); - } - - public void StopLookAt() - { - APIDActive = false; - } + if(ParentGroup.IsDeleted) + return; + // non physical is done on LSL + if(ParentGroup.IsAttachment || !ParentGroup.UsesPhysics) + return; + // physical is SOG + if(ParentGroup.RootPart != this) + ParentGroup.RotLookAt(target, strength, damping); + else + RotLookAt(target,strength,damping); + } - public void ScheduleFullUpdateIfNone() + public void StopLookAt() { - if (ParentGroup == null) + if(ParentGroup.IsDeleted) return; -// ??? ParentGroup.HasGroupChanged = true; + if(ParentGroup.RootPart != this && ParentGroup.UsesPhysics) + ParentGroup.StopLookAt(); - if (UpdateFlag != UpdateRequired.FULL) - ScheduleFullUpdate(); + // just in case do this always + if(APIDActive) + AngularVelocity = Vector3.Zero; + + APIDActive = false; } /// @@ -2701,41 +3278,44 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup == null) return; + if (ParentGroup.Scene == null) + return; - ParentGroup.QueueForUpdateCheck(); + if(ParentGroup.Scene.GetNumberOfClients() == 0) + return; - int timeNow = Util.UnixTimeSinceEpoch(); + ParentGroup.QueueForUpdateCheck(); // just in case - // If multiple updates are scheduled on the same second, we still need to perform all of them - // So we'll force the issue by bumping up the timestamp so that later processing sees these need - // to be performed. - if (timeNow <= TimeStampFull) - { - TimeStampFull += 1; - } - else + lock(UpdateFlagLock) { - TimeStampFull = (uint)timeNow; - } - - UpdateFlag = UpdateRequired.FULL; + if(UpdateFlag != UpdateRequired.FULL) + { + UpdateFlag = UpdateRequired.FULL; - // m_log.DebugFormat( - // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", - // UUID, Name, TimeStampFull); + // m_log.DebugFormat( + // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", + // UUID, Name, TimeStampFull); - if (ParentGroup.Scene != null) - ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, true); + } + } + ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, true); } /// /// Schedule a terse update for this prim. Terse updates only send position, - /// rotation, velocity and rotational velocity information. + /// rotation, velocity and rotational velocity information. WRONG!!!! /// public void ScheduleTerseUpdate() { if (ParentGroup == null) return; + if (ParentGroup.Scene == null) + return; + + ParentGroup.HasGroupChanged = true; + + if(ParentGroup.Scene.GetNumberOfClients() == 0) + return; // This was pulled from SceneViewer. Attachments always receive full updates. // This is needed because otherwise if only the root prim changes position, then @@ -2746,21 +3326,19 @@ namespace OpenSim.Region.Framework.Scenes return; } - if (UpdateFlag == UpdateRequired.NONE) + ParentGroup.QueueForUpdateCheck(); + lock(UpdateFlagLock) { - ParentGroup.HasGroupChanged = true; - ParentGroup.QueueForUpdateCheck(); - - TimeStampTerse = (uint) Util.UnixTimeSinceEpoch(); - UpdateFlag = UpdateRequired.TERSE; + if (UpdateFlag == UpdateRequired.NONE) + { + UpdateFlag = UpdateRequired.TERSE; - // m_log.DebugFormat( - // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}", - // UUID, Name, TimeStampTerse); + // m_log.DebugFormat( + // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1}", + // UUID, Name); + } } - - if (ParentGroup.Scene != null) - ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, false); + ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, false); } public void ScriptSetPhysicsStatus(bool UsePhysics) @@ -2769,39 +3347,6 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Set sculpt and mesh data, and tell the physics engine to process the change. - /// - /// The mesh itself. -/* - public void SculptTextureCallback(AssetBase texture) - { - if (m_shape.SculptEntry) - { - // commented out for sculpt map caching test - null could mean a cached sculpt map has been found - //if (texture != null) - { - if (texture != null) - { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Setting sculpt data for {0} on SculptTextureCallback()", Name); - - m_shape.SculptData = texture.Data; - } - - PhysicsActor pa = PhysActor; - - if (pa != null) - { - // Update the physics actor with the new loaded sculpt data and set the taint signal. - pa.Shape = m_shape; - - ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa); - } - } - } - } -*/ - /// /// Send a full update to the client for the given part /// /// @@ -2812,16 +3357,14 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SOG]: Sendinging part full update to {0} for {1} {2}", remoteClient.Name, part.Name, part.LocalId); - - if (IsRoot) + + + if (ParentGroup.IsAttachment) { - if (ParentGroup.IsAttachment) - { - SendFullUpdateToClient(remoteClient, AttachedPos); - } - else + ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar); + if (sp != null) { - SendFullUpdateToClient(remoteClient, AbsolutePosition); + sp.SendAttachmentUpdate(this, UpdateRequired.FULL); } } else @@ -2833,42 +3376,68 @@ namespace OpenSim.Region.Framework.Scenes /// /// Send a full update for this part to all clients. /// - public void SendFullUpdateToAllClients() + public void SendFullUpdateToAllClientsInternal() { if (ParentGroup == null) return; + // Update the "last" values + lock(UpdateFlagLock) + { + m_lastPosition = AbsolutePosition; + m_lastRotation = RotationOffset; + m_lastVelocity = Velocity; + m_lastAcceleration = Acceleration; + m_lastAngularVelocity = AngularVelocity; + m_lastUpdateSentTime = Util.GetTimeStampMS(); + } + ParentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) { SendFullUpdate(avatar.ControllingClient); }); } - /// - /// Sends a full update to the client - /// - /// - public void SendFullUpdateToClient(IClientAPI remoteClient) + public void SendFullUpdateToAllClients() { - SendFullUpdateToClient(remoteClient, OffsetPosition); + if (ParentGroup == null) + return; + + // Update the "last" values + lock(UpdateFlagLock) + { + m_lastPosition = AbsolutePosition; + m_lastRotation = RotationOffset; + m_lastVelocity = Velocity; + m_lastAcceleration = Acceleration; + m_lastAngularVelocity = AngularVelocity; + m_lastUpdateSentTime = Util.GetTimeStampMS(); + } + + if (ParentGroup.IsAttachment) + { + ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar); + if (sp != null) + { + sp.SendAttachmentUpdate(this, UpdateRequired.FULL); + } + } + else + { + ParentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) + { + SendFullUpdate(avatar.ControllingClient); + }); + } } /// /// Sends a full update to the client /// /// - /// - public void SendFullUpdateToClient(IClientAPI remoteClient, Vector3 lPos) + public void SendFullUpdateToClient(IClientAPI remoteClient) { - if (ParentGroup == null) - return; - - // Suppress full updates during attachment editing - // - if (ParentGroup.IsSelected && ParentGroup.IsAttachment) - return; - - if (ParentGroup.IsDeleted) + if (ParentGroup == null || ParentGroup.IsDeleted) return; if (ParentGroup.IsAttachment @@ -2889,62 +3458,212 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.Scene.StatsReporter.AddObjectUpdates(1); } + private const float ROTATION_TOLERANCE = 0.01f; + private const float VELOCITY_TOLERANCE = 0.1f; + private const float ANGVELOCITY_TOLERANCE = 0.005f; + private const float POSITION_TOLERANCE = 0.05f; // I don't like this, but I suppose it's necessary + private const double TIME_MS_TOLERANCE = 200.0; //llSetPos has a 200ms delay. This should NOT be 3 seconds. + /// /// Tell all the prims which have had updates scheduled /// - public void SendScheduledUpdates() - { - const float ROTATION_TOLERANCE = 0.01f; - const float VELOCITY_TOLERANCE = 0.001f; - const float POSITION_TOLERANCE = 0.05f; - const int TIME_MS_TOLERANCE = 3000; + public void SendScheduledUpdates(double now) + { + bool sendterse = false; + bool sendfull = false; - switch (UpdateFlag) + lock(UpdateFlagLock) { - case UpdateRequired.TERSE: + switch (UpdateFlag) { - ClearUpdateSchedule(); - // Throw away duplicate or insignificant updates - if (!RotationOffset.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) || - !Acceleration.Equals(m_lastAcceleration) || - !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) || - Velocity.ApproxEquals(Vector3.Zero, VELOCITY_TOLERANCE) || - !AngularVelocity.ApproxEquals(m_lastAngularVelocity, VELOCITY_TOLERANCE) || - !OffsetPosition.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || - Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE) - { - SendTerseUpdateToAllClients(); + case UpdateRequired.NONE: + break; + + case UpdateRequired.TERSE: + sendterse = true; + + Vector3 curvel = Velocity; + Vector3 curacc = Acceleration; + Vector3 angvel = AngularVelocity; + + while(true) // just to avoid ugly goto + { + double elapsed = now - m_lastUpdateSentTime; + if (elapsed > TIME_MS_TOLERANCE) + break; + + if( Math.Abs(curacc.X - m_lastAcceleration.X) > VELOCITY_TOLERANCE || + Math.Abs(curacc.Y - m_lastAcceleration.Y) > VELOCITY_TOLERANCE || + Math.Abs(curacc.Z - m_lastAcceleration.Z) > VELOCITY_TOLERANCE) + break; + + if( Math.Abs(curvel.X - m_lastVelocity.X) > VELOCITY_TOLERANCE || + Math.Abs(curvel.Y - m_lastVelocity.Y) > VELOCITY_TOLERANCE || + Math.Abs(curvel.Z - m_lastVelocity.Z) > VELOCITY_TOLERANCE) + break; + + float vx = Math.Abs(curvel.X); + if(vx > 128.0) + break; + float vy = Math.Abs(curvel.Y); + if(vy > 128.0) + break; + float vz = Math.Abs(curvel.Z); + if(vz > 128.0) + break; + + if ( + vx < VELOCITY_TOLERANCE && + vy < VELOCITY_TOLERANCE && + vz < VELOCITY_TOLERANCE + ) + { + if(!AbsolutePosition.ApproxEquals(m_lastPosition, POSITION_TOLERANCE)) + break; + + if (vx < 1e-4 && + vy < 1e-4 && + vz < 1e-4 && + ( + Math.Abs(m_lastVelocity.X) > 1e-4 || + Math.Abs(m_lastVelocity.Y) > 1e-4 || + Math.Abs(m_lastVelocity.Z) > 1e-4 + )) + break; + } + + if( Math.Abs(angvel.X - m_lastAngularVelocity.X) > ANGVELOCITY_TOLERANCE || + Math.Abs(angvel.Y - m_lastAngularVelocity.Y) > ANGVELOCITY_TOLERANCE || + Math.Abs(angvel.Z - m_lastAngularVelocity.Z) > ANGVELOCITY_TOLERANCE) + break; + + // viewer interpolators have a limit of 64rad/s + float ax = Math.Abs(angvel.X); + if(ax > 64.0) + break; + float ay = Math.Abs(angvel.Y); + if(ay > 64.0) + break; + float az = Math.Abs(angvel.Z); + if(az > 64.0) + break; + + if ( + ax < ANGVELOCITY_TOLERANCE && + ay < ANGVELOCITY_TOLERANCE && + az < ANGVELOCITY_TOLERANCE && + !RotationOffset.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) + ) + break; + + sendterse = false; + break; + } + + if(sendterse) + { + // Update the "last" values + m_lastPosition = AbsolutePosition; + m_lastRotation = RotationOffset; + m_lastVelocity = curvel; + m_lastAcceleration = curacc; + m_lastAngularVelocity = angvel; + m_lastUpdateSentTime = now; + ClearUpdateSchedule(); + } + break; - // Update the "last" values - m_lastPosition = OffsetPosition; + case UpdateRequired.FULL: + m_lastPosition = AbsolutePosition; m_lastRotation = RotationOffset; m_lastVelocity = Velocity; m_lastAcceleration = Acceleration; m_lastAngularVelocity = AngularVelocity; - m_lastTerseSent = Environment.TickCount; - } - break; + m_lastUpdateSentTime = now; + ClearUpdateSchedule(); + sendfull = true; + break; } - case UpdateRequired.FULL: + } + if(sendterse) + { + ParentGroup.Scene.ForEachClient(delegate(IClientAPI client) { - ClearUpdateSchedule(); - SendFullUpdateToAllClients(); - break; - } + SendTerseUpdateToClient(client); + }); + } + else if(sendfull) + { + ParentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) + { + SendFullUpdate(avatar.ControllingClient); + }); } } /// /// Send a terse update to all clients /// - public void SendTerseUpdateToAllClients() + public void SendTerseUpdateToAllClientsInternal() { + if (ParentGroup == null || ParentGroup.Scene == null) + return; + lock(UpdateFlagLock) + { + if(UpdateFlag != UpdateRequired.NONE) + return; + + // Update the "last" values + m_lastPosition = AbsolutePosition; + m_lastRotation = RotationOffset; + m_lastVelocity = Velocity; + m_lastAcceleration = Acceleration; + m_lastAngularVelocity = AngularVelocity; + m_lastUpdateSentTime = Util.GetTimeStampMS(); + } + ParentGroup.Scene.ForEachClient(delegate(IClientAPI client) { SendTerseUpdateToClient(client); }); } + public void SendTerseUpdateToAllClients() + { + if (ParentGroup == null || ParentGroup.Scene == null) + return; + + lock(UpdateFlagLock) + { + if(UpdateFlag != UpdateRequired.NONE) + return; + + // Update the "last" values + m_lastPosition = AbsolutePosition; + m_lastRotation = RotationOffset; + m_lastVelocity = Velocity; + m_lastAcceleration = Acceleration; + m_lastAngularVelocity = AngularVelocity; + m_lastUpdateSentTime = Util.GetTimeStampMS(); + } + + if (ParentGroup.IsAttachment) + { + ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar); + if (sp != null) + { + sp.SendAttachmentUpdate(this, UpdateRequired.TERSE); + } + } + else + { + ParentGroup.Scene.ForEachClient(delegate(IClientAPI client) + { + SendTerseUpdateToClient(client); + }); + } + } + public void SetAxisRotation(int axis, int rotate) { ParentGroup.SetAxisRotation(axis, rotate); @@ -2962,10 +3681,13 @@ namespace OpenSim.Region.Framework.Scenes public void SetBuoyancy(float fvalue) { - PhysicsActor pa = PhysActor; - - if (pa != null) - pa.Buoyancy = fvalue; + Buoyancy = fvalue; +/* + if (PhysActor != null) + { + PhysActor.Buoyancy = fvalue; + } + */ } public void SetDieAtEdge(bool p) @@ -2981,47 +3703,123 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor pa = PhysActor; if (pa != null) - pa.FloatOnWater = floatYN == 1; + pa.FloatOnWater = (floatYN == 1); } public void SetForce(Vector3 force) { - PhysicsActor pa = PhysActor; + Force = force; + } - if (pa != null) - pa.Force = force; + public PhysicsInertiaData PhysicsInertia + { + get + { + return m_physicsInertia; + } + set + { + m_physicsInertia = value; + } + } + + public SOPVehicle VehicleParams + { + get + { + return m_vehicleParams; + } + set + { + m_vehicleParams = value; + + } + } + + public int VehicleType + { + get + { + if (m_vehicleParams == null) + return (int)Vehicle.TYPE_NONE; + else + return (int)m_vehicleParams.Type; + } + set + { + SetVehicleType(value); + } } public void SetVehicleType(int type) { - PhysicsActor pa = PhysActor; + m_vehicleParams = null; - if (pa != null) - pa.VehicleType = type; + if (type == (int)Vehicle.TYPE_NONE) + { + if (_parentID ==0 && PhysActor != null) + PhysActor.VehicleType = (int)Vehicle.TYPE_NONE; + return; + } + m_vehicleParams = new SOPVehicle(); + m_vehicleParams.ProcessTypeChange((Vehicle)type); + { + if (_parentID ==0 && PhysActor != null) + PhysActor.VehicleType = type; + return; + } + } + + public void SetVehicleFlags(int param, bool remove) + { + if (m_vehicleParams == null) + return; + + m_vehicleParams.ProcessVehicleFlags(param, remove); + + if (_parentID == 0 && PhysActor != null) + { + PhysActor.VehicleFlags(param, remove); + } } public void SetVehicleFloatParam(int param, float value) { - PhysicsActor pa = PhysActor; + if (m_vehicleParams == null) + return; - if (pa != null) - pa.VehicleFloatParam(param, value); + m_vehicleParams.ProcessFloatVehicleParam((Vehicle)param, value); + + if (_parentID == 0 && PhysActor != null) + { + PhysActor.VehicleFloatParam(param, value); + } } public void SetVehicleVectorParam(int param, Vector3 value) { - PhysicsActor pa = PhysActor; + if (m_vehicleParams == null) + return; - if (pa != null) - pa.VehicleVectorParam(param, value); + m_vehicleParams.ProcessVectorVehicleParam((Vehicle)param, value); + + if (_parentID == 0 && PhysActor != null) + { + PhysActor.VehicleVectorParam(param, value); + } } public void SetVehicleRotationParam(int param, Quaternion rotation) { - PhysicsActor pa = PhysActor; + if (m_vehicleParams == null) + return; - if (pa != null) - pa.VehicleRotationParam(param, rotation); + m_vehicleParams.ProcessRotationVehicleParam((Vehicle)param, rotation); + + if (_parentID == 0 && PhysActor != null) + { + PhysActor.VehicleRotationParam(param, rotation); + } } /// @@ -3041,7 +3839,8 @@ namespace OpenSim.Region.Framework.Scenes Byte[] buf = Shape.Textures.GetBytes(); Primitive.TextureEntry tex = new Primitive.TextureEntry(buf, 0, buf.Length); Color4 texcolor; - if (face >= 0 && face < GetNumberOfSides()) + int nsides = GetNumberOfSides(); + if (face >= 0 && face < nsides) { texcolor = tex.CreateFace((uint)face).RGBA; texcolor.R = clippedColor.X; @@ -3057,7 +3856,7 @@ namespace OpenSim.Region.Framework.Scenes } else if (face == ALL_SIDES) { - for (uint i = 0; i < GetNumberOfSides(); i++) + for (uint i = 0; i < nsides; i++) { if (tex.FaceTextures[i] != null) { @@ -3093,64 +3892,110 @@ namespace OpenSim.Region.Framework.Scenes public int GetNumberOfSides() { int ret = 0; - bool hasCut; - bool hasHollow; - bool hasDimple; - bool hasProfileCut; - PrimType primType = GetPrimType(); - HasCutHollowDimpleProfileCut(primType, Shape, out hasCut, out hasHollow, out hasDimple, out hasProfileCut); + if(Shape.SculptEntry) + { + if (Shape.SculptType != (byte)SculptType.Mesh) + return 1; // sculp + + //hack to detect new upload with faces data enconded on pbs + if ((Shape.ProfileCurve & 0xf0) != (byte)HollowShape.Triangle) + // old broken upload TODO + return 8; + } + + PrimType primType = GetPrimType(true); switch (primType) { case PrimType.BOX: ret = 6; - if (hasCut) ret += 2; - if (hasHollow) ret += 1; - break; - case PrimType.CYLINDER: - ret = 3; - if (hasCut) ret += 2; - if (hasHollow) ret += 1; + if (Shape.ProfileBegin > 0 || Shape.ProfileEnd > 0) // cut case + { + // removed sides + int cut = (Shape.ProfileEnd + Shape.ProfileBegin); + if(cut > 50000) // range is 0 to 50000 + cut = 50000; + cut /= 12500; // ie 1/4 + ret -= cut; + ret += 2; // both cut faces + } break; case PrimType.PRISM: ret = 5; - if (hasCut) ret += 2; - if (hasHollow) ret += 1; + if (Shape.ProfileBegin > 0 || Shape.ProfileEnd > 0) // cut case + { + // removed faces + int cut = (Shape.ProfileEnd + Shape.ProfileBegin); + if(cut >= 16667 ) // ie 1/3 + ret--; + if(cut >= 33333 ) // ie 2/3 + ret--; + ret += 2; // both cut faces + } + break; + case PrimType.CYLINDER: + ret = 3; + if (Shape.ProfileBegin > 0 || Shape.ProfileEnd > 0) // cut + ret += 2; break; case PrimType.SPHERE: ret = 1; - if (hasCut) ret += 2; - if (hasDimple) ret += 2; - if (hasHollow) ret += 1; + // cut faces exist if cut or skew or unequal twist limits + if (Shape.PathBegin > 0 || Shape.PathEnd > 0 || Shape.PathSkew != 0 || (Shape.PathTwistBegin != Shape.PathTwist)) + ret += 2; + if (Shape.ProfileBegin > 0 || Shape.ProfileEnd > 0 || Shape.ProfileHollow > 0) // dimple faces also if hollow + ret += 2; break; case PrimType.TORUS: ret = 1; - if (hasCut) ret += 2; - if (hasProfileCut) ret += 2; - if (hasHollow) ret += 1; + if (Shape.PathBegin > 0 || Shape.PathEnd > 0 || Shape.PathSkew != 0 + || Shape.PathTaperX != 0 || Shape.PathTaperY != 0 || Shape.PathRevolutions > 0 + || Shape.PathRadiusOffset != 0 || (Shape.PathTwistBegin != Shape.PathTwist)) + ret += 2; + if (Shape.ProfileBegin > 0 || Shape.ProfileEnd > 0) // profile cut + ret += 2; break; case PrimType.TUBE: ret = 4; - if (hasCut) ret += 2; - if (hasProfileCut) ret += 2; - if (hasHollow) ret += 1; + if (Shape.PathBegin > 0 || Shape.PathEnd > 0 || Shape.PathSkew != 0 + || Shape.PathTaperX != 0 || Shape.PathTaperY != 0 || Shape.PathRevolutions > 0 + || Shape.PathRadiusOffset != 0 || (Shape.PathTwistBegin != Shape.PathTwist)) + ret += 2; + if (Shape.ProfileBegin > 0 || Shape.ProfileEnd > 0) // profile cut + { + // removed sides + int cut = (Shape.ProfileEnd + Shape.ProfileBegin); + if(cut > 50000) + cut = 50000; + cut /= 12500; + ret -= cut; + ret += 2; // both cut faces + } break; case PrimType.RING: ret = 3; - if (hasCut) ret += 2; - if (hasProfileCut) ret += 2; - if (hasHollow) ret += 1; - break; - case PrimType.SCULPT: - // Special mesh handling - if (Shape.SculptType == (byte)SculptType.Mesh) - ret = 8; // if it's a mesh then max 8 faces - else - ret = 1; // if it's a sculpt then max 1 face + if (Shape.PathBegin > 0 || Shape.PathEnd > 0 || Shape.PathSkew != 0 + || Shape.PathTaperX != 0 || Shape.PathTaperY != 0 || Shape.PathRevolutions > 0 + || Shape.PathRadiusOffset != 0 || (Shape.PathTwistBegin != Shape.PathTwist)) + ret += 2; + if (Shape.ProfileBegin > 0 || Shape.ProfileEnd > 0) // profile cut + { + // removed faces + int cut = (Shape.ProfileEnd + Shape.ProfileBegin); + if(cut >= 16667 ) + ret--; + if(cut >= 33333 ) + ret--; + ret += 2; // both cut faces + } break; } + // hollow face commum to all + if (Shape.ProfileHollow > 0) + ret += 1; + return ret; } @@ -3159,11 +4004,11 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public PrimType GetPrimType() + public PrimType GetPrimType(bool ignoreSculpt = false) { - if (Shape.SculptEntry) + if (Shape.SculptEntry && !ignoreSculpt) return PrimType.SCULPT; - + if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.Square) { if (Shape.PathCurve == (byte)Extrusion.Straight) @@ -3173,7 +4018,7 @@ namespace OpenSim.Region.Framework.Scenes } else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) { - if (Shape.PathCurve == (byte)Extrusion.Straight) + if (Shape.PathCurve == (byte)Extrusion.Straight || Shape.PathCurve == (byte)Extrusion.Flexible) return PrimType.CYLINDER; // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits else if (Shape.PathCurve == (byte)Extrusion.Curve1) @@ -3186,48 +4031,13 @@ namespace OpenSim.Region.Framework.Scenes } else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) { - if (Shape.PathCurve == (byte)Extrusion.Straight) + if (Shape.PathCurve == (byte)Extrusion.Straight || Shape.PathCurve == (byte)Extrusion.Flexible) return PrimType.PRISM; else if (Shape.PathCurve == (byte)Extrusion.Curve1) return PrimType.RING; } - - return PrimType.BOX; - } - - /// - /// Tell us if this object has cut, hollow, dimple, and other factors affecting the number of faces - /// - /// - /// - /// - /// - /// - /// - protected static void HasCutHollowDimpleProfileCut(PrimType primType, PrimitiveBaseShape shape, out bool hasCut, out bool hasHollow, - out bool hasDimple, out bool hasProfileCut) - { - if (primType == PrimType.BOX - || - primType == PrimType.CYLINDER - || - primType == PrimType.PRISM) - - hasCut = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); - else - hasCut = (shape.PathBegin > 0) || (shape.PathEnd > 0); - - hasHollow = shape.ProfileHollow > 0; - hasDimple = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); // taken from llSetPrimitiveParms - hasProfileCut = hasDimple; // is it the same thing? - } - - public void SetVehicleFlags(int param, bool remove) - { - PhysicsActor pa = PhysActor; - if (pa != null) - pa.VehicleFlags(param, remove); + return PrimType.BOX; } public void SetGroup(UUID groupID, IClientAPI client) @@ -3238,8 +4048,8 @@ namespace OpenSim.Region.Framework.Scenes // Name, groupID, OwnerID); GroupID = groupID; - if (client != null) - SendPropertiesToClient(client); +// if (client != null) +// SendPropertiesToClient(client); UpdateFlag = UpdateRequired.FULL; } @@ -3263,7 +4073,7 @@ namespace OpenSim.Region.Framework.Scenes if (pa != null) { - pa.LockAngularMotion(RotationAxis); + pa.LockAngularMotion(RotationAxisLocks); ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa); } } @@ -3276,7 +4086,7 @@ namespace OpenSim.Region.Framework.Scenes public void SetScriptEvents(UUID scriptid, int events) { // m_log.DebugFormat( -// "[SCENE OBJECT PART]: Set script events for script with id {0} on {1}/{2} to {3} in {4}", +// "[SCENE OBJECT PART]: Set script events for script with id {0} on {1}/{2} to {3} in {4}", // scriptid, Name, ParentGroup.Name, events, ParentGroup.Scene.Name); // scriptEvents oldparts; @@ -3313,7 +4123,7 @@ namespace OpenSim.Region.Framework.Scenes ScheduleFullUpdate(); } } - + /// /// Set the text displayed for this part. /// @@ -3334,67 +4144,16 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.StopMoveToTarget(); } - public void StoreUndoState() - { - StoreUndoState(false); - } - - public void StoreUndoState(bool forGroup) + public void StoreUndoState(ObjectChangeType change) { - if (ParentGroup == null || ParentGroup.Scene == null) - return; - - if (Undoing) - { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId); - return; - } - - if (IgnoreUndoUpdate) + lock (m_UndoLock) { -// m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId); - return; - } - - lock (m_undo) - { - if (m_undo.Count > 0) - { - UndoState last = m_undo[m_undo.Count - 1]; - if (last != null) - { - // TODO: May need to fix for group comparison - if (last.Compare(this)) - { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}", -// Name, LocalId, m_undo.Count); - - return; - } - } - } - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Storing undo state for {0} {1}, forGroup {2}, initial stack size {3}", -// Name, LocalId, forGroup, m_undo.Count); + if (m_UndoRedo == null) + m_UndoRedo = new UndoRedoState(5); - if (ParentGroup.Scene.MaxUndoCount > 0) + if (!Undoing && !IgnoreUndoUpdate && ParentGroup != null) // just to read better - undo is in progress, or suspended { - UndoState nUndo = new UndoState(this, forGroup); - - m_undo.Add(nUndo); - - if (m_undo.Count > ParentGroup.Scene.MaxUndoCount) - m_undo.RemoveAt(0); - - if (m_redo.Count > 0) - m_redo.Clear(); - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}", -// Name, LocalId, forGroup, m_undo.Count); + m_UndoRedo.StoreUndo(this, change); } } } @@ -3406,186 +4165,47 @@ namespace OpenSim.Region.Framework.Scenes { get { - lock (m_undo) - return m_undo.Count; + if (m_UndoRedo == null) + return 0; + return m_UndoRedo.Count; } } public void Undo() { - lock (m_undo) - { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handling undo request for {0} {1}, stack size {2}", -// Name, LocalId, m_undo.Count); - - if (m_undo.Count > 0) - { - UndoState goback = m_undo[m_undo.Count - 1]; - m_undo.RemoveAt(m_undo.Count - 1); - - UndoState nUndo = null; - - if (ParentGroup.Scene.MaxUndoCount > 0) - { - nUndo = new UndoState(this, goback.ForGroup); - } - - goback.PlaybackState(this); - - if (nUndo != null) - { - m_redo.Add(nUndo); - - if (m_redo.Count > ParentGroup.Scene.MaxUndoCount) - m_redo.RemoveAt(0); - } - } - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handled undo request for {0} {1}, stack size now {2}", -// Name, LocalId, m_undo.Count); - } - } - - public void Redo() - { - lock (m_undo) - { -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handling redo request for {0} {1}, stack size {2}", -// Name, LocalId, m_redo.Count); - - if (m_redo.Count > 0) - { - UndoState gofwd = m_redo[m_redo.Count - 1]; - m_redo.RemoveAt(m_redo.Count - 1); - - if (ParentGroup.Scene.MaxUndoCount > 0) - { - UndoState nUndo = new UndoState(this, gofwd.ForGroup); - - m_undo.Add(nUndo); - - if (m_undo.Count > ParentGroup.Scene.MaxUndoCount) - m_undo.RemoveAt(0); - } - - gofwd.PlayfwdState(this); - -// m_log.DebugFormat( -// "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}", -// Name, LocalId, m_redo.Count); - } - } - } - - public void ClearUndoState() - { -// m_log.DebugFormat("[SCENE OBJECT PART]: Clearing undo and redo stacks in {0} {1}", Name, LocalId); - - lock (m_undo) + lock (m_UndoLock) { - m_undo.Clear(); - m_redo.Clear(); + if (m_UndoRedo == null || Undoing || ParentGroup == null) + return; + + Undoing = true; + m_UndoRedo.Undo(this); + Undoing = false; } } - public EntityIntersection TestIntersection(Ray iray, Quaternion parentrot) + public void Redo() { - // In this case we're using a sphere with a radius of the largest dimension of the prim - // TODO: Change to take shape into account - - EntityIntersection result = new EntityIntersection(); - Vector3 vAbsolutePosition = AbsolutePosition; - Vector3 vScale = Scale; - Vector3 rOrigin = iray.Origin; - Vector3 rDirection = iray.Direction; - - //rDirection = rDirection.Normalize(); - // Buidling the first part of the Quadratic equation - Vector3 r2ndDirection = rDirection*rDirection; - float itestPart1 = r2ndDirection.X + r2ndDirection.Y + r2ndDirection.Z; - - // Buidling the second part of the Quadratic equation - Vector3 tmVal2 = rOrigin - vAbsolutePosition; - Vector3 r2Direction = rDirection*2.0f; - Vector3 tmVal3 = r2Direction*tmVal2; - - float itestPart2 = tmVal3.X + tmVal3.Y + tmVal3.Z; - - // Buidling the third part of the Quadratic equation - Vector3 tmVal4 = rOrigin*rOrigin; - Vector3 tmVal5 = vAbsolutePosition*vAbsolutePosition; - - Vector3 tmVal6 = vAbsolutePosition*rOrigin; - - // Set Radius to the largest dimension of the prim - float radius = 0f; - if (vScale.X > radius) - radius = vScale.X; - if (vScale.Y > radius) - radius = vScale.Y; - if (vScale.Z > radius) - radius = vScale.Z; - - // the second part of this is the default prim size - // once we factor in the aabb of the prim we're adding we can - // change this to; - // radius = (radius / 2) - 0.01f; - // - radius = (radius / 2) + (0.5f / 2) - 0.1f; - - //radius = radius; - - float itestPart3 = tmVal4.X + tmVal4.Y + tmVal4.Z + tmVal5.X + tmVal5.Y + tmVal5.Z - - (2.0f*(tmVal6.X + tmVal6.Y + tmVal6.Z + (radius*radius))); - - // Yuk Quadradrics.. Solve first - float rootsqr = (itestPart2*itestPart2) - (4.0f*itestPart1*itestPart3); - if (rootsqr < 0.0f) + lock (m_UndoLock) { - // No intersection - return result; + if (m_UndoRedo == null || Undoing || ParentGroup == null) + return; + + Undoing = true; + m_UndoRedo.Redo(this); + Undoing = false; } - float root = ((-itestPart2) - (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f); + } - if (root < 0.0f) + public void ClearUndoState() + { + lock (m_UndoLock) { - // perform second quadratic root solution - root = ((-itestPart2) + (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f); + if (m_UndoRedo == null || Undoing) + return; - // is there any intersection? - if (root < 0.0f) - { - // nope, no intersection - return result; - } + m_UndoRedo.Clear(); } - - // We got an intersection. putting together an EntityIntersection object with the - // intersection information - Vector3 ipoint = - new Vector3(iray.Origin.X + (iray.Direction.X*root), iray.Origin.Y + (iray.Direction.Y*root), - iray.Origin.Z + (iray.Direction.Z*root)); - - result.HitTF = true; - result.ipoint = ipoint; - - // Normal is calculated by the difference and then normalizing the result - Vector3 normalpart = ipoint - vAbsolutePosition; - result.normal = normalpart / normalpart.Length(); - - // It's funny how the Vector3 object has a Distance function, but the Axiom.Math object doesn't. - // I can write a function to do it.. but I like the fact that this one is Static. - - Vector3 distanceConvert1 = new Vector3(iray.Origin.X, iray.Origin.Y, iray.Origin.Z); - Vector3 distanceConvert2 = new Vector3(ipoint.X, ipoint.Y, ipoint.Z); - float distance = (float) Util.GetDistanceTo(distanceConvert1, distanceConvert2); - - result.distance = distance; - - return result; } public EntityIntersection TestIntersectionOBB(Ray iray, Quaternion parentrot, bool frontFacesOnly, bool faceCenters) @@ -3955,15 +4575,7 @@ namespace OpenSim.Region.Framework.Scenes public void UpdateExtraParam(ushort type, bool inUse, byte[] data) { m_shape.ReadInUpdateExtraParam(type, inUse, data); -/* - if (type == 0x30) - { - if (m_shape.SculptEntry && m_shape.SculptTexture != UUID.Zero) - { - ParentGroup.Scene.AssetService.Get(m_shape.SculptTexture.ToString(), this, AssetReceived); - } - } -*/ + if (ParentGroup != null) { ParentGroup.HasGroupChanged = true; @@ -4030,8 +4642,11 @@ namespace OpenSim.Region.Framework.Scenes if (god) baseMask = 0x7ffffff0; - // Are we the owner? - if ((AgentID == OwnerID) || god) + bool canChange = (AgentID == OwnerID) || god; + if(!canChange) + canChange = ParentGroup.Scene.Permissions.CanEditObjectPermissions(ParentGroup, AgentID); + + if (canChange) { switch (field) { @@ -4039,7 +4654,7 @@ namespace OpenSim.Region.Framework.Scenes if (god) { BaseMask = ApplyMask(BaseMask, set, mask); - Inventory.ApplyGodPermissions(_baseMask); + Inventory.ApplyGodPermissions(BaseMask); } break; @@ -4070,7 +4685,7 @@ namespace OpenSim.Region.Framework.Scenes } NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) & baseMask; - // Prevent the client from creating no mod, no copy + // Prevent the client from creating no copy, no transfer // objects if ((NextOwnerMask & (uint)PermissionMask.Copy) == 0) NextOwnerMask |= (uint)PermissionMask.Transfer; @@ -4079,36 +4694,36 @@ namespace OpenSim.Region.Framework.Scenes break; } - + AggregateInnerPerms(); SendFullUpdateToAllClients(); } } public void ClonePermissions(SceneObjectPart source) { - bool update = false; + uint prevOwnerMask = OwnerMask; + uint prevGroupMask = GroupMask; + uint prevEveryoneMask = EveryoneMask; + uint prevNextOwnerMask = NextOwnerMask; - if (BaseMask != source.BaseMask || - OwnerMask != source.OwnerMask || - GroupMask != source.GroupMask || - EveryoneMask != source.EveryoneMask || - NextOwnerMask != source.NextOwnerMask) - update = true; + OwnerMask = source.OwnerMask & BaseMask; + GroupMask = source.GroupMask & BaseMask; + EveryoneMask = source.EveryoneMask & BaseMask; + NextOwnerMask = source.NextOwnerMask & BaseMask; - BaseMask = source.BaseMask; - OwnerMask = source.OwnerMask; - GroupMask = source.GroupMask; - EveryoneMask = source.EveryoneMask; - NextOwnerMask = source.NextOwnerMask; + AggregateInnerPerms(); - if (update) + if (OwnerMask != prevOwnerMask || + GroupMask != prevGroupMask || + EveryoneMask != prevEveryoneMask || + NextOwnerMask != prevNextOwnerMask) SendFullUpdateToAllClients(); } public bool IsHingeJoint() { // For now, we use the NINJA naming scheme for identifying joints. - // In the future, we can support other joint specification schemes such as a + // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { @@ -4124,7 +4739,7 @@ namespace OpenSim.Region.Framework.Scenes public bool IsBallJoint() { // For now, we use the NINJA naming scheme for identifying joints. - // In the future, we can support other joint specification schemes such as a + // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { @@ -4140,7 +4755,7 @@ namespace OpenSim.Region.Framework.Scenes public bool IsJoint() { // For now, we use the NINJA naming scheme for identifying joints. - // In the future, we can support other joint specification schemes such as a + // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { @@ -4157,18 +4772,19 @@ namespace OpenSim.Region.Framework.Scenes if (physdata.PhysShapeType == PhysShapeType.invalid || ParentGroup == null) return; - if (PhysicsShapeType != (byte)physdata.PhysShapeType) - { - PhysicsShapeType = (byte)physdata.PhysShapeType; - - } + byte newtype = (byte)physdata.PhysShapeType; + if (PhysicsShapeType != newtype) + PhysicsShapeType = newtype; if(Density != physdata.Density) Density = physdata.Density; + if(GravityModifier != physdata.GravitationModifier) GravityModifier = physdata.GravitationModifier; + if(Friction != physdata.Friction) Friction = physdata.Friction; + if(Restitution != physdata.Bounce) Restitution = physdata.Bounce; } @@ -4179,7 +4795,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public void UpdatePrimFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVD) + public void UpdatePrimFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVD, bool building) { bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0); bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0); @@ -4189,134 +4805,85 @@ namespace OpenSim.Region.Framework.Scenes if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD)) return; - PhysicsActor pa = PhysActor; - - // Special cases for VD. VD can only be called from a script - // and can't be combined with changes to other states. So we can rely - // that... - // ... if VD is changed, all others are not. - // ... if one of the others is changed, VD is not. - if (SetVD) // VD is active, special logic applies - { - // State machine logic for VolumeDetect - // More logic below - bool phanReset = (SetPhantom != wasPhantom) && !SetPhantom; - - if (phanReset) // Phantom changes from on to off switch VD off too - { - SetVD = false; // Switch it of for the course of this routine - VolumeDetectActive = false; // and also permanently - - if (pa != null) - pa.SetVolumeDetect(0); // Let physics know about it too - } - else - { - // If volumedetect is active we don't want phantom to be applied. - // If this is a new call to VD out of the state "phantom" - // this will also cause the prim to be visible to physics - SetPhantom = false; - } - } + VolumeDetectActive = SetVD; - if (UsePhysics && IsJoint()) - { + // volume detector implies phantom we need to decouple this mess + if (SetVD) SetPhantom = true; - } + else if(wasVD) + SetPhantom = false; if (UsePhysics) - { AddFlag(PrimFlags.Physics); - if (!wasUsingPhysics) - { - DoPhysicsPropertyUpdate(UsePhysics, false); - } - } else - { RemFlag(PrimFlags.Physics); - if (wasUsingPhysics) - { - DoPhysicsPropertyUpdate(UsePhysics, false); - } - } - if (SetPhantom - || ParentGroup.IsAttachmentCheckFull() - || PhysicsShapeType == (byte)PhysShapeType.none - || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints - { + if (SetPhantom) AddFlag(PrimFlags.Phantom); - - if (PhysActor != null) - { - RemoveFromPhysics(); - pa = null; - } - } - else // Not phantom - { + else RemFlag(PrimFlags.Phantom); - if (ParentGroup.Scene == null) - return; + if (SetTemporary) + AddFlag(PrimFlags.TemporaryOnRez); + else + RemFlag(PrimFlags.TemporaryOnRez); - if (ParentGroup.Scene.CollidablePrims && pa == null) - { - AddToPhysics(UsePhysics, SetPhantom, false); - pa = PhysActor; + if (ParentGroup.Scene == null) + return; - if (pa != null) - { - pa.SetMaterial(Material); - pa.Position = GetWorldPosition(); - pa.Orientation = GetWorldRotation(); - DoPhysicsPropertyUpdate(UsePhysics, true); + PhysicsActor pa = PhysActor; - SubscribeForCollisionEvents(); - } - } - else // it already has a physical representation - { - DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim - } - } + if (pa != null && building && pa.Building != building) + pa.Building = building; - if (SetVD) + if ((SetPhantom && !UsePhysics && !SetVD) || ParentGroup.IsAttachment || PhysicsShapeType == (byte)PhysShapeType.none + || (Shape.PathCurve == (byte)Extrusion.Flexible)) { - // If the above logic worked (this is urgent candidate to unit tests!) - // we now have a physicsactor. - // Defensive programming calls for a check here. - // Better would be throwing an exception that could be catched by a unit test as the internal - // logic should make sure, this Physactor is always here. if (pa != null) { - pa.SetVolumeDetect(1); - AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active - VolumeDetectActive = true; + if(wasUsingPhysics) + ParentGroup.Scene.RemovePhysicalPrim(1); + RemoveFromPhysics(); } - } - else if (SetVD != wasVD) - { - // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like - // (mumbles, well, at least if you have infinte CPU powers :-)) - if (pa != null) - pa.SetVolumeDetect(0); - RemFlag(PrimFlags.Phantom); - VolumeDetectActive = false; + Stop(); } - if (SetTemporary) - { - AddFlag(PrimFlags.TemporaryOnRez); - } else { - RemFlag(PrimFlags.TemporaryOnRez); + if (ParentGroup.Scene.CollidablePrims) + { + if (pa == null) + { + AddToPhysics(UsePhysics, SetPhantom, building, false); + pa = PhysActor; + + if (pa != null) + { + pa.SetMaterial(Material); + DoPhysicsPropertyUpdate(UsePhysics, true); + } + } + else // it already has a physical representation + { + + DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. + + if(UsePhysics && !SetPhantom && m_localId == ParentGroup.RootPart.LocalId && + m_vehicleParams != null && m_vehicleParams.CameraDecoupled) + AddFlag(PrimFlags.CameraDecoupled); + else + RemFlag(PrimFlags.CameraDecoupled); + + if (pa.Building != building) + pa.Building = building; + } + + UpdatePhysicsSubscribedEvents(); + } } - // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); + // and last in case we have a new actor and not building if (ParentGroup != null) { @@ -4328,58 +4895,14 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Subscribe for physics collision events if needed for scripts and sounds - /// - public void SubscribeForCollisionEvents() - { - PhysicsActor pa = PhysActor; - - if (pa != null) - { - if ( - ((AggregateScriptEvents & scriptEvents.collision) != 0) || - ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || - ((AggregateScriptEvents & scriptEvents.collision_start) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || - (CollisionSound != UUID.Zero) - ) - { - if (!pa.SubscribedEvents()) - { - // If not already subscribed for event, set up for a collision event. - pa.OnCollisionUpdate += PhysicsCollision; - pa.SubscribeEvents(1000); - } - } - else - { - // There is no need to be subscribed to collisions so, if subscribed, remove subscription - if (pa.SubscribedEvents()) - { - pa.OnCollisionUpdate -= PhysicsCollision; - pa.UnSubscribeEvents(); - } - } - } - } - - /// /// Adds this part to the physics scene. + /// and sets the PhysActor property /// - /// This method also sets the PhysActor property. - /// Add this prim with a rigid body. - /// - /// The physics actor. null if there was a failure. - /// - private void AddToPhysics(bool isPhysical, bool isPhantom, bool applyDynamics) + /// Add this prim as physical. + /// Add this prim as phantom. + /// tells physics to delay full construction of object + /// applies velocities, force and torque + private void AddToPhysics(bool isPhysical, bool isPhantom, bool building, bool applyDynamics) { PhysicsActor pa; @@ -4389,15 +4912,15 @@ namespace OpenSim.Region.Framework.Scenes try { pa = ParentGroup.Scene.PhysicsScene.AddPrimShape( - string.Format("{0}/{1}", Name, UUID), - Shape, - AbsolutePosition, - Scale, - GetWorldRotation(), - isPhysical, - isPhantom, - PhysicsShapeType, - m_localId); + string.Format("{0}/{1}", Name, UUID), + Shape, + AbsolutePosition, + Scale, + GetWorldRotation(), + isPhysical, + isPhantom, + PhysicsShapeType, + m_localId); } catch (Exception e) { @@ -4414,12 +4937,37 @@ namespace OpenSim.Region.Framework.Scenes pa.GravModifier = GravityModifier; pa.Friction = Friction; pa.Restitution = Restitution; + pa.Buoyancy = Buoyancy; + + if(LocalId == ParentGroup.RootPart.LocalId) + { + pa.LockAngularMotion(RotationAxisLocks); + } if (VolumeDetectActive) // change if not the default only pa.SetVolumeDetect(1); + + bool isroot = (m_localId == ParentGroup.RootPart.LocalId); + + if(isroot && m_physicsInertia != null) + pa.SetInertiaData(m_physicsInertia); + + if (isroot && m_vehicleParams != null ) + { + m_vehicleParams.SetVehicle(pa); + if(isPhysical && !isPhantom && m_vehicleParams.CameraDecoupled) + AddFlag(PrimFlags.CameraDecoupled); + else + RemFlag(PrimFlags.CameraDecoupled); + } + else + RemFlag(PrimFlags.CameraDecoupled); // we are going to tell rest of code about physics so better have this here PhysActor = pa; + // DoPhysicsPropertyUpdate(isPhysical, true); + // lets expand it here just with what it really needs to do + if (isPhysical) { if (ParentGroup.RootPart.KeyframeMotion != null) @@ -4430,7 +4978,7 @@ namespace OpenSim.Region.Framework.Scenes pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; pa.OnOutOfBounds += PhysicsOutOfBounds; - if (ParentID != 0 && ParentID != LocalId) + if (_parentID != 0 && _parentID != LocalId) { PhysicsActor parentPa = ParentGroup.RootPart.PhysActor; @@ -4441,19 +4989,31 @@ namespace OpenSim.Region.Framework.Scenes } } - if (applyDynamics) - // do independent of isphysical so parameters get setted (at least some) + if (applyDynamics && LocalId == ParentGroup.RootPart.LocalId) + // do independent of isphysical so parameters get setted (at least some) { Velocity = velocity; AngularVelocity = rotationalVelocity; -// pa.Velocity = velocity; - pa.RotationalVelocity = rotationalVelocity; + + // if not vehicle and root part apply force and torque + if ((m_vehicleParams == null || m_vehicleParams.Type == Vehicle.TYPE_NONE)) + { + pa.Force = Force; + pa.Torque = Torque; + } } - ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa); +// if (Shape.SculptEntry) +// CheckSculptAndLoad(); +// else + ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa); + + if (!building) + pa.Building = false; } PhysActor = pa; + ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this); } @@ -4462,14 +5022,22 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// This isn't the same as turning off physical, since even without being physical the prim has a physics - /// representation for collision detection. Rather, this would be used in situations such as making a prim - /// phantom. + /// representation for collision detection. /// public void RemoveFromPhysics() { - ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this); - if (ParentGroup.Scene.PhysicsScene != null) - ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); + PhysicsActor pa = PhysActor; + if (pa != null) + { + pa.OnCollisionUpdate -= PhysicsCollision; + pa.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate; + pa.OnOutOfBounds -= PhysicsOutOfBounds; + + ParentGroup.Scene.PhysicsScene.RemovePrim(pa); + + ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this); + } + RemFlag(PrimFlags.CameraDecoupled); PhysActor = null; } @@ -4590,40 +5158,6 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// If the part is a sculpt/mesh, retrieve the mesh data and reinsert it into the shape so that the physics - /// engine can use it. - /// - /// - /// When the physics engine has finished with it, the sculpt data is discarded to save memory. - /// -/* - public void CheckSculptAndLoad() - { -// m_log.DebugFormat("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); - - if (ParentGroup.IsDeleted) - return; - - if ((ParentGroup.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) - return; - - if (Shape.SculptEntry && Shape.SculptTexture != UUID.Zero) - { - // check if a previously decoded sculpt map has been cached - // We don't read the file here - the meshmerizer will do that later. - // TODO: Could we simplify the meshmerizer code by reading and setting the data here? - if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + Shape.SculptTexture.ToString()))) - { - SculptTextureCallback(null); - } - else - { - ParentGroup.Scene.AssetService.Get(Shape.SculptTexture.ToString(), this, AssetReceived); - } - } - } -*/ - /// /// Update the texture entry for this part. /// /// @@ -4642,41 +5176,42 @@ namespace OpenSim.Region.Framework.Scenes Changed changeFlags = 0; - Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture; - Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture; - - // On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all + Primitive.TextureEntryFace defaultNewFace = newTex.DefaultTexture; + Primitive.TextureEntryFace defaultOldFace = oldTex.DefaultTexture; + + // On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all // other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point. - if (fallbackNewFace == null) + if (defaultNewFace == null) { - fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); - newTex.DefaultTexture = fallbackNewFace; + defaultNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); + newTex.DefaultTexture = defaultNewFace; } - if (fallbackOldFace == null) + if (defaultOldFace == null) { - fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); - oldTex.DefaultTexture = fallbackOldFace; + defaultOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); + oldTex.DefaultTexture = defaultOldFace; } // Materials capable viewers can send a ObjectImage packet // when nothing in TE has changed. MaterialID should be updated // by the RenderMaterials CAP handler, so updating it here may cause a - // race condtion. Therefore, if no non-materials TE fields have changed, + // race condtion. Therefore, if no non-materials TE fields have changed, // we should ignore any changes and not update Shape.TextureEntry bool otherFieldsChanged = false; - - for (int i = 0 ; i < GetNumberOfSides(); i++) + int nsides = GetNumberOfSides(); + for (int i = 0 ; i < nsides; i++) { - - Primitive.TextureEntryFace newFace = newTex.DefaultTexture; - Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture; - + Primitive.TextureEntryFace newFace = defaultNewFace; + Primitive.TextureEntryFace oldFace = defaultOldFace; if (oldTex.FaceTextures[i] != null) oldFace = oldTex.FaceTextures[i]; if (newTex.FaceTextures[i] != null) newFace = newTex.FaceTextures[i]; + if (oldFace.TextureID != newFace.TextureID) + changeFlags |= Changed.TEXTURE; + Color4 oldRGBA = oldFace.RGBA; Color4 newRGBA = newFace.RGBA; @@ -4686,9 +5221,6 @@ namespace OpenSim.Region.Framework.Scenes oldRGBA.A != newRGBA.A) changeFlags |= Changed.COLOR; - if (oldFace.TextureID != newFace.TextureID) - changeFlags |= Changed.TEXTURE; - // Max change, skip the rest of testing if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) break; @@ -4706,24 +5238,56 @@ namespace OpenSim.Region.Framework.Scenes if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true; if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true; if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true; + if(otherFieldsChanged) + changeFlags |= Changed.TEXTURE; } } - if (changeFlags != 0 || otherFieldsChanged) - { - m_shape.TextureEntry = newTex.GetBytes(); - if (changeFlags != 0) - TriggerScriptChangedEvent(changeFlags); - UpdateFlag = UpdateRequired.FULL; - ParentGroup.HasGroupChanged = true; + if (changeFlags == 0) + return; + m_shape.TextureEntry = newTex.GetBytes(); + TriggerScriptChangedEvent(changeFlags); + ParentGroup.HasGroupChanged = true; + ScheduleFullUpdate(); + } - //This is madness.. - //ParentGroup.ScheduleGroupForFullUpdate(); - //This is sparta - ScheduleFullUpdate(); + internal void UpdatePhysicsSubscribedEvents() + { + PhysicsActor pa = PhysActor; + if (pa == null) + return; + + pa.OnCollisionUpdate -= PhysicsCollision; + + bool hassound = (!VolumeDetectActive && CollisionSoundType >= 0 && ((Flags & PrimFlags.Physics) != 0)); + + scriptEvents CombinedEvents = AggregateScriptEvents; + + // merge with root part + if (ParentGroup != null && ParentGroup.RootPart != null) + CombinedEvents |= ParentGroup.RootPart.AggregateScriptEvents; + + // submit to this part case + if (VolumeDetectActive) + CombinedEvents &= PhyscicsVolumeDtcSubsEvents; + else if ((Flags & PrimFlags.Phantom) != 0) + CombinedEvents &= PhyscicsPhantonSubsEvents; + else + CombinedEvents &= PhysicsNeededSubsEvents; + + if (hassound || CombinedEvents != 0) + { + // subscribe to physics updates. + pa.OnCollisionUpdate += PhysicsCollision; + pa.SubscribeEvents(50); // 20 reports per second + } + else + { + pa.UnSubscribeEvents(); } } + public void aggregateScriptEvents() { if (ParentGroup == null || ParentGroup.RootPart == null) @@ -4761,17 +5325,6 @@ namespace OpenSim.Region.Framework.Scenes objectflagupdate |= (uint) PrimFlags.AllowInventoryDrop; } - SubscribeForCollisionEvents(); - - //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) - //{ - // ParentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting; - //} - //else - //{ - // ParentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting; - //} - LocalFlags = (PrimFlags)objectflagupdate; if (ParentGroup != null && ParentGroup.RootPart == this) @@ -4782,6 +5335,7 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat( // "[SCENE OBJECT PART]: Scheduling part {0} {1} for full update in aggregateScriptEvents()", Name, LocalId); + UpdatePhysicsSubscribedEvents(); ScheduleFullUpdate(); } } @@ -4815,7 +5369,7 @@ namespace OpenSim.Region.Framework.Scenes { return m_forceMouselook; } - + public override string ToString() { return String.Format("{0} {1} (parent {2}))", Name, UUID, ParentGroup); @@ -4832,7 +5386,7 @@ namespace OpenSim.Region.Framework.Scenes && (ParentGroup.RootPart != this || ParentGroup.AttachedAvatar != remoteClient.AgentId && ParentGroup.HasPrivateAttachmentPoint)) return; - + // Causes this thread to dig into the Client Thread Data. // Remember your locking here! remoteClient.SendEntityUpdate( @@ -4840,9 +5394,9 @@ namespace OpenSim.Region.Framework.Scenes PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity); - ParentGroup.Scene.StatsReporter.AddObjectUpdates(1); + ParentGroup.Scene.StatsReporter.AddObjectUpdates(1); } - + public void AddScriptLPS(int count) { ParentGroup.AddScriptLPS(count); @@ -4856,7 +5410,7 @@ namespace OpenSim.Region.Framework.Scenes /// The scene the prim is being rezzed into public void ApplyPermissionsOnRez(InventoryItemBase item, bool userInventory, Scene scene) { - if ((OwnerID != item.Owner) || ((item.CurrentPermissions & SceneObjectGroup.SLAM) != 0) || ((item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0)) + if ((OwnerID != item.Owner) || ((item.CurrentPermissions & (uint)PermissionMask.Slam) != 0) || ((item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0)) { if (scene.Permissions.PropagatePermissions()) { @@ -4887,16 +5441,13 @@ namespace OpenSim.Region.Framework.Scenes if (OwnerID != item.Owner) { - //LogPermissions("Before ApplyNextOwnerPermissions"); + if(OwnerID != GroupID) + LastOwnerID = OwnerID; + OwnerID = item.Owner; + Inventory.ChangeInventoryOwner(item.Owner); if (scene.Permissions.PropagatePermissions()) ApplyNextOwnerPermissions(); - - //LogPermissions("After ApplyNextOwnerPermissions"); - - LastOwnerID = OwnerID; - OwnerID = item.Owner; - Inventory.ChangeInventoryOwner(item.Owner); } } @@ -4908,17 +5459,19 @@ namespace OpenSim.Region.Framework.Scenes { PermissionsUtil.LogPermissions(Name, message, BaseMask, OwnerMask, NextOwnerMask); } - + public void ApplyNextOwnerPermissions() { // Export needs to be preserved in the base and everyone // mask, but removed in the owner mask as a next owner // can never change the export status - BaseMask &= NextOwnerMask | (uint)PermissionMask.Export; + BaseMask &= (NextOwnerMask | (uint)PermissionMask.Export); OwnerMask &= NextOwnerMask; - EveryoneMask &= NextOwnerMask | (uint)PermissionMask.Export; + EveryoneMask &= (NextOwnerMask | (uint)PermissionMask.Export); + GroupMask = 0; // Giving an object zaps group permissions Inventory.ApplyNextOwnerPermissions(); + AggregateInnerPerms(); } public void UpdateLookAt() @@ -4970,6 +5523,19 @@ namespace OpenSim.Region.Framework.Scenes return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); } + public void ResetOwnerChangeFlag() + { + List inv = Inventory.GetInventoryList(); + + foreach (UUID itemID in inv) + { + TaskInventoryItem item = Inventory.GetInventoryItem(itemID); + item.OwnerChanged = false; + Inventory.UpdateInventoryItem(item, false, false); + } + AggregateInnerPerms(); + } + /// /// Record an avatar sitting on this part. /// @@ -4990,7 +5556,8 @@ namespace OpenSim.Region.Framework.Scenes if (m_sittingAvatars.Add(sp)) { - ParentGroup.m_sittingAvatars.Add(sp); + if(!ParentGroup.m_sittingAvatars.Contains(sp)) + ParentGroup.m_sittingAvatars.Add(sp); return true; } @@ -5062,5 +5629,32 @@ namespace OpenSim.Region.Framework.Scenes return m_sittingAvatars.Count; } } + + public void Stop() + { + Velocity = Vector3.Zero; + AngularVelocity = Vector3.Zero; + Acceleration = Vector3.Zero; + APIDActive = false; + } + + // handle osVolumeDetect + public void ScriptSetVolumeDetect(bool makeVolumeDetect) + { + if(_parentID == 0) + { + // if root prim do it via SOG + ParentGroup.ScriptSetVolumeDetect(makeVolumeDetect); + return; + } + + bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0); + bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0); + bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0); + + if(PhysActor != null) + PhysActor.Building = true; + UpdatePrimFlags(wasUsingPhysics,wasTemporary,wasPhantom,makeVolumeDetect,false); + } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index ec39726..30f7151 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -26,6 +26,7 @@ */ using System; +using System.Text; using System.Xml; using System.IO; using System.Collections.Generic; @@ -46,10 +47,15 @@ namespace OpenSim.Region.Framework.Scenes { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private string m_inventoryFileName = String.Empty; private byte[] m_inventoryFileData = new byte[0]; + private byte[] m_inventoryFileNameBytes = new byte[0]; + private string m_inventoryFileName = ""; private uint m_inventoryFileNameSerial = 0; - + private bool m_inventoryPrivileged = false; + private object m_inventoryFileLock = new object(); + + private Dictionary m_scriptErrors = new Dictionary(); + /// /// The part to which the inventory belongs. /// @@ -70,7 +76,7 @@ namespace OpenSim.Region.Framework.Scenes /// Tracks whether inventory has changed since the last persistent backup /// internal bool HasInventoryChanged; - + /// /// Inventory serial number /// @@ -85,7 +91,10 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal TaskInventoryDictionary Items { - get { return m_items; } + get + { + return m_items; + } set { m_items = value; @@ -102,7 +111,7 @@ namespace OpenSim.Region.Framework.Scenes return m_items.Count; } } - + /// /// Constructor /// @@ -133,39 +142,54 @@ namespace OpenSim.Region.Framework.Scenes /// public void ResetInventoryIDs() { - if (null == m_part) + if (m_part == null) return; - - lock (m_items) + + m_items.LockItemsForWrite(true); + if (m_items.Count == 0) { - if (0 == m_items.Count) - return; + m_items.LockItemsForWrite(false); + return; + } - IList items = GetInventoryItems(); - m_items.Clear(); + UUID partID = m_part.UUID; + IList items = new List(m_items.Values); + m_items.Clear(); - foreach (TaskInventoryItem item in items) - { - item.ResetIDs(m_part.UUID); - m_items.Add(item.ItemID, item); - } + foreach (TaskInventoryItem item in items) + { + item.ResetIDs(partID); + m_items.Add(item.ItemID, item); } + m_inventorySerial++; + m_items.LockItemsForWrite(false); } public void ResetObjectID() { - lock (Items) + if (m_part == null) + return; + + m_items.LockItemsForWrite(true); + + if (m_items.Count == 0) { - IList items = new List(Items.Values); - Items.Clear(); - - foreach (TaskInventoryItem item in items) - { - item.ParentPartID = m_part.UUID; - item.ParentID = m_part.UUID; - Items.Add(item.ItemID, item); - } + m_items.LockItemsForWrite(false); + return; } + + IList items = new List(m_items.Values); + m_items.Clear(); + + UUID partID = m_part.UUID; + foreach (TaskInventoryItem item in items) + { + item.ParentPartID = partID; + item.ParentID = partID; + m_items.Add(item.ItemID, item); + } + m_inventorySerial++; + m_items.LockItemsForWrite(false); } /// @@ -174,18 +198,17 @@ namespace OpenSim.Region.Framework.Scenes /// public void ChangeInventoryOwner(UUID ownerId) { - lock (Items) + if(m_part == null) + return; + + m_items.LockItemsForWrite(true); + if (m_items.Count == 0) { - if (0 == Items.Count) - { - return; - } + m_items.LockItemsForWrite(false); + return; } - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; - List items = GetInventoryItems(); - foreach (TaskInventoryItem item in items) + foreach (TaskInventoryItem item in m_items.Values) { if (ownerId != item.OwnerID) item.LastOwnerID = item.OwnerID; @@ -195,6 +218,10 @@ namespace OpenSim.Region.Framework.Scenes item.PermsGranter = UUID.Zero; item.OwnerChanged = true; } + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; + m_inventorySerial++; + m_items.LockItemsForWrite(false); } /// @@ -203,14 +230,16 @@ namespace OpenSim.Region.Framework.Scenes /// public void ChangeInventoryGroup(UUID groupID) { - lock (Items) + if(m_part == null) + return; + + m_items.LockItemsForWrite(true); + if (m_items.Count == 0) { - if (0 == Items.Count) - { - return; - } + m_items.LockItemsForWrite(false); + return; } - + m_inventorySerial++; // Don't let this set the HasGroupChanged flag for attachments // as this happens during rez and we don't want a new asset // for each attachment each time @@ -220,12 +249,10 @@ namespace OpenSim.Region.Framework.Scenes m_part.ParentGroup.HasGroupChanged = true; } - List items = GetInventoryItems(); - foreach (TaskInventoryItem item in items) - { - if (groupID != item.GroupID) - item.GroupID = groupID; - } + foreach (TaskInventoryItem item in m_items.Values) + item.GroupID = groupID; + + m_items.LockItemsForWrite(false); } private void QueryScriptStates() @@ -233,15 +260,18 @@ namespace OpenSim.Region.Framework.Scenes if (m_part == null || m_part.ParentGroup == null || m_part.ParentGroup.Scene == null) return; - lock (Items) + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in Items.Values) + if (item.InvType == (int)InventoryType.LSL) { bool running; if (TryGetScriptInstanceRunning(m_part.ParentGroup.Scene, item, out running)) item.ScriptRunning = running; } } + + m_items.LockItemsForRead(false); } public bool TryGetScriptInstanceRunning(UUID itemId, out bool running) @@ -318,7 +348,10 @@ namespace OpenSim.Region.Framework.Scenes { List scripts = GetInventoryItems(InventoryType.LSL); foreach (TaskInventoryItem item in scripts) + { RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); + m_part.RemoveScriptEvents(item.ItemID); + } } /// @@ -326,7 +359,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void StopScriptInstances() { - GetInventoryItems(InventoryType.LSL).ForEach(i => StopScriptInstance(i)); + List scripts = GetInventoryItems(InventoryType.LSL); + foreach (TaskInventoryItem item in scripts) + StopScriptInstance(item); } /// @@ -339,8 +374,11 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[PRIM INVENTORY]: Starting script {0} {1} in prim {2} {3} in {4}", // item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName); - if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) + if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item, m_part)) + { + StoreScriptError(item.ItemID, "no permission"); return false; + } m_part.AddFlag(PrimFlags.Scripted); @@ -350,14 +388,13 @@ namespace OpenSim.Region.Framework.Scenes if (stateSource == 2 && // Prim crossing m_part.ParentGroup.Scene.m_trustBinaries) { - lock (m_items) - { - m_items[item.ItemID].PermsMask = 0; - m_items[item.ItemID].PermsGranter = UUID.Zero; - } - + m_items.LockItemsForWrite(true); + m_items[item.ItemID].PermsMask = 0; + m_items[item.ItemID].PermsGranter = UUID.Zero; + m_items.LockItemsForWrite(false); m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); + StoreScriptErrors(item.ItemID, null); m_part.ParentGroup.AddActiveScriptCount(1); m_part.ScheduleFullUpdate(); return true; @@ -366,9 +403,11 @@ namespace OpenSim.Region.Framework.Scenes AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); if (null == asset) { + string msg = String.Format("asset ID {0} could not be found", item.AssetID); + StoreScriptError(item.ItemID, msg); m_log.ErrorFormat( "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", - item.Name, item.ItemID, m_part.AbsolutePosition, + item.Name, item.ItemID, m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID); return false; @@ -378,16 +417,18 @@ namespace OpenSim.Region.Framework.Scenes if (m_part.ParentGroup.m_savedScriptState != null) item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID); - lock (m_items) - { - m_items[item.ItemID].OldItemID = item.OldItemID; - m_items[item.ItemID].PermsMask = 0; - m_items[item.ItemID].PermsGranter = UUID.Zero; - } + m_items.LockItemsForWrite(true); + + m_items[item.ItemID].OldItemID = item.OldItemID; + m_items[item.ItemID].PermsMask = 0; + m_items[item.ItemID].PermsGranter = UUID.Zero; + + m_items.LockItemsForWrite(false); string script = Utils.BytesToString(asset.Data); m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); + StoreScriptErrors(item.ItemID, null); if (!item.ScriptRunning) m_part.ParentGroup.Scene.EventManager.TriggerStopScript( m_part.LocalId, item.ItemID); @@ -401,7 +442,7 @@ namespace OpenSim.Region.Framework.Scenes private UUID RestoreSavedScriptState(UUID loadedID, UUID oldID, UUID newID) { // m_log.DebugFormat( -// "[PRIM INVENTORY]: Restoring scripted state for item {0}, oldID {1}, loadedID {2}", +// "[PRIM INVENTORY]: Restoring scripted state for item {0}, oldID {1}, loadedID {2}", // newID, oldID, loadedID); IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); @@ -414,7 +455,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_part.ParentGroup.m_savedScriptState.ContainsKey(stateID)) { XmlDocument doc = new XmlDocument(); - + doc.XmlResolver=null; doc.LoadXml(m_part.ParentGroup.m_savedScriptState[stateID]); ////////// CRUFT WARNING /////////////////////////////////// @@ -450,7 +491,7 @@ namespace OpenSim.Region.Framework.Scenes m_part.ParentGroup.m_savedScriptState[stateID] = newDoc.OuterXml; } - + foreach (IScriptModule e in engines) { if (e != null) @@ -466,22 +507,138 @@ namespace OpenSim.Region.Framework.Scenes return stateID; } + /// + /// Start a script which is in this prim's inventory. + /// Some processing may occur in the background, but this routine returns asap. + /// + /// + /// A + /// public bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) { - TaskInventoryItem item = GetInventoryItem(itemId); - if (item != null) + lock (m_scriptErrors) + { + // Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion + m_scriptErrors.Remove(itemId); + } + CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource); + return true; + } + + private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) + { + m_items.LockItemsForRead(true); + + if (m_items.ContainsKey(itemId)) { - return CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); + TaskInventoryItem it = m_items[itemId]; + m_items.LockItemsForRead(false); + + CreateScriptInstance(it, startParam, postOnRez, engine, stateSource); } else { - m_log.ErrorFormat( - "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", - itemId, m_part.Name, m_part.UUID, + m_items.LockItemsForRead(false); + string msg = String.Format("couldn't be found for prim {0}, {1} at {2} in {3}", m_part.Name, m_part.UUID, m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); + StoreScriptError(itemId, msg); + m_log.ErrorFormat( + "[PRIM INVENTORY]: " + + "Couldn't start script with ID {0} since it {1}", itemId, msg); + } + } - return false; + /// + /// Start a script which is in this prim's inventory and return any compilation error messages. + /// + /// + /// A + /// + public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) + { + ArrayList errors; + + // Indicate to CreateScriptInstanceInternal() we want it to + // post any compilation/loading error messages + lock (m_scriptErrors) + { + m_scriptErrors[itemId] = null; } + + // Perform compilation/loading + CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource); + + // Wait for and retrieve any errors + lock (m_scriptErrors) + { + while ((errors = m_scriptErrors[itemId]) == null) + { + if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000)) + { + m_log.ErrorFormat( + "[PRIM INVENTORY]: " + + "timedout waiting for script {0} errors", itemId); + errors = m_scriptErrors[itemId]; + if (errors == null) + { + errors = new ArrayList(1); + errors.Add("timedout waiting for errors"); + } + break; + } + } + m_scriptErrors.Remove(itemId); + } + return errors; + } + + // Signal to CreateScriptInstanceEr() that compilation/loading is complete + private void StoreScriptErrors(UUID itemId, ArrayList errors) + { + lock (m_scriptErrors) + { + // If compilation/loading initiated via CreateScriptInstance(), + // it does not want the errors, so just get out + if (!m_scriptErrors.ContainsKey(itemId)) + { + return; + } + + // Initiated via CreateScriptInstanceEr(), if we know what the + // errors are, save them and wake CreateScriptInstanceEr(). + if (errors != null) + { + m_scriptErrors[itemId] = errors; + System.Threading.Monitor.PulseAll(m_scriptErrors); + return; + } + } + + // Initiated via CreateScriptInstanceEr() but we don't know what + // the errors are yet, so retrieve them from the script engine. + // This may involve some waiting internal to GetScriptErrors(). + errors = GetScriptErrors(itemId); + + // Get a default non-null value to indicate success. + if (errors == null) + { + errors = new ArrayList(); + } + + // Post to CreateScriptInstanceEr() and wake it up + lock (m_scriptErrors) + { + m_scriptErrors[itemId] = errors; + System.Threading.Monitor.PulseAll(m_scriptErrors); + } + } + + // Like StoreScriptErrors(), but just posts a single string message + private void StoreScriptError(UUID itemId, string message) + { + ArrayList errors = new ArrayList(1); + errors.Add(message); + StoreScriptErrors(itemId, errors); } /// @@ -494,19 +651,11 @@ namespace OpenSim.Region.Framework.Scenes /// public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted) { - bool scriptPresent = false; - - lock (m_items) - { - if (m_items.ContainsKey(itemId)) - scriptPresent = true; - } - - if (scriptPresent) + if (m_items.ContainsKey(itemId)) { if (!sceneObjectBeingDeleted) m_part.RemoveScriptEvents(itemId); - + m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId); m_part.ParentGroup.AddActiveScriptCount(-1); } @@ -515,7 +664,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[PRIM INVENTORY]: " + "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", - itemId, m_part.Name, m_part.UUID, + itemId, m_part.Name, m_part.UUID, m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); } } @@ -544,7 +693,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[PRIM INVENTORY]: " + "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", - itemId, m_part.Name, m_part.UUID, + itemId, m_part.Name, m_part.UUID, m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); } } @@ -573,14 +722,16 @@ namespace OpenSim.Region.Framework.Scenes /// private bool InventoryContainsName(string name) { - lock (m_items) + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) + if (item.Name == name) { - if (item.Name == name) - return true; + m_items.LockItemsForRead(false); + return true; } } + m_items.LockItemsForRead(false); return false; } @@ -622,8 +773,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) { - List il = GetInventoryItems(); - + m_items.LockItemsForRead(true); + List il = new List(m_items.Values); + m_items.LockItemsForRead(false); foreach (TaskInventoryItem i in il) { if (i.Name == item.Name) @@ -661,16 +813,16 @@ namespace OpenSim.Region.Framework.Scenes item.Name = name; item.GroupID = m_part.GroupID; - lock (m_items) - m_items.Add(item.ItemID, item); - - if (allowedDrop) - m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); - else - m_part.TriggerScriptChangedEvent(Changed.INVENTORY); + m_items.LockItemsForWrite(true); + m_items.Add(item.ItemID, item); + m_items.LockItemsForWrite(false); + if (allowedDrop) + m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); + else + m_part.TriggerScriptChangedEvent(Changed.INVENTORY); + m_part.AggregateInnerPerms(); m_inventorySerial++; - //m_inventorySerial += 2; HasInventoryChanged = true; m_part.ParentGroup.HasGroupChanged = true; } @@ -684,15 +836,15 @@ namespace OpenSim.Region.Framework.Scenes /// public void RestoreInventoryItems(ICollection items) { - lock (m_items) + m_items.LockItemsForWrite(true); + foreach (TaskInventoryItem item in items) { - foreach (TaskInventoryItem item in items) - { - m_items.Add(item.ItemID, item); -// m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - } - m_inventorySerial++; + m_items.Add(item.ItemID, item); +// m_part.TriggerScriptChangedEvent(Changed.INVENTORY); } + m_items.LockItemsForWrite(false); + m_part.AggregateInnerPerms(); + m_inventorySerial++; } /// @@ -703,23 +855,24 @@ namespace OpenSim.Region.Framework.Scenes public TaskInventoryItem GetInventoryItem(UUID itemId) { TaskInventoryItem item; - - lock (m_items) - m_items.TryGetValue(itemId, out item); - + m_items.LockItemsForRead(true); + m_items.TryGetValue(itemId, out item); + m_items.LockItemsForRead(false); return item; } public TaskInventoryItem GetInventoryItem(string name) { - lock (m_items) + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) + if (item.Name == name) { - if (item.Name == name) - return item; + m_items.LockItemsForRead(false); + return item; } } + m_items.LockItemsForRead(false); return null; } @@ -728,41 +881,45 @@ namespace OpenSim.Region.Framework.Scenes { List items = new List(); - lock (m_items) + m_items.LockItemsForRead(true); + + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) - { - if (item.Name == name) - items.Add(item); - } + if (item.Name == name) + items.Add(item); } + m_items.LockItemsForRead(false); + return items; } - public bool GetRezReadySceneObjects(TaskInventoryItem item, out List objlist, out List veclist) + public bool GetRezReadySceneObjects(TaskInventoryItem item, out List objlist, out List veclist, out Vector3 bbox, out float offsetHeight) { AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); if (null == rezAsset) { m_log.WarnFormat( - "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}", + "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}", item.AssetID, item.Name, m_part.Name); objlist = null; veclist = null; + bbox = Vector3.Zero; + offsetHeight = 0; return false; } - Vector3 bbox; - float offsetHeight; - - m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight); + bool single = m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight); for (int i = 0; i < objlist.Count; i++) { SceneObjectGroup group = objlist[i]; - +/* + group.RootPart.AttachPoint = group.RootPart.Shape.State; + group.RootPart.AttachedPos = group.AbsolutePosition; + group.RootPart.AttachRotation = group.GroupRotation; +*/ group.ResetIDs(); SceneObjectPart rootPart = group.GetPart(group.UUID); @@ -771,12 +928,14 @@ namespace OpenSim.Region.Framework.Scenes // in the serialization, transfer the correct name from the inventory to the // object itself before we rez. // Only do these for the first object if we are rezzing a coalescence. - if (i == 0) + // nahh dont mess with coalescence objects, + // the name in inventory can be change for inventory purpuses only + if (objlist.Count == 1) { rootPart.Name = item.Name; rootPart.Description = item.Description; } - +/* reverted to old code till part.ApplyPermissionsOnRez is better reviewed/fixed group.SetGroup(m_part.GroupID, null); foreach (SceneObjectPart part in group.Parts) @@ -792,13 +951,55 @@ namespace OpenSim.Region.Framework.Scenes part.ApplyPermissionsOnRez(dest, false, m_part.ParentGroup.Scene); } +*/ +// old code start + SceneObjectPart[] partList = group.Parts; + group.SetGroup(m_part.GroupID, null); + + if ((rootPart.OwnerID != item.OwnerID) || (item.CurrentPermissions & (uint)PermissionMask.Slam) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) + { + if (m_part.ParentGroup.Scene.Permissions.PropagatePermissions()) + { + foreach (SceneObjectPart part in partList) + { + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) + part.EveryoneMask = item.EveryonePermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) + part.NextOwnerMask = item.NextPermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) + part.GroupMask = item.GroupPermissions; + } + + group.ApplyNextOwnerPermissions(); + } + } + + foreach (SceneObjectPart part in partList) + { + if ((part.OwnerID != item.OwnerID) || (item.CurrentPermissions & (uint)PermissionMask.Slam) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) + { + if(part.GroupID != part.OwnerID) + part.LastOwnerID = part.OwnerID; + part.OwnerID = item.OwnerID; + part.Inventory.ChangeInventoryOwner(item.OwnerID); + } + + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) + part.EveryoneMask = item.EveryonePermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) + part.NextOwnerMask = item.NextPermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) + part.GroupMask = item.GroupPermissions; + } +// old code end rootPart.TrimPermissions(); + group.InvalidateDeepEffectivePerms(); } return true; } - + /// /// Update an existing inventory item. /// @@ -817,11 +1018,12 @@ namespace OpenSim.Region.Framework.Scenes public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged) { - TaskInventoryItem it = GetInventoryItem(item.ItemID); - if (it != null) + m_items.LockItemsForWrite(true); + + if (m_items.ContainsKey(item.ItemID)) { // m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name); - + item.ParentID = m_part.UUID; item.ParentPartID = m_part.UUID; @@ -830,24 +1032,26 @@ namespace OpenSim.Region.Framework.Scenes if (item.GroupPermissions != (uint)PermissionMask.None) item.GroupID = m_part.GroupID; + if(item.OwnerID == UUID.Zero) // viewer to internal enconding of group owned + item.OwnerID = item.GroupID; + if (item.AssetID == UUID.Zero) - item.AssetID = it.AssetID; + item.AssetID = m_items[item.ItemID].AssetID; - lock (m_items) - { - m_items[item.ItemID] = item; - m_inventorySerial++; - } - + m_items[item.ItemID] = item; + + m_inventorySerial++; if (fireScriptEvents) m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - + if (considerChanged) { + m_part.ParentGroup.InvalidateDeepEffectivePerms(); HasInventoryChanged = true; m_part.ParentGroup.HasGroupChanged = true; } - + m_items.LockItemsForWrite(false); + return true; } else @@ -855,11 +1059,12 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat( "[PRIM INVENTORY]: " + "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", - item.ItemID, m_part.Name, m_part.UUID, + item.ItemID, m_part.Name, m_part.UUID, m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); } - return false; + m_items.LockItemsForWrite(false); + return false; } /// @@ -870,160 +1075,194 @@ namespace OpenSim.Region.Framework.Scenes /// in this prim's inventory. public int RemoveInventoryItem(UUID itemID) { - TaskInventoryItem item = GetInventoryItem(itemID); - if (item != null) + m_items.LockItemsForRead(true); + + if (m_items.ContainsKey(itemID)) { int type = m_items[itemID].InvType; - if (type == 10) // Script + m_items.LockItemsForRead(false); + if (type == (int)InventoryType.LSL) // Script { - // route it through here, to handle script cleanup tasks - RemoveScriptInstance(itemID, false); + m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); } + m_items.LockItemsForWrite(true); m_items.Remove(itemID); + m_items.LockItemsForWrite(false); + + m_part.ParentGroup.InvalidateDeepEffectivePerms(); + m_inventorySerial++; m_part.TriggerScriptChangedEvent(Changed.INVENTORY); HasInventoryChanged = true; m_part.ParentGroup.HasGroupChanged = true; - if (!ContainsScripts()) + int scriptcount = 0; + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) + { + if (item.Type == (int)InventoryType.LSL) + { + scriptcount++; + } + } + m_items.LockItemsForRead(false); + + + if (scriptcount <= 0) + { m_part.RemFlag(PrimFlags.Scripted); + } m_part.ScheduleFullUpdate(); return type; - } else { + m_items.LockItemsForRead(false); m_log.ErrorFormat( "[PRIM INVENTORY]: " + - "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", - itemID, m_part.Name, m_part.UUID, - m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); + "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory", + itemID, m_part.Name, m_part.UUID); } return -1; } - private bool CreateInventoryFile() - { -// m_log.DebugFormat( -// "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}", -// m_part.Name, m_part.UUID, m_part.LocalId, m_inventorySerial); - if (m_inventoryFileName == String.Empty || - m_inventoryFileNameSerial < m_inventorySerial) + /// + /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client + /// + /// + public void RequestInventoryFile(IClientAPI client, IXfer xferManager) + { + lock (m_inventoryFileLock) { - // Something changed, we need to create a new file - m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp"; - m_inventoryFileNameSerial = m_inventorySerial; + bool changed = false; - InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); + m_items.LockItemsForRead(true); - lock (m_items) + if (m_inventorySerial == 0) // No inventory { - foreach (TaskInventoryItem item in m_items.Values) - { -// m_log.DebugFormat( -// "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}", -// item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId); + m_items.LockItemsForRead(false); + client.SendTaskInventory(m_part.UUID, 0, new byte[0]); + return; + } - UUID ownerID = item.OwnerID; - uint everyoneMask = 0; - uint baseMask = item.BasePermissions; - uint ownerMask = item.CurrentPermissions; - uint groupMask = item.GroupPermissions; + if (m_items.Count == 0) // No inventory + { + m_items.LockItemsForRead(false); + client.SendTaskInventory(m_part.UUID, 0, new byte[0]); + return; + } - invString.AddItemStart(); - invString.AddNameValueLine("item_id", item.ItemID.ToString()); - invString.AddNameValueLine("parent_id", m_part.UUID.ToString()); + if (m_inventoryFileNameSerial != m_inventorySerial) + { + m_inventoryFileNameSerial = m_inventorySerial; + changed = true; + } - invString.AddPermissionsStart(); + m_items.LockItemsForRead(false); - invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); - invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); - invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask)); - invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask)); - invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions)); + if (m_inventoryFileData.Length < 2) + changed = true; - invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); - invString.AddNameValueLine("owner_id", ownerID.ToString()); + bool includeAssets = false; + if (m_part.ParentGroup.Scene.Permissions.CanEditObjectInventory(m_part.UUID, client.AgentId)) + includeAssets = true; - invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); + if (m_inventoryPrivileged != includeAssets) + changed = true; - invString.AddNameValueLine("group_id", item.GroupID.ToString()); - invString.AddSectionEnd(); + if (!changed) + { + xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData); + client.SendTaskInventory(m_part.UUID, (short)m_inventoryFileNameSerial, + m_inventoryFileNameBytes); - invString.AddNameValueLine("asset_id", item.AssetID.ToString()); - invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type)); - invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType)); - invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags)); + return; + } - invString.AddSaleStart(); - invString.AddNameValueLine("sale_type", "not"); - invString.AddNameValueLine("sale_price", "0"); - invString.AddSectionEnd(); + m_inventoryPrivileged = includeAssets; - invString.AddNameValueLine("name", item.Name + "|"); - invString.AddNameValueLine("desc", item.Description + "|"); + InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); - invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); - invString.AddSectionEnd(); - } - } + m_items.LockItemsForRead(true); - m_inventoryFileData = Utils.StringToBytes(invString.BuildString); + foreach (TaskInventoryItem item in m_items.Values) + { + UUID ownerID = item.OwnerID; + UUID groupID = item.GroupID; + uint everyoneMask = item.EveryonePermissions; + uint baseMask = item.BasePermissions; + uint ownerMask = item.CurrentPermissions; + uint groupMask = item.GroupPermissions; - return true; - } + invString.AddItemStart(); + invString.AddNameValueLine("item_id", item.ItemID.ToString()); + invString.AddNameValueLine("parent_id", m_part.UUID.ToString()); - // No need to recreate, the existing file is fine - return false; - } + invString.AddPermissionsStart(); - /// - /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client - /// - /// - public void RequestInventoryFile(IClientAPI client, IXfer xferManager) - { - lock (m_items) - { - // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing - // a new script if any previous deletion has left the prim inventory empty. - if (m_items.Count == 0) // No inventory - { -// m_log.DebugFormat( -// "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items", -// m_part.Name, m_part.LocalId, m_part.UUID, client.Name); + invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); + invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); + invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask)); + invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask)); + invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions)); - client.SendTaskInventory(m_part.UUID, 0, new byte[0]); - return; + invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); + + invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); + + invString.AddNameValueLine("group_id",groupID.ToString()); + if(groupID != UUID.Zero && ownerID == groupID) + { + invString.AddNameValueLine("owner_id", UUID.Zero.ToString()); + invString.AddNameValueLine("group_owned","1"); + } + else + { + invString.AddNameValueLine("owner_id", ownerID.ToString()); + invString.AddNameValueLine("group_owned","0"); + } + + invString.AddSectionEnd(); + + if (includeAssets) + invString.AddNameValueLine("asset_id", item.AssetID.ToString()); + else + invString.AddNameValueLine("asset_id", UUID.Zero.ToString()); + invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type)); + invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType)); + invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags)); + + invString.AddSaleStart(); + invString.AddNameValueLine("sale_type", "not"); + invString.AddNameValueLine("sale_price", "0"); + invString.AddSectionEnd(); + + invString.AddNameValueLine("name", item.Name + "|"); + invString.AddNameValueLine("desc", item.Description + "|"); + + invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); + invString.AddSectionEnd(); } - CreateInventoryFile(); - - // In principle, we should only do the rest if the inventory changed; - // by sending m_inventorySerial to the client, it ought to know - // that nothing changed and that it doesn't need to request the file. - // Unfortunately, it doesn't look like the client optimizes this; - // the client seems to always come back and request the Xfer, - // no matter what value m_inventorySerial has. - // FIXME: Could probably be > 0 here rather than > 2 + m_items.LockItemsForRead(false); + + m_inventoryFileData = Utils.StringToBytes(invString.GetString()); + if (m_inventoryFileData.Length > 2) { - // Add the file for Xfer - // m_log.DebugFormat( - // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}", - // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId); - + m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp"; + m_inventoryFileNameBytes = Util.StringToBytes256(m_inventoryFileName); xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData); + client.SendTaskInventory(m_part.UUID, (short)m_inventoryFileNameSerial,m_inventoryFileNameBytes); + return; } - - // Tell the client we're ready to Xfer the file - client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial, - Util.StringToBytes256(m_inventoryFileName)); + + client.SendTaskInventory(m_part.UUID, 0, new byte[0]); } } @@ -1033,67 +1272,80 @@ namespace OpenSim.Region.Framework.Scenes /// public void ProcessInventoryBackup(ISimulationDataService datastore) { - if (HasInventoryChanged) - { +// Removed this because linking will cause an immediate delete of the new +// child prim from the database and the subsequent storing of the prim sees +// the inventory of it as unchanged and doesn't store it at all. The overhead +// of storing prim inventory needlessly is much less than the aggravation +// of prim inventory loss. +// if (HasInventoryChanged) +// { + m_items.LockItemsForRead(true); + ICollection itemsvalues = m_items.Values; HasInventoryChanged = false; - List items = GetInventoryItems(); - datastore.StorePrimInventory(m_part.UUID, items); - - } + m_items.LockItemsForRead(false); + try + { + datastore.StorePrimInventory(m_part.UUID, itemsvalues); + } + catch {} +// } } public class InventoryStringBuilder { - public string BuildString = String.Empty; + private StringBuilder BuildString = new StringBuilder(1024); public InventoryStringBuilder(UUID folderID, UUID parentID) { - BuildString += "\tinv_object\t0\n\t{\n"; + BuildString.Append("\tinv_object\t0\n\t{\n"); AddNameValueLine("obj_id", folderID.ToString()); AddNameValueLine("parent_id", parentID.ToString()); AddNameValueLine("type", "category"); - AddNameValueLine("name", "Contents|"); - AddSectionEnd(); + AddNameValueLine("name", "Contents|\n\t}"); } public void AddItemStart() { - BuildString += "\tinv_item\t0\n"; - AddSectionStart(); + BuildString.Append("\tinv_item\t0\n\t{\n"); } public void AddPermissionsStart() { - BuildString += "\tpermissions 0\n"; - AddSectionStart(); + BuildString.Append("\tpermissions 0\n\t{\n"); } public void AddSaleStart() { - BuildString += "\tsale_info\t0\n"; - AddSectionStart(); + BuildString.Append("\tsale_info\t0\n\t{\n"); } protected void AddSectionStart() { - BuildString += "\t{\n"; + BuildString.Append("\t{\n"); } public void AddSectionEnd() { - BuildString += "\t}\n"; + BuildString.Append("\t}\n"); } public void AddLine(string addLine) { - BuildString += addLine; + BuildString.Append(addLine); } public void AddNameValueLine(string name, string value) { - BuildString += "\t\t"; - BuildString += name + "\t"; - BuildString += value + "\n"; + BuildString.Append("\t\t"); + BuildString.Append(name); + BuildString.Append("\t"); + BuildString.Append(value); + BuildString.Append("\n"); + } + + public String GetString() + { + return BuildString.ToString(); } public void Close() @@ -1101,71 +1353,74 @@ namespace OpenSim.Region.Framework.Scenes } } + public void AggregateInnerPerms(ref uint owner, ref uint group, ref uint everyone) + { + foreach (TaskInventoryItem item in m_items.Values) + { + if(item.InvType == (sbyte)InventoryType.Landmark) + continue; + owner &= item.CurrentPermissions; + group &= item.GroupPermissions; + everyone &= item.EveryonePermissions; + } + } + public uint MaskEffectivePermissions() { + // used to propagate permissions restrictions outwards + // Modify does not propagate outwards. uint mask=0x7fffffff; - - lock (m_items) + + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) - { - if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0) - mask &= ~((uint)PermissionMask.Copy >> 13); - if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0) - mask &= ~((uint)PermissionMask.Transfer >> 13); - if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) - mask &= ~((uint)PermissionMask.Modify >> 13); - - if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) - mask &= ~(uint)PermissionMask.Copy; - if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0) - mask &= ~(uint)PermissionMask.Transfer; - if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0) - mask &= ~(uint)PermissionMask.Modify; - } + if(item.InvType == (sbyte)InventoryType.Landmark) + continue; + + // apply current to normal permission bits + uint newperms = item.CurrentPermissions; + + if ((newperms & (uint)PermissionMask.Copy) == 0) + mask &= ~(uint)PermissionMask.Copy; + if ((newperms & (uint)PermissionMask.Transfer) == 0) + mask &= ~(uint)PermissionMask.Transfer; + if ((newperms & (uint)PermissionMask.Export) == 0) + mask &= ~((uint)PermissionMask.Export); + + // apply next owner restricted by current to folded bits + newperms &= item.NextPermissions; + + if ((newperms & (uint)PermissionMask.Copy) == 0) + mask &= ~((uint)PermissionMask.FoldedCopy); + if ((newperms & (uint)PermissionMask.Transfer) == 0) + mask &= ~((uint)PermissionMask.FoldedTransfer); + if ((newperms & (uint)PermissionMask.Export) == 0) + mask &= ~((uint)PermissionMask.FoldedExport); + } - return mask; } public void ApplyNextOwnerPermissions() { - lock (m_items) + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) - { -// m_log.DebugFormat ( -// "[SCENE OBJECT PART INVENTORY]: Applying next permissions {0} to {1} in {2} with current {3}, base {4}, everyone {5}", -// item.NextPermissions, item.Name, m_part.Name, item.CurrentPermissions, item.BasePermissions, item.EveryonePermissions); - - if (item.InvType == (int)InventoryType.Object) - { - uint perms = item.CurrentPermissions; - PermissionsUtil.ApplyFoldedPermissions(perms, ref perms); - item.CurrentPermissions = perms; - } - - item.CurrentPermissions &= item.NextPermissions; - item.BasePermissions &= item.NextPermissions; - item.EveryonePermissions &= item.NextPermissions; - item.OwnerChanged = true; - item.PermsMask = 0; - item.PermsGranter = UUID.Zero; - } + item.CurrentPermissions &= item.NextPermissions; + item.BasePermissions &= item.NextPermissions; + item.EveryonePermissions &= item.NextPermissions; + item.OwnerChanged = true; + item.PermsMask = 0; + item.PermsGranter = UUID.Zero; } } public void ApplyGodPermissions(uint perms) { - lock (m_items) + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) - { - item.CurrentPermissions = perms; - item.BasePermissions = perms; - } + item.CurrentPermissions = perms; + item.BasePermissions = perms; } - + m_inventorySerial++; HasInventoryChanged = true; } @@ -1176,14 +1431,11 @@ namespace OpenSim.Region.Framework.Scenes /// public bool ContainsScripts() { - lock (m_items) + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) + if (item.InvType == (int)InventoryType.LSL) { - if (item.InvType == (int)InventoryType.LSL) - { - return true; - } + return true; } } @@ -1197,17 +1449,13 @@ namespace OpenSim.Region.Framework.Scenes public int ScriptCount() { int count = 0; - lock (m_items) + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) - { - if (item.InvType == (int)InventoryType.LSL) - { - count++; - } - } + if (item.InvType == (int)InventoryType.LSL) + count++; } - + m_items.LockItemsForRead(false); return count; } /// @@ -1230,9 +1478,7 @@ namespace OpenSim.Region.Framework.Scenes if (engine != null) { if (engine.GetScriptState(item.ItemID)) - { count++; - } } } } @@ -1241,50 +1487,52 @@ namespace OpenSim.Region.Framework.Scenes public List GetInventoryList() { - List ret = new List(); + m_items.LockItemsForRead(true); - lock (m_items) - { - foreach (TaskInventoryItem item in m_items.Values) - ret.Add(item.ItemID); - } + List ret = new List(m_items.Count); + foreach (TaskInventoryItem item in m_items.Values) + ret.Add(item.ItemID); + m_items.LockItemsForRead(false); return ret; } public List GetInventoryItems() { - List ret = new List(); - - lock (m_items) - ret = new List(m_items.Values); + m_items.LockItemsForRead(true); + List ret = new List(m_items.Values); + m_items.LockItemsForRead(false); return ret; } public List GetInventoryItems(InventoryType type) { - List ret = new List(); + m_items.LockItemsForRead(true); - lock (m_items) - { - foreach (TaskInventoryItem item in m_items.Values) - if (item.InvType == (int)type) - ret.Add(item); - } + List ret = new List(m_items.Count); + foreach (TaskInventoryItem item in m_items.Values) + if (item.InvType == (int)type) + ret.Add(item); + m_items.LockItemsForRead(false); return ret; } - + public Dictionary GetScriptStates() { - Dictionary ret = new Dictionary(); - + return GetScriptStates(false); + } + + public Dictionary GetScriptStates(bool oldIDs) + { + Dictionary ret = new Dictionary(); + if (m_part.ParentGroup.Scene == null) // Group not in a scene return ret; - + IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); - + if (engines.Length == 0) // No engine at all return ret; @@ -1303,17 +1551,24 @@ namespace OpenSim.Region.Framework.Scenes string n = e.GetXMLState(item.ItemID); if (n != String.Empty) { - if (!ret.ContainsKey(item.ItemID)) - ret[item.ItemID] = n; + if (oldIDs) + { + if (!ret.ContainsKey(item.OldItemID)) + ret[item.OldItemID] = n; + } + else + { + if (!ret.ContainsKey(item.ItemID)) + ret[item.ItemID] = n; + } break; } } } } - return ret; } - + public void ResumeScripts() { IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 1fddd91..74f765d 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -90,7 +90,26 @@ namespace OpenSim.Region.Framework.Scenes m_scene.EventManager.TriggerScenePresenceUpdated(this); } - public PresenceType PresenceType { get; private set; } + public bool IsNPC { get; private set; } + + // simple yes or no isGOD from god level >= 200 + // should only be set by GodController + // we have two to suport legacy behaviour + // IsViewerUIGod was controlled by viewer in older versions + // IsGod may now be also controled by viewer acording to options + public bool IsViewerUIGod { get; set; } + public bool IsGod { get; set; } + + private PresenceType m_presenceType; + public PresenceType PresenceType + { + get {return m_presenceType;} + private set + { + m_presenceType = value; + IsNPC = (m_presenceType == PresenceType.Npc); + } + } private ScenePresenceStateMachine m_stateMachine; @@ -98,8 +117,8 @@ namespace OpenSim.Region.Framework.Scenes /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine /// for more details. /// - public ScenePresenceState LifecycleState - { + public ScenePresenceState LifecycleState + { get { return m_stateMachine.GetState(); @@ -116,7 +135,7 @@ namespace OpenSim.Region.Framework.Scenes /// the viewer fires these in quick succession. /// /// - /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement + /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement /// regulation done there. /// private object m_completeMovementLock = new object(); @@ -124,7 +143,7 @@ namespace OpenSim.Region.Framework.Scenes // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); - + /// /// Experimentally determined "fudge factor" to make sit-target positions /// the same as in SecondLife. Fudge factor was tested for 36 different @@ -134,21 +153,116 @@ namespace OpenSim.Region.Framework.Scenes /// issue #1716 /// public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.4f); + public bool LegacySitOffsets = true; /// /// Movement updates for agents in neighboring regions are sent directly to clients. /// This value only affects how often agent positions are sent to neighbor regions /// for things such as distance-based update prioritization + /// this are the square of real distances /// - public static readonly float SIGNIFICANT_MOVEMENT = 2.0f; + public static readonly float MOVEMENT = .25f; + public static readonly float SIGNIFICANT_MOVEMENT = 16.0f; + public static readonly float CHILDUPDATES_MOVEMENT = 100.0f; + public static readonly float CHILDUPDATES_TIME = 2000f; // min time between child updates (ms) + + private UUID m_previusParcelUUID = UUID.Zero; + private UUID m_currentParcelUUID = UUID.Zero; + private bool m_previusParcelHide = false; + private bool m_currentParcelHide = false; + private object parcelLock = new Object(); + public double ParcelDwellTickMS; + + public UUID currentParcelUUID + { + get { return m_currentParcelUUID; } + set + { + lock (parcelLock) + { + bool oldhide = m_currentParcelHide; + bool checksame = true; + if (value != m_currentParcelUUID) + { + ParcelDwellTickMS = Util.GetTimeStampMS(); + m_previusParcelHide = m_currentParcelHide; + m_previusParcelUUID = m_currentParcelUUID; + checksame = false; + } + m_currentParcelUUID = value; + m_currentParcelHide = false; + + ILandObject land = m_scene.LandChannel.GetLandObject(AbsolutePosition.X, AbsolutePosition.Y); + if (land != null && !land.LandData.SeeAVs) + m_currentParcelHide = true; + + if (m_previusParcelUUID != UUID.Zero || checksame) + ParcelCrossCheck(m_currentParcelUUID, m_previusParcelUUID, m_currentParcelHide, m_previusParcelHide, oldhide,checksame); + } + } + } + + public void sitSOGmoved() + { +/* + if (IsDeleted || !IsSatOnObject) + //what me? nahh + return; + if (IsInTransit) + return; + + ILandObject land = m_scene.LandChannel.GetLandObject(AbsolutePosition.X, AbsolutePosition.Y); + if (land == null) + return; //?? + UUID parcelID = land.LandData.GlobalID; + if (m_currentParcelUUID != parcelID) + currentParcelUUID = parcelID; +*/ + } + + public bool ParcelAllowThisAvatarSounds + { + get + { + try + { + lock (parcelLock) + { + ILandObject land = m_scene.LandChannel.GetLandObject(AbsolutePosition.X, AbsolutePosition.Y); + if (land == null) + return true; + if (land.LandData.AnyAVSounds) + return true; + if (!land.LandData.GroupAVSounds) + return false; + return ControllingClient.IsGroupMember(land.LandData.GroupID); + } + } + catch + { + return true; + } + } + } - public UUID currentParcelUUID = UUID.Zero; + public bool ParcelHideThisAvatar + { + get + { + return m_currentParcelHide; + } + } /// /// The animator for this avatar /// public ScenePresenceAnimator Animator { get; private set; } + /// + /// Server Side Animation Override + /// + public MovementAnimationOverrides Overrides { get; private set; } + public String sitAnimation = "SIT"; /// /// Attachments recorded on this avatar. /// @@ -164,21 +278,19 @@ namespace OpenSim.Region.Framework.Scenes private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO; private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO; private bool MouseDown = false; -// private SceneObjectGroup proxyObjectGroup; - //private SceneObjectPart proxyObjectPart = null; public Vector3 lastKnownAllowedPosition; public bool sentMessageAboutRestrictedParcelFlyingDown; + public Vector4 CollisionPlane = Vector4.UnitW; + public Vector4 m_lastCollisionPlane = Vector4.UnitW; + private byte m_lastState; private Vector3 m_lastPosition; private Quaternion m_lastRotation; private Vector3 m_lastVelocity; private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f); + private bool SentInitialData = false; - private bool m_followCamAuto = false; - - - private Vector3? m_forceToApply; private int m_userFlags; public int UserFlags { @@ -192,23 +304,14 @@ namespace OpenSim.Region.Framework.Scenes set { PhysicsActor.Flying = value; } } - // add for fly velocity control - private bool FlyingOld {get; set;} - public bool WasFlying - { - get; private set; - } - - public bool IsColliding + public bool IsColliding { get { return PhysicsActor != null && PhysicsActor.IsColliding; } // We would expect setting IsColliding to be private but it's used by a hack in Scene set { PhysicsActor.IsColliding = value; } } -// private int m_lastColCount = -1; //KF: Look for Collision chnages -// private int m_updateCount = 0; //KF: Update Anims for a while -// private static readonly int UPDATE_COUNT = 10; // how many frames to update for + private List m_lastColliders = new List(); private TeleportFlags m_teleportFlags; public TeleportFlags TeleportFlags @@ -233,9 +336,18 @@ namespace OpenSim.Region.Framework.Scenes private float m_sitAvatarHeight = 2.0f; + private bool m_childUpdatesBusy = false; + private int m_lastChildUpdatesTime; + private int m_lastChildAgentUpdateGodLevel; + private float m_lastChildAgentUpdateDrawDistance; private Vector3 m_lastChildAgentUpdatePosition; // private Vector3 m_lastChildAgentUpdateCamPosition; + private Vector3 m_lastCameraRayCastCam; + private Vector3 m_lastCameraRayCastPos; + + private float m_FOV = 1.04f; + private const int LAND_VELOCITYMAG_MAX = 12; private const float FLY_ROLL_MAX_RADIANS = 1.1f; @@ -244,32 +356,51 @@ namespace OpenSim.Region.Framework.Scenes private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f; private float m_health = 100f; + private float m_healRate = 1f; + private float m_healRatePerFrame = 0.05f; - protected ulong crossingFromRegion; - - private readonly Vector3[] Dir_Vectors = new Vector3[11]; + private readonly Vector3[] Dir_Vectors = new Vector3[12]; - protected Timer m_reprioritization_timer; - protected bool m_reprioritizing; - protected bool m_reprioritization_called; + protected int m_reprioritizationLastTime; + protected bool m_reprioritizationBusy; + protected Vector3 m_reprioritizationLastPosition; + protected float m_reprioritizationLastDrawDistance; private Quaternion m_headrotation = Quaternion.Identity; //PauPaw:Proper PID Controler for autopilot************ - public bool MovingToTarget { get; private set; } - public Vector3 MoveToPositionTarget { get; private set; } + + private bool m_movingToTarget; + public bool MovingToTarget + { + get {return m_movingToTarget;} + private set {m_movingToTarget = value; } + } + + private Vector3 m_moveToPositionTarget; + public Vector3 MoveToPositionTarget + { + get {return m_moveToPositionTarget;} + private set {m_moveToPositionTarget = value; } + } + + private float m_moveToSpeed; + public float MoveToSpeed + { + get {return m_moveToSpeed;} + private set {m_moveToSpeed = value; } + } + + private double m_delayedStop = -1.0; /// /// Controls whether an avatar automatically moving to a target will land when it gets there (if flying). /// public bool LandAtTarget { get; private set; } - private int m_movementUpdateCount; - private const int NumMovementsBetweenRayCast = 5; - private bool CameraConstraintActive; - //private int m_moveToPositionStateStatus; - //***************************************************** + + private object m_collisionEventLock = new Object(); private int m_movementAnimationUpdateCounter = 0; @@ -287,7 +418,6 @@ namespace OpenSim.Region.Framework.Scenes } } - public bool SentInitialDataToClient { get; private set; } /// /// Copy of the script states while the agent is in transit. This state may @@ -303,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Implemented Control Flags /// - private enum Dir_ControlFlags + private enum Dir_ControlFlags:uint { DIR_CONTROL_FLAG_FORWARD = AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, DIR_CONTROL_FLAG_BACK = AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, @@ -315,13 +445,15 @@ namespace OpenSim.Region.Framework.Scenes DIR_CONTROL_FLAG_BACKWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, DIR_CONTROL_FLAG_LEFT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS, DIR_CONTROL_FLAG_RIGHT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG, + DIR_CONTROL_FLAG_UP_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS, DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG } - + /// /// Position at which a significant movement was made /// private Vector3 posLastSignificantMove; + private Vector3 posLastMove; #region For teleports and crossings callbacks @@ -346,10 +478,7 @@ namespace OpenSim.Region.Framework.Scenes /// private object m_originRegionIDAccessLock = new object(); - /// - /// Triggered on entity transfer after to allow CompleteMovement() to proceed after we have received an - /// UpdateAgent from the originating region.ddkjjkj - /// + private AutoResetEvent m_updateAgentReceivedAfterTransferEvent = new AutoResetEvent(false); /// @@ -366,6 +495,14 @@ namespace OpenSim.Region.Framework.Scenes /// private IScriptModule[] m_scriptEngines; + private enum LandingPointBehavior + { + OS = 1, + SL = 2 + } + + private LandingPointBehavior m_LandingPointBehavior = LandingPointBehavior.OS; + #region Properties /// @@ -379,11 +516,6 @@ namespace OpenSim.Region.Framework.Scenes public uint MovementFlag { get; private set; } /// - /// Set this if we need to force a movement update on the next received AgentUpdate from the viewer. - /// - private const uint ForceUpdateMovementFlagValue = uint.MaxValue; - - /// /// Is the agent stop control flag currently active? /// public bool AgentControlStopActive { get; private set; } @@ -396,28 +528,21 @@ namespace OpenSim.Region.Framework.Scenes get { return m_invulnerable; } } - private int m_userLevel; - - public int UserLevel - { - get { return m_userLevel; } - private set { m_userLevel = value; } - } - - private int m_godLevel; - - public int GodLevel - { - get { return m_godLevel; } - private set { m_godLevel = value; } - } + public GodController GodController { get; private set; } private ulong m_rootRegionHandle; + private Vector3 m_rootRegionPosition = new Vector3(); public ulong RegionHandle { get { return m_rootRegionHandle; } - private set { m_rootRegionHandle = value; } + private set + { + m_rootRegionHandle = value; + // position rounded to lower multiple of 256m + m_rootRegionPosition.X = (float)((m_rootRegionHandle >> 32) & 0xffffff00); + m_rootRegionPosition.Y = (float)(m_rootRegionHandle & 0xffffff00); + } } #region Client Camera @@ -425,17 +550,13 @@ namespace OpenSim.Region.Framework.Scenes /// /// Position of agent's camera in world (region cordinates) /// - protected Vector3 m_lastCameraPosition; +// protected Vector3 m_lastCameraPosition; private Vector4 m_lastCameraCollisionPlane = new Vector4(0f, 0f, 0f, 1); private bool m_doingCamRayCast = false; public Vector3 CameraPosition { get; set; } - - public Quaternion CameraRotation - { - get { return Util.Axes2Rot(CameraAtAxis, CameraLeftAxis, CameraUpAxis); } - } + public Quaternion CameraRotation { get; private set; } // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion @@ -449,39 +570,51 @@ namespace OpenSim.Region.Framework.Scenes get { Vector3 a = new Vector3(CameraAtAxis.X, CameraAtAxis.Y, 0); - - if (a == Vector3.Zero) - return a; - - return Util.GetNormalizedVector(a); + a.Normalize(); + return a; } } - #endregion + #endregion public string Firstname { get; private set; } public string Lastname { get; private set; } + public bool haveGroupInformation; + public bool gotCrossUpdate; + public byte crossingFlags; + public string Grouptitle { - get { return UseFakeGroupTitle ? "(Loading)" : m_groupTitle; } + get { return m_groupTitle; } set { m_groupTitle = value; } } private string m_groupTitle; - /// - /// When this is 'true', return a dummy group title instead of the real group title. This is - /// used as part of a hack to force viewers to update the displayed avatar name. - /// - public bool UseFakeGroupTitle { get; set; } - - // Agent's Draw distance. - public float DrawDistance { get; set; } + private float m_drawDistance = 255f; + public float DrawDistance + { + get + { + return m_drawDistance; + } + set + { + m_drawDistance = Util.Clamp(value, 32f, m_scene.MaxDrawDistance); + } + } + + public float RegionViewDistance + { + get + { + return Util.Clamp(m_drawDistance, 32f, m_scene.MaxRegionViewDistance); + } + } public bool AllowMovement { get; set; } private bool m_setAlwaysRun; - public bool SetAlwaysRun { get @@ -557,12 +690,16 @@ namespace OpenSim.Region.Framework.Scenes // in the sim unless the avatar is on a sit target. While // on a sit target, m_pos will contain the desired offset // without the parent rotation applied. - SceneObjectPart sitPart = ParentPart; - - if (sitPart != null) - return sitPart.ParentGroup.AbsolutePosition + (m_pos * sitPart.GetWorldRotation()); + if (ParentPart != null) + { + SceneObjectPart rootPart = ParentPart.ParentGroup.RootPart; + // if (sitPart != null) + // return sitPart.AbsolutePosition + (m_pos * sitPart.GetWorldRotation()); + if (rootPart != null) + return rootPart.AbsolutePosition + (m_pos * rootPart.GetWorldRotation()); + } } - + return m_pos; } set @@ -614,11 +751,8 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Velocity of the avatar with respect to its local reference frame. + /// Current velocity of the avatar. /// - /// - /// So when sat on a vehicle this will be 0. To get velocity with respect to the world use GetWorldVelocity() - /// public override Vector3 Velocity { get @@ -631,21 +765,12 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!", // m_velocity, Name, Scene.RegionInfo.RegionName); } -// else if (ParentPart != null) -// { -// return ParentPart.ParentGroup.Velocity; -// } return m_velocity; } set { -// Util.PrintCallStack(); -// m_log.DebugFormat( -// "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}", -// Scene.RegionInfo.RegionName, Name, value); - if (PhysicsActor != null) { try @@ -658,27 +783,42 @@ namespace OpenSim.Region.Framework.Scenes } } - m_velocity = value; + m_velocity = value; + +// m_log.DebugFormat( +// "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}", +// Scene.RegionInfo.RegionName, Name, m_velocity); } } -/* - public override Vector3 AngularVelocity + + // requested Velocity for physics engines avatar motors + // only makes sense if there is a physical rep + public Vector3 TargetVelocity { get { if (PhysicsActor != null) - { - m_rotationalvelocity = PhysicsActor.RotationalVelocity; + return PhysicsActor.TargetVelocity; + else + return Vector3.Zero; + } - // m_log.DebugFormat( - // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!", - // m_velocity, Name, Scene.RegionInfo.RegionName); + set + { + if (PhysicsActor != null) + { + try + { + PhysicsActor.TargetVelocity = value; + } + catch (Exception e) + { + m_log.Error("[SCENE PRESENCE]: TARGETVELOCITY " + e.Message); + } } - - return m_rotationalvelocity; } } -*/ + private Quaternion m_bodyRot = Quaternion.Identity; /// @@ -691,9 +831,9 @@ namespace OpenSim.Region.Framework.Scenes /// public Quaternion Rotation { - get - { - return m_bodyRot; + get + { + return m_bodyRot; } set @@ -758,16 +898,42 @@ namespace OpenSim.Region.Framework.Scenes set { m_health = value; } } + public float HealRate + { + get { return m_healRate; } + set + { + if(value > 100.0f) + m_healRate = 100.0f; + else if (value <= 0.0) + m_healRate = 0.0f; + else + m_healRate = value; + + if(Scene != null) + m_healRatePerFrame = m_healRate * Scene.FrameTime; + else + m_healRatePerFrame = 0.05f; + } + } + + /// - /// Get rotation relative to the world. + /// Gets the world rotation of this presence. /// + /// + /// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not. + /// /// public Quaternion GetWorldRotation() { - SceneObjectPart sitPart = ParentPart; + if (IsSatOnObject) + { + SceneObjectPart sitPart = ParentPart; - if (sitPart != null) - return sitPart.GetWorldRotation() * Rotation; + if (sitPart != null) + return sitPart.GetWorldRotation() * Rotation; + } return Rotation; } @@ -793,26 +959,7 @@ namespace OpenSim.Region.Framework.Scenes seeds = Scene.CapsModule.GetChildrenSeeds(UUID); else seeds = new Dictionary(); - - List old = new List(); - foreach (ulong handle in seeds.Keys) - { - uint x, y; - Util.RegionHandleToRegionLoc(handle, out x, out y); - - if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) - { - old.Add(handle); - } - } - DropOldNeighbours(old); - - if (Scene.CapsModule != null) - Scene.CapsModule.SetChildrenSeed(UUID, seeds); - KnownRegions = seeds; - //m_log.Debug(" ++++++++++AFTER+++++++++++++ "); - //DumpKnownRegions(); } public void DumpKnownRegions() @@ -827,20 +974,20 @@ namespace OpenSim.Region.Framework.Scenes } private bool m_mouseLook; -// private bool m_leftButtonDown; + private bool m_leftButtonDown; private bool m_inTransit; /// /// This signals whether the presence is in transit between neighbouring regions. /// - /// + /// /// It is not set when the presence is teleporting or logging in/out directly to a region. /// public bool IsInTransit { get { return m_inTransit; } - set { + set { if(value) { if (Flying) @@ -851,14 +998,11 @@ namespace OpenSim.Region.Framework.Scenes m_inTransit = value; } } + // this is is only valid if IsInTransit is true + // only false on HG tps + // used work arounf viewers asking source region about destination user + public bool IsInLocalTransit {get; set; } - private float m_speedModifier = 1.0f; - - public float SpeedModifier - { - get { return m_speedModifier; } - set { m_speedModifier = value; } - } /// /// Modifier for agent movement if we get an AGENT_CONTROL_STOP whilst walking or running @@ -866,7 +1010,20 @@ namespace OpenSim.Region.Framework.Scenes /// /// AGENT_CONTRL_STOP comes about if user holds down space key on viewers. /// - private float AgentControlStopSlowWhilstMoving = 0.5f; + private const float AgentControlStopSlowVel = 0.2f; + // velocities + public const float AgentControlNudgeVel = 1.0f; // setting this diferent from normal as no effect currently + public const float AgentControlNormalVel = 1.0f; + + // old normal speed was tuned to match sl normal plus Fast modifiers + // so we need to rescale it + private float m_speedModifier = 1.0f; + + public float SpeedModifier + { + get { return m_speedModifier; } + set { m_speedModifier = value; } + } private bool m_forceFly; @@ -889,35 +1046,32 @@ namespace OpenSim.Region.Framework.Scenes get { return Util.GetViewerName(m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode)); } } - /// - /// Count of how many terse updates we have sent out. It doesn't matter if this overflows. - /// - private int m_terseUpdateCount; - #endregion #region Constructor(s) public ScenePresence( IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) - { + { + m_scene = world; AttachmentsSyncLock = new Object(); AllowMovement = true; IsChildAgent = true; IsLoggingIn = false; m_sendCoarseLocationsMethod = SendCoarseLocationsDefault; Animator = new ScenePresenceAnimator(this); + Overrides = new MovementAnimationOverrides(); PresenceType = type; - // DrawDistance = world.DefaultDrawDistance; - DrawDistance = Constants.RegionSize; + DrawDistance = world.DefaultDrawDistance; RegionHandle = world.RegionInfo.RegionHandle; ControllingClient = client; Firstname = ControllingClient.FirstName; Lastname = ControllingClient.LastName; m_name = String.Format("{0} {1}", Firstname, Lastname); - m_scene = world; m_uuid = client.AgentId; LocalId = m_scene.AllocateLocalId(); + LegacySitOffsets = m_scene.LegacySitOffsets; + IsInLocalTransit = true; UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); if (account != null) @@ -925,32 +1079,52 @@ namespace OpenSim.Region.Framework.Scenes else m_userFlags = 0; + int userlevel = 0; if (account != null) - UserLevel = account.UserLevel; + userlevel = account.UserLevel; - IGroupsModule gm = m_scene.RequestModuleInterface(); - if (gm != null) - Grouptitle = gm.GetGroupTitle(m_uuid); + GodController = new GodController(world, this, userlevel); + + // IGroupsModule gm = m_scene.RequestModuleInterface(); + // if (gm != null) + // Grouptitle = gm.GetGroupTitle(m_uuid); m_scriptEngines = m_scene.RequestModuleInterfaces(); - - AbsolutePosition = posLastSignificantMove = CameraPosition = - m_lastCameraPosition = ControllingClient.StartPos; - m_reprioritization_timer = new Timer(world.ReprioritizationInterval); - m_reprioritization_timer.Elapsed += new ElapsedEventHandler(Reprioritize); - m_reprioritization_timer.AutoReset = false; + AbsolutePosition = posLastMove = posLastSignificantMove = CameraPosition = + m_reprioritizationLastPosition = ControllingClient.StartPos; + + m_reprioritizationLastDrawDistance = DrawDistance; + + // disable updates workjobs for now + m_childUpdatesBusy = true; + m_reprioritizationBusy = true; AdjustKnownSeeds(); - RegisterToEvents(); + RegisterToClientEvents(); SetDirectionVectors(); Appearance = appearance; m_stateMachine = new ScenePresenceStateMachine(this); + + HealRate = 0.5f; + + IConfig sconfig = m_scene.Config.Configs["EntityTransfer"]; + if (sconfig != null) + { + string lpb = sconfig.GetString("LandingPointBehavior", "LandingPointBehavior_OS"); + if (lpb == "LandingPointBehavior_SL") + m_LandingPointBehavior = LandingPointBehavior.SL; + } + + ControllingClient.RefreshGroupMembership(); + } + private float lastHealthSent = 0; + private void RegionHeartbeatEnd(Scene scene) { if (IsChildAgent) @@ -973,12 +1147,29 @@ namespace OpenSim.Region.Framework.Scenes } else { - m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; +// m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; + } + } + + if(m_healRatePerFrame != 0f && Health != 100.0f) + { + float last = Health; + Health += m_healRatePerFrame; + if(Health > 100.0f) + { + Health = 100.0f; + lastHealthSent = Health; + ControllingClient.SendHealth(Health); + } + else if(Math.Abs(Health - lastHealthSent) > 1.0) + { + lastHealthSent = Health; + ControllingClient.SendHealth(Health); } } } - public void RegisterToEvents() + public void RegisterToClientEvents() { ControllingClient.OnCompleteMovementToRegion += CompleteMovement; ControllingClient.OnAgentUpdate += HandleAgentUpdate; @@ -988,28 +1179,48 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; ControllingClient.OnStartAnim += HandleStartAnim; ControllingClient.OnStopAnim += HandleStopAnim; + ControllingClient.OnChangeAnim += avnHandleChangeAnim; ControllingClient.OnForceReleaseControls += HandleForceReleaseControls; - ControllingClient.OnAutoPilotGo += MoveToTarget; + ControllingClient.OnAutoPilotGo += MoveToTargetHandle; + ControllingClient.OnUpdateThrottles += RaiseUpdateThrottles; +// ControllingClient.OnAgentFOV += HandleAgentFOV; // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange); // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement); } - private void SetDirectionVectors() + public void RemoveClientEvents() { - Dir_Vectors[0] = Vector3.UnitX; //FORWARD - Dir_Vectors[1] = -Vector3.UnitX; //BACK - Dir_Vectors[2] = Vector3.UnitY; //LEFT - Dir_Vectors[3] = -Vector3.UnitY; //RIGHT - Dir_Vectors[4] = Vector3.UnitZ; //UP - Dir_Vectors[5] = -Vector3.UnitZ; //DOWN - Dir_Vectors[6] = new Vector3(0.5f, 0f, 0f); //FORWARD_NUDGE - Dir_Vectors[7] = new Vector3(-0.5f, 0f, 0f); //BACK_NUDGE - Dir_Vectors[8] = new Vector3(0f, 0.5f, 0f); //LEFT_NUDGE - Dir_Vectors[9] = new Vector3(0f, -0.5f, 0f); //RIGHT_NUDGE - Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge + ControllingClient.OnCompleteMovementToRegion -= CompleteMovement; + ControllingClient.OnAgentUpdate -= HandleAgentUpdate; + ControllingClient.OnAgentCameraUpdate -= HandleAgentCamerasUpdate; + ControllingClient.OnAgentRequestSit -= HandleAgentRequestSit; + ControllingClient.OnAgentSit -= HandleAgentSit; + ControllingClient.OnSetAlwaysRun -= HandleSetAlwaysRun; + ControllingClient.OnStartAnim -= HandleStartAnim; + ControllingClient.OnStopAnim -= HandleStopAnim; + ControllingClient.OnChangeAnim -= avnHandleChangeAnim; + ControllingClient.OnForceReleaseControls -= HandleForceReleaseControls; + ControllingClient.OnAutoPilotGo -= MoveToTargetHandle; + ControllingClient.OnUpdateThrottles -= RaiseUpdateThrottles; +// ControllingClient.OnAgentFOV += HandleAgentFOV; } + private void SetDirectionVectors() + { + Dir_Vectors[0] = new Vector3(AgentControlNormalVel,0,0); //FORWARD + Dir_Vectors[1] = new Vector3(-AgentControlNormalVel,0,0);; //BACK + Dir_Vectors[2] = new Vector3(0,AgentControlNormalVel,0); //LEFT + Dir_Vectors[3] = new Vector3(0,-AgentControlNormalVel,0); //RIGHT + Dir_Vectors[4] = new Vector3(0,0,AgentControlNormalVel); //UP + Dir_Vectors[5] = new Vector3(0,0,-AgentControlNormalVel); //DOWN + Dir_Vectors[6] = new Vector3(AgentControlNudgeVel, 0f, 0f); //FORWARD_NUDGE + Dir_Vectors[7] = new Vector3(-AgentControlNudgeVel, 0f, 0f); //BACK_NUDGE + Dir_Vectors[8] = new Vector3(0f, AgentControlNudgeVel, 0f); //LEFT_NUDGE + Dir_Vectors[9] = new Vector3(0f, -AgentControlNudgeVel, 0f); //RIGHT_NUDGE + Dir_Vectors[10] = new Vector3(0f, 0f, AgentControlNudgeVel); //UP_Nudge + Dir_Vectors[11] = new Vector3(0f, 0f, -AgentControlNudgeVel); //DOWN_Nudge + } #endregion #region Status Methods @@ -1026,18 +1237,29 @@ namespace OpenSim.Region.Framework.Scenes /// This method is on the critical path for transferring an avatar from one region to another. Delay here /// delays that crossing. /// - private bool MakeRootAgent(Vector3 pos, bool isFlying) + + // constants for physics position search + const float PhysSearchHeight = 600f; + const float PhysMinSkipGap = 50f; + const int PhysNumberCollisions = 30; + + // only in use as part of completemovement + // other uses need fix + private bool MakeRootAgent(Vector3 pos, bool isFlying, ref Vector3 lookat) { + //int ts = Util.EnvironmentTickCount(); + lock (m_completeMovementLock) { if (!IsChildAgent) return false; + //m_log.DebugFormat("[MakeRootAgent] enter lock: {0}ms", Util.EnvironmentTickCountSubtract(ts)); //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); - // m_log.InfoFormat( - // "[SCENE]: Upgrading child to root agent for {0} in {1}", - // Name, m_scene.RegionInfo.RegionName); + // m_log.InfoFormat( + // "[SCENE]: Upgrading child to root agent for {0} in {1}", + // Name, m_scene.RegionInfo.RegionName); if (ParentUUID != UUID.Zero) { @@ -1046,20 +1268,33 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) { m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID); + ParentID = 0; + ParentPart = null; + PrevSitOffset = Vector3.Zero; + HandleForceReleaseControls(ControllingClient, UUID); // needs testing + IsLoggingIn = false; } else { part.AddSittingAvatar(this); - // ParentPosition = part.GetWorldPosition(); + // if not actually on the target invalidate it + if(gotCrossUpdate && (crossingFlags & 0x04) == 0) + part.SitTargetAvatar = UUID.Zero; + ParentID = part.LocalId; ParentPart = part; m_pos = PrevSitOffset; - // pos = ParentPosition; pos = part.GetWorldPosition(); + PhysicsActor partPhysActor = part.PhysActor; + if(partPhysActor != null) + { + partPhysActor.OnPhysicsRequestingCameraData -= + physActor_OnPhysicsRequestingCameraData; + partPhysActor.OnPhysicsRequestingCameraData += + physActor_OnPhysicsRequestingCameraData; + } } ParentUUID = UUID.Zero; - - // Animator.TrySetMovementAnimation("SIT"); } else { @@ -1069,135 +1304,144 @@ namespace OpenSim.Region.Framework.Scenes IsChildAgent = false; } + //m_log.DebugFormat("[MakeRootAgent] out lock: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + // Must reset this here so that a teleport to a region next to an existing region does not keep the flag // set and prevent the close of the connection on a subsequent re-teleport. // Should not be needed if we are not trying to tell this region to close -// DoNotCloseAfterTeleport = false; - - IGroupsModule gm = m_scene.RequestModuleInterface(); - if (gm != null) - Grouptitle = gm.GetGroupTitle(m_uuid); - - AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode); - uint teleportFlags = (aCircuit == null) ? 0 : aCircuit.teleportFlags; - if ((teleportFlags & (uint)TeleportFlags.ViaHGLogin) != 0) - { - // The avatar is arriving from another grid. This means that we may have changed the - // avatar's name to or from the special Hypergrid format ("First.Last @grid.example.com"). - // Unfortunately, due to a viewer bug, viewers don't always show the new name. - // But we have a trick that can force them to update the name anyway. - ForceViewersUpdateName(); - } + // DoNotCloseAfterTeleport = false; RegionHandle = m_scene.RegionInfo.RegionHandle; m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene); - - UUID groupUUID = ControllingClient.ActiveGroupId; - string groupName = string.Empty; - ulong groupPowers = 0; - - // ---------------------------------- - // Previous Agent Difference - AGNI sends an unsolicited AgentDataUpdate upon root agent status - try - { - if (groupUUID != UUID.Zero && gm != null) - { - GroupRecord record = gm.GetGroupRecord(groupUUID); - if (record != null) - groupName = record.GroupName; - - GroupMembershipData groupMembershipData = gm.GetMembershipData(groupUUID, m_uuid); - - if (groupMembershipData != null) - groupPowers = groupMembershipData.GroupPowers; - } - - ControllingClient.SendAgentDataUpdate( - m_uuid, groupUUID, Firstname, Lastname, groupPowers, groupName, Grouptitle); - } - catch (Exception e) - { - m_log.Error("[AGENTUPDATE]: Error ", e); - } - // ------------------------------------ + //m_log.DebugFormat("[MakeRootAgent] TriggerSetRootAgentScene: {0}ms", Util.EnvironmentTickCountSubtract(ts)); if (ParentID == 0) { - // Moved this from SendInitialData to ensure that Appearance is initialized - // before the inventory is processed in MakeRootAgent. This fixes a race condition - // related to the handling of attachments - //m_scene.GetAvatarAppearance(ControllingClient, out Appearance); - - /* RA 20140111: Commented out these TestBorderCross's. - * Not sure why this code is here. It is not checking all the borders - * and 'in region' sanity checking is done in CheckAndAdjustLandingPoint and below. - if (m_scene.TestBorderCross(pos, Cardinals.E)) - { - Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E); - pos.X = crossedBorder.BorderLine.Z - 1; - } - - if (m_scene.TestBorderCross(pos, Cardinals.N)) - { - Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); - pos.Y = crossedBorder.BorderLine.Z - 1; - } - */ + bool positionChanged = false; + bool success = true; + if (m_LandingPointBehavior == LandingPointBehavior.OS) + success = CheckAndAdjustLandingPoint_OS(ref pos, ref lookat, ref positionChanged); + else + success = CheckAndAdjustLandingPoint_SL(ref pos, ref lookat, ref positionChanged); - CheckAndAdjustLandingPoint(ref pos); + if (!success) + m_log.DebugFormat("[SCENE PRESENCE MakeRootAgent]: houston we have a problem.. {0} ({1} got banned)", Name, UUID); - if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) + if (pos.X < 0f || pos.Y < 0f + || pos.X >= m_scene.RegionInfo.RegionSizeX + || pos.Y >= m_scene.RegionInfo.RegionSizeY) { m_log.WarnFormat( "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping", pos, Name, UUID); - if (pos.X < 0f) pos.X = 0f; - if (pos.Y < 0f) pos.Y = 0f; - if (pos.Z < 0f) pos.Z = 0f; + if (pos.X < 0f) + pos.X = 0.5f; + else if(pos.X >= m_scene.RegionInfo.RegionSizeX) + pos.X = m_scene.RegionInfo.RegionSizeX - 0.5f; + if (pos.Y < 0f) + pos.Y = 0.5f; + else if(pos.Y >= m_scene.RegionInfo.RegionSizeY) + pos.Y = m_scene.RegionInfo.RegionSizeY - 0.5f; } - float localAVHeight = 1.56f; - if (Appearance.AvatarHeight > 0) - localAVHeight = Appearance.AvatarHeight; + float groundHeight = m_scene.GetGroundHeight(pos.X, pos.Y) + .01f; + float physTestHeight; - float posZLimit = 0; + if(PhysSearchHeight < groundHeight + 100f) + physTestHeight = groundHeight + 100f; + else + physTestHeight = PhysSearchHeight; - if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY) - posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; - - float newPosZ = posZLimit + localAVHeight / 2; - if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) + float localAVHalfHeight = 0.8f; + if (Appearance != null && Appearance.AvatarHeight > 0) + localAVHalfHeight = 0.5f * Appearance.AvatarHeight; + + groundHeight += localAVHalfHeight; + if (groundHeight > pos.Z) + pos.Z = groundHeight; + + bool checkPhysics = !positionChanged && + m_scene.SupportsRayCastFiltered() && + pos.Z < physTestHeight && + ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == + (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) + || (m_teleportFlags & TeleportFlags.ViaLocation) != 0 + || (m_teleportFlags & TeleportFlags.ViaHGLogin) != 0); + + if(checkPhysics) { - pos.Z = newPosZ; + // land check was done above + RayFilterFlags rayfilter = RayFilterFlags.BackFaceCull; + rayfilter |= RayFilterFlags.PrimsNonPhantomAgents; + + int physcount = PhysNumberCollisions; + + float dist = physTestHeight - groundHeight + localAVHalfHeight; + + Vector3 direction = new Vector3(0f, 0f, -1f); + Vector3 RayStart = pos; + RayStart.Z = physTestHeight; + + List physresults = + (List)m_scene.RayCastFiltered(RayStart, direction, dist, physcount, rayfilter); + if (physresults != null && physresults.Count > 0) + { + float dest = physresults[0].Pos.Z; + + if(physresults.Count > 1) + { + physresults.Sort(delegate(ContactResult a, ContactResult b) + { + return a.Depth.CompareTo(b.Depth); + }); + + int sel = 0; + int count = physresults.Count; + float curd = physresults[0].Depth; + float nextd = curd + PhysMinSkipGap; + float maxDepth = dist - pos.Z; + for(int i = 1; i < count; i++) + { + curd = physresults[i].Depth; + if(curd >= nextd) + { + sel = i; + if(curd >= maxDepth) + break; + } + nextd = curd + PhysMinSkipGap; + } + dest = physresults[sel].Pos.Z; + } + + dest += localAVHalfHeight; + if(dest > pos.Z) + pos.Z = dest; + } } + AbsolutePosition = pos; // m_log.DebugFormat( -// "Set pos {0}, vel {1} in {1} to {2} from input position of {3} on MakeRootAgent", +// "Set pos {0}, vel {1} in {1} to {2} from input position of {3} on MakeRootAgent", // Name, Scene.Name, AbsolutePosition, pos); // if (m_teleportFlags == TeleportFlags.Default) { + Vector3 vel = Velocity; AddToPhysicalScene(isFlying); -// -// Console.WriteLine( -// "Set velocity of {0} in {1} to {2} from input velocity of {3} on MakeRootAgent", -// Name, Scene.Name, PhysicsActor.Velocity, vel); -// } + if (PhysicsActor != null) + PhysicsActor.SetMomentum(vel); } else { AddToPhysicalScene(isFlying); - } - // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a - // location outside the 'root region' (the south-west 256x256 corner). This is the earlist we can do it - // since it requires a physics actor to be present. If it is left any later, then physics appears to reset - // the value to a negative position which does not trigger the border cross. - // This may not be the best location for this. - CheckForBorderCrossing(); + // reset camera to avatar pos + CameraPosition = pos; + } if (ForceFly) { @@ -1209,53 +1453,16 @@ namespace OpenSim.Region.Framework.Scenes } } - // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying - // avatar to return to the standing position in mid-air. On login it looks like this is being sent - // elsewhere anyway - // Animator.SendAnimPack(); - + //m_log.DebugFormat("[MakeRootAgent] position and physical: {0}ms", Util.EnvironmentTickCountSubtract(ts)); m_scene.SwapRootAgentCount(false); - if (Scene.AttachmentsModule != null) - { - // The initial login scene presence is already root when it gets here - // and it has already rezzed the attachments and started their scripts. - // We do the following only for non-login agents, because their scripts - // haven't started yet. - if (PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags)) - { - WorkManager.RunJob( - "RezAttachments", - o => Scene.AttachmentsModule.RezAttachments(this), - null, - string.Format("Rez attachments for {0} in {1}", Name, Scene.Name)); - } - else - { - WorkManager.RunJob( - "StartAttachmentScripts", - o => RestartAttachmentScripts(), - null, - string.Format("Start attachment scripts for {0} in {1}", Name, Scene.Name), - true); - } - } - - SendAvatarDataToAllClients(); - - // send the animations of the other presences to me - m_scene.ForEachRootScenePresence(delegate(ScenePresence presence) - { - if (presence != this) - presence.Animator.SendAnimPackToClient(ControllingClient); - }); - // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will // stall on the border crossing since the existing child agent will still have the last movement // recorded, which stops the input from being processed. - MovementFlag = ForceUpdateMovementFlagValue; + MovementFlag = 0; m_scene.EventManager.TriggerOnMakeRootAgent(this); + //m_log.DebugFormat("[MakeRootAgent] TriggerOnMakeRootAgent and done: {0}ms", Util.EnvironmentTickCountSubtract(ts)); return true; } @@ -1304,12 +1511,13 @@ namespace OpenSim.Region.Framework.Scenes /// Group Title. So the following trick makes viewers update the avatar's name by briefly changing /// the group title (to "(Loading)"), and then restoring it. /// +/* public void ForceViewersUpdateName() { m_log.DebugFormat("[SCENE PRESENCE]: Forcing viewers to update the avatar name for " + Name); UseFakeGroupTitle = true; - SendAvatarDataToAllClients(false); + Util.FireAndForget(o => { @@ -1323,7 +1531,7 @@ namespace OpenSim.Region.Framework.Scenes SendAvatarDataToAllClients(false); }, null, "Scenepresence.ForceViewersUpdateName"); } - +*/ public int GetStateSource() { AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(UUID); @@ -1347,11 +1555,17 @@ namespace OpenSim.Region.Framework.Scenes /// It doesn't get called for a teleport. Reason being, an agent that /// teleports out may not end up anywhere near this region /// - public void MakeChildAgent() + public void MakeChildAgent(ulong newRegionHandle) { + haveGroupInformation = false; + gotCrossUpdate = false; + crossingFlags = 0; m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; - m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName); + RegionHandle = newRegionHandle; + + m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1} from root region {2}", + Name, Scene.RegionInfo.RegionName, newRegionHandle); // Reset the m_originRegionID as it has dual use as a flag to signal that the UpdateAgent() call orignating // from the source simulator has completed on a V2 teleport. @@ -1371,7 +1585,7 @@ namespace OpenSim.Region.Framework.Scenes else Animator.ResetAnimations(); - + // m_log.DebugFormat( // "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}", // Name, UUID, m_scene.RegionInfo.RegionName); @@ -1379,14 +1593,21 @@ namespace OpenSim.Region.Framework.Scenes // Don't zero out the velocity since this can cause problems when an avatar is making a region crossing, // depending on the exact timing. This shouldn't matter anyway since child agent positions are not updated. //Velocity = new Vector3(0, 0, 0); - + IsChildAgent = true; m_scene.SwapRootAgentCount(true); RemoveFromPhysicalScene(); ParentID = 0; // Child agents can't be sitting +// we dont have land information for child + m_previusParcelHide = false; + m_previusParcelUUID = UUID.Zero; + m_currentParcelHide = false; + m_currentParcelUUID = UUID.Zero; // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into - + + CollisionPlane = Vector4.UnitW; + m_scene.EventManager.TriggerOnMakeChildAgent(this); } @@ -1398,9 +1619,10 @@ namespace OpenSim.Region.Framework.Scenes if (PhysicsActor != null) { // PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; - PhysicsActor.UnSubscribeEvents(); + PhysicsActor.OnOutOfBounds -= OutOfBoundsCall; PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; + PhysicsActor.UnSubscribeEvents(); m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); PhysicsActor = null; } @@ -1423,12 +1645,16 @@ namespace OpenSim.Region.Framework.Scenes public void TeleportWithMomentum(Vector3 pos, Vector3? v) { + if(!CheckLocalTPLandingPoint(ref pos)) + return; + if (ParentID != (uint)0) StandUp(); + bool isFlying = Flying; Vector3 vel = Velocity; RemoveFromPhysicalScene(); - CheckLandingPoint(ref pos); + AbsolutePosition = pos; AddToPhysicalScene(isFlying); if (PhysicsActor != null) @@ -1438,11 +1664,29 @@ namespace OpenSim.Region.Framework.Scenes else PhysicsActor.SetMomentum(vel); } + + SendTerseUpdateToAllClients(); + } + + public void TeleportOnEject(Vector3 pos) + { + if (ParentID != (uint)0) + StandUp(); + + bool isFlying = Flying; + RemoveFromPhysicalScene(); + + AbsolutePosition = pos; + + AddToPhysicalScene(isFlying); + SendTerseUpdateToAllClients(); } public void avnLocalTeleport(Vector3 newpos, Vector3? newvel, bool rotateToVelXY) { - CheckLandingPoint(ref newpos); + if(!CheckLocalTPLandingPoint(ref newpos)) + return; + AbsolutePosition = newpos; if (newvel.HasValue) @@ -1469,11 +1713,15 @@ namespace OpenSim.Region.Framework.Scenes } } } + SendTerseUpdateToAllClients(); } public void StopFlying() { - Vector3 pos = AbsolutePosition; + if (IsInTransit) + return; + + Vector3 pos = AbsolutePosition; if (Appearance.AvatarHeight != 127.0f) pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f)); else @@ -1492,7 +1740,7 @@ namespace OpenSim.Region.Framework.Scenes else CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f)); - ControllingClient.SendAgentTerseUpdate(this); + SendAgentTerseUpdate(this); } /// @@ -1501,7 +1749,7 @@ namespace OpenSim.Region.Framework.Scenes /// Postive or negative roll amount in radians private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown) { - + float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS); m_AngularVelocity.Z = rollAmount; @@ -1553,17 +1801,14 @@ namespace OpenSim.Region.Framework.Scenes if (m_AngularVelocity.Z > 0) { - float leftOverToMin = m_AngularVelocity.Z - rollMinRadians; if (amount > leftOverToMin) return -leftOverToMin; else return -amount; - } else { - float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians; if (amount > leftOverToMin) return leftOverToMin; @@ -1571,22 +1816,65 @@ namespace OpenSim.Region.Framework.Scenes return amount; } } - - // neighbouring regions we have enabled a child agent in // holds the seed cap for the child agent in that region private Dictionary m_knownChildRegions = new Dictionary(); - public void AddNeighbourRegion(ulong regionHandle, string cap) + struct spRegionSizeInfo + { + public int sizeX; + public int sizeY; + } + + private Dictionary m_knownChildRegionsSizeInfo = new Dictionary(); + + public void AddNeighbourRegion(GridRegion region, string capsPath) + { + lock (m_knownChildRegions) + { + ulong regionHandle = region.RegionHandle; + m_knownChildRegions.Add(regionHandle,capsPath); + + spRegionSizeInfo sizeInfo = new spRegionSizeInfo(); + sizeInfo.sizeX = region.RegionSizeX; + sizeInfo.sizeY = region.RegionSizeY; + m_knownChildRegionsSizeInfo[regionHandle] = sizeInfo; + } + } + + public void AddNeighbourRegionSizeInfo(GridRegion region) + { + lock (m_knownChildRegions) + { + spRegionSizeInfo sizeInfo = new spRegionSizeInfo(); + sizeInfo.sizeX = region.RegionSizeX; + sizeInfo.sizeY = region.RegionSizeY; + ulong regionHandle = region.RegionHandle; + + if (!m_knownChildRegionsSizeInfo.ContainsKey(regionHandle)) + { + m_knownChildRegionsSizeInfo.Add(regionHandle, sizeInfo); + + } + else + m_knownChildRegionsSizeInfo[regionHandle] = sizeInfo; + } + } + + public void SetNeighbourRegionSizeInfo(List regionsList) { lock (m_knownChildRegions) { - if (!m_knownChildRegions.ContainsKey(regionHandle)) + m_knownChildRegionsSizeInfo.Clear(); + + foreach (GridRegion region in regionsList) { - uint x, y; - Utils.LongToUInts(regionHandle, out x, out y); - m_knownChildRegions.Add(regionHandle, cap); + spRegionSizeInfo sizeInfo = new spRegionSizeInfo(); + sizeInfo.sizeX = region.RegionSizeX; + sizeInfo.sizeY = region.RegionSizeY; + ulong regionHandle = region.RegionHandle; + m_knownChildRegionsSizeInfo.Add(regionHandle, sizeInfo); } } } @@ -1600,9 +1888,16 @@ namespace OpenSim.Region.Framework.Scenes //if (m_knownChildRegions.ContainsKey(regionHandle)) // m_log.DebugFormat(" !!! removing known region {0} in {1}. Count = {2}", regionHandle, Scene.RegionInfo.RegionName, m_knownChildRegions.Count); m_knownChildRegions.Remove(regionHandle); + m_knownChildRegionsSizeInfo.Remove(regionHandle); } } + public bool knowsNeighbourRegion(ulong regionHandle) + { + lock (m_knownChildRegions) + return m_knownChildRegions.ContainsKey(regionHandle); + } + public void DropOldNeighbours(List oldRegions) { foreach (ulong handle in oldRegions) @@ -1612,6 +1907,13 @@ namespace OpenSim.Region.Framework.Scenes } } + public void DropThisRootRegionFromNeighbours() + { + ulong handle = m_scene.RegionInfo.RegionHandle; + RemoveNeighbourRegion(handle); + Scene.CapsModule.DropChildSeed(UUID, handle); + } + public Dictionary KnownRegions { get @@ -1632,7 +1934,8 @@ namespace OpenSim.Region.Framework.Scenes { get { - return new List(KnownRegions.Keys); + lock (m_knownChildRegions) + return new List(m_knownChildRegions.Keys); } } @@ -1662,35 +1965,66 @@ namespace OpenSim.Region.Framework.Scenes public void SetSize(Vector3 size, float feetoffset) { if (PhysicsActor != null && !IsChildAgent) - { - // Eventually there will be a physics call that sets avatar size that includes offset info. - // For the moment, just set the size as passed. - PhysicsActor.Size = size; - // PhysicsActor.setAvatarSize(size, feetoffset); - } + PhysicsActor.setAvatarSize(size, feetoffset); } private bool WaitForUpdateAgent(IClientAPI client) { // Before the source region executes UpdateAgent - // (which triggers Scene.IncomingUpdateChildAgent(AgentData cAgentData) here in the destination, + // (which triggers Scene.IncomingUpdateChildAgent(AgentData cAgentData) here in the destination, // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero - m_updateAgentReceivedAfterTransferEvent.WaitOne(10000); - UUID originID = UUID.Zero; + try + { + if(m_updateAgentReceivedAfterTransferEvent.WaitOne(10000)) + { + UUID originID = UUID.Zero; - lock (m_originRegionIDAccessLock) - originID = m_originRegionID; + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + if (originID.Equals(UUID.Zero)) + { + // Movement into region will fail + m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} at {1} got invalid origin region id ", client.Name, Scene.Name); + return false; + } + return true; + } + else + { + m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} at {1} did not receive agent update ", client.Name, Scene.Name); + return false; + } + } + catch { } + + return false; + } - if (originID.Equals(UUID.Zero)) + public void RotateToLookAt(Vector3 lookAt) + { + if(ParentID == 0) { - // Movement into region will fail - m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name); - return false; + float n = lookAt.X * lookAt.X + lookAt.Y * lookAt.Y; + if(n < 0.0001f) + { + Rotation = Quaternion.Identity; + return; + } + n = lookAt.X/(float)Math.Sqrt(n); + float angle = (float)Math.Acos(n); + angle *= 0.5f; + float s = (float)Math.Sin(angle); + if(lookAt.Y < 0) + s = -s; + Rotation = new Quaternion( + 0f, + 0f, + s, + (float)Math.Cos(angle) + ); } - - return true; } /// @@ -1704,62 +2038,72 @@ namespace OpenSim.Region.Framework.Scenes /// public void CompleteMovement(IClientAPI client, bool openChildAgents) { -// DateTime startTime = DateTime.Now; + int ts = Util.EnvironmentTickCount(); m_log.InfoFormat( "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", client.Name, Scene.Name, AbsolutePosition); - bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); // Get this ahead of time because IsInTransit modifies 'm_AgentControlFlags' + m_inTransit = true; - IsInTransit = true; try { // Make sure it's not a login agent. We don't want to wait for updates during login - if (!(PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags))) + if (!IsNPC && !IsRealLogin(m_teleportFlags)) { + // Let's wait until UpdateAgent (called by departing region) is done if (!WaitForUpdateAgent(client)) // The sending region never sent the UpdateAgent data, we have to refuse return; } - Vector3 look = Velocity; + //m_log.DebugFormat("[CompleteMovement] WaitForUpdateAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) - if ((Math.Abs(look.X) < 0.1) && (Math.Abs(look.Y) < 0.1) && (Math.Abs(look.Z) < 0.1)) - { - look = new Vector3(0.99f, 0.042f, 0); - } + bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); - // Prevent teleporting to an underground location - // (may crash client otherwise) - // - Vector3 pos = AbsolutePosition; - float ground = m_scene.GetGroundHeight(pos.X, pos.Y); - if (pos.Z < ground + 1.5f) + Vector3 look = Lookat; + look.Z = 0f; + if ((Math.Abs(look.X) < 0.01) && (Math.Abs(look.Y) < 0.01)) { - pos.Z = ground + 1.5f; - AbsolutePosition = pos; + look = Velocity; + look.Normalize(); + if ((Math.Abs(look.X) < 0.01) && (Math.Abs(look.Y) < 0.01) ) + look = new Vector3(0.99f, 0.042f, 0); } - if (!MakeRootAgent(AbsolutePosition, flying)) + // Check Default Location (Also See EntityTransferModule.TeleportAgentWithinRegion) + if (AbsolutePosition.X == 128f && AbsolutePosition.Y == 128f && AbsolutePosition.Z == 22.5f) + AbsolutePosition = Scene.RegionInfo.DefaultLandingPoint; + + if (!MakeRootAgent(AbsolutePosition, flying, ref look)) { m_log.DebugFormat( - "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", + "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", Name, Scene.Name); return; } - // Tell the client that we're totally ready - ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); - // Child agents send initial data up in LLUDPServer.HandleUseCircuitCode() - if (!SentInitialDataToClient) - SendInitialDataToClient(); + //m_log.DebugFormat("[CompleteMovement] MakeRootAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + if(!haveGroupInformation && !IsChildAgent && !IsNPC) + { + IGroupsModule gm = m_scene.RequestModuleInterface(); + if (gm != null) + Grouptitle = gm.GetGroupTitle(m_uuid); + + //m_log.DebugFormat("[CompleteMovement] Missing Grouptitle: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + InventoryFolderBase cof = m_scene.InventoryService.GetFolderForType(client.AgentId, (FolderType)46); + if (cof == null) + COF = UUID.Zero; + else + COF = cof.ID; - // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); + m_log.DebugFormat("[CompleteMovement]: Missing COF for {0} is {1}", client.AgentId, COF); + } if (!string.IsNullOrEmpty(m_callbackURI)) { @@ -1768,69 +2112,260 @@ namespace OpenSim.Region.Framework.Scenes // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this // region as the current region, meaning that a close sent before then will fail the teleport. - // System.Threading.Thread.Sleep(2000); + // System.Threading.Thread.Sleep(2000); m_log.DebugFormat( "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", client.Name, client.AgentId, m_callbackURI); - Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); + UUID originID; + + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + + Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI); m_callbackURI = null; + //m_log.DebugFormat("[CompleteMovement] ReleaseAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); } - // else - // { - // m_log.DebugFormat( - // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", - // client.Name, client.AgentId, m_scene.RegionInfo.RegionName); - // } +// else +// { +// m_log.DebugFormat( +// "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", +// client.Name, client.AgentId, m_scene.RegionInfo.RegionName); +// } - ValidateAndSendAppearanceAndAgentData(); - // Create child agents in neighbouring regions - if (openChildAgents && !IsChildAgent) + // Tell the client that we're totally ready + ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); + //m_log.DebugFormat("[CompleteMovement] MoveAgentIntoRegion: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + bool isHGTP = (m_teleportFlags & TeleportFlags.ViaHGLogin) != 0; + + int delayctnr = Util.EnvironmentTickCount(); + + if (!IsChildAgent) { - IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); - if (m_agentTransfer != null) + if( ParentPart != null && !IsNPC && (crossingFlags & 0x08) != 0) { - // Note: this call can take a while, because it notifies each of the simulator's neighbours. - // It's important that we don't allow the avatar to cross regions meanwhile, as that will - // cause serious errors. We've prevented that from happening by setting IsInTransit=true. - m_agentTransfer.EnableChildAgents(this); + +// SceneObjectPart root = ParentPart.ParentGroup.RootPart; +// if(root.LocalId != ParentPart.LocalId) +// ControllingClient.SendEntityTerseUpdateImmediate(root); +// ControllingClient.SendEntityTerseUpdateImmediate(ParentPart); + ParentPart.ParentGroup.SendFullUpdateToClient(ControllingClient); } - IFriendsModule friendsModule = m_scene.RequestModuleInterface(); - if (friendsModule != null) - friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + // verify baked textures and cache + bool cachedbaked = false; + + if (IsNPC) + cachedbaked = true; + else + { + if (m_scene.AvatarFactory != null && !isHGTP) + cachedbaked = m_scene.AvatarFactory.ValidateBakedTextureCache(this); + + // not sure we need this + if (!cachedbaked) + { + if (m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(UUID); + } + } + //m_log.DebugFormat("[CompleteMovement] Baked check: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + } + + if(m_teleportFlags > 0) + { + gotCrossUpdate = false; // sanity check + if(Util.EnvironmentTickCountSubtract(delayctnr)< 500) + Thread.Sleep(500); // let viewers catch us + } + + if(!gotCrossUpdate) + RotateToLookAt(look); + + // HG + if(isHGTP) + { +// ControllingClient.SendNameReply(m_uuid, Firstname, Lastname); + m_log.DebugFormat("[CompleteMovement] HG"); + } + + m_previusParcelHide = false; + m_previusParcelUUID = UUID.Zero; + m_currentParcelHide = false; + m_currentParcelUUID = UUID.Zero; + ParcelDwellTickMS = Util.GetTimeStampMS(); + + if(!IsNPC) + { + GodController.SyncViewerState(); + + // start sending terrain patchs + if (!gotCrossUpdate) + Scene.SendLayerData(ControllingClient); + } + // send initial land overlay and parcel + ILandChannel landch = m_scene.LandChannel; + if (landch != null) + landch.sendClientInitialLandInfo(client); + + if (!IsChildAgent) + { + List allpresences = m_scene.GetScenePresences(); + + // send avatar object to all presences including us, so they cross it into region + // then hide if necessary + + SendInitialAvatarDataToAllAgents(allpresences); + + // send this look + SendAppearanceToAgent(this); + + // send this animations + + UUID[] animIDs = null; + int[] animseqs = null; + UUID[] animsobjs = null; + + if (Animator != null) + Animator.GetArrays(out animIDs, out animseqs, out animsobjs); + + bool haveAnims = (animIDs != null && animseqs != null && animsobjs != null); + + if (haveAnims) + SendAnimPackToAgent(this, animIDs, animseqs, animsobjs); + + // we should be able to receive updates, etc + // so release them + m_inTransit = false; + + // send look and animations to others + // if not cached we send greys + // uncomented if will wait till avatar does baking + //if (cachedbaked) + { + foreach (ScenePresence p in allpresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + SendAppearanceToAgentNF(p); + if (haveAnims) + SendAnimPackToAgentNF(p, animIDs, animseqs, animsobjs); + } + } // greys if + + //m_log.DebugFormat("[CompleteMovement] ValidateAndSendAppearanceAndAgentData: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + // attachments + if (IsNPC || IsRealLogin(m_teleportFlags)) + { + if (Scene.AttachmentsModule != null) + // Util.FireAndForget( + // o => + // { + + if (!IsNPC) + Scene.AttachmentsModule.RezAttachments(this); + else + Util.FireAndForget(x => + { + Scene.AttachmentsModule.RezAttachments(this); + }); + + // }); + } + else + { + if (m_attachments.Count > 0) + { + m_log.DebugFormat( + "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); + + foreach (SceneObjectGroup sog in m_attachments) + { + sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); + sog.ResumeScripts(); + } + + foreach (ScenePresence p in allpresences) + { + if (p == this) + { + SendAttachmentsToAgentNF(this); + continue; + } + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + SendAttachmentsToAgentNF(p); + } + } + } + //m_log.DebugFormat("[CompleteMovement] attachments: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + if (openChildAgents) + { + // Create child agents in neighbouring regions + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + { + m_agentTransfer.EnableChildAgents(this); + } + } + // let updates be sent, with some delay + m_lastChildUpdatesTime = Util.EnvironmentTickCount() + 10000; + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_lastChildAgentUpdateDrawDistance = DrawDistance; + m_lastChildAgentUpdatePosition = AbsolutePosition; + m_childUpdatesBusy = false; // allow them } - // XXX: If we force an update after activity has completed, then multiple attachments do appear correctly on a destination region - // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work. - // This may be due to viewer code or it may be something we're not doing properly simulator side. - WorkManager.RunJob( - "ScheduleAttachmentsForFullUpdate", - o => ScheduleAttachmentsForFullUpdate(), - null, - string.Format("Schedule attachments for full update for {0} in {1}", Name, Scene.Name), - true); + //m_log.DebugFormat("[CompleteMovement] openChildAgents: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + // send the rest of the world + if (m_teleportFlags > 0 && !IsNPC || m_currentParcelHide) + SendInitialDataToMe(); + + // priority uses avatar position only +// m_reprioritizationLastPosition = AbsolutePosition; +// m_reprioritizationLastDrawDistance = DrawDistance; +// m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it +// m_reprioritizationBusy = false; + + //m_log.DebugFormat("[CompleteMovement] SendInitialDataToMe: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + if (!IsChildAgent && openChildAgents) + { + IFriendsModule friendsModule = m_scene.RequestModuleInterface(); + if (friendsModule != null) + { + if(gotCrossUpdate) + friendsModule.IsNowRoot(this); + else + friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + } + //m_log.DebugFormat("[CompleteMovement] friendsModule: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - // m_log.DebugFormat( - // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", - // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); + } } finally { - IsInTransit = false; + haveGroupInformation = false; + gotCrossUpdate = false; + crossingFlags = 0; + m_inTransit = false; } - } + + m_scene.EventManager.OnRegionHeartbeatEnd += RegionHeartbeatEnd; - private void ScheduleAttachmentsForFullUpdate() - { - lock (m_attachments) - { - foreach (SceneObjectGroup sog in m_attachments) - sog.ScheduleGroupForFullUpdate(); - } + m_log.DebugFormat("[CompleteMovement] end: {0}ms", Util.EnvironmentTickCountSubtract(ts)); } /// @@ -1841,30 +2376,71 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - /// + /// - private void UpdateCameraCollisionPlane(Vector4 plane) + private void checkCameraCollision() { - if (m_lastCameraCollisionPlane != plane) + if(m_doingCamRayCast || !m_scene.PhysicsScene.SupportsRayCast()) + return; + + if(m_mouseLook || ParentID != 0) { - m_lastCameraCollisionPlane = plane; - ControllingClient.SendCameraConstraint(plane); + if (CameraConstraintActive) + { + Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... + UpdateCameraCollisionPlane(plane); + CameraConstraintActive = false; + } + return; } - } + + Vector3 posAdjusted = AbsolutePosition; + posAdjusted.Z += 1.0f; // viewer current camera focus point - public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal) - { - const float POSITION_TOLERANCE = 0.02f; - const float ROTATION_TOLERANCE = 0.02f; + if(posAdjusted.ApproxEquals(m_lastCameraRayCastPos, 0.2f) && + CameraPosition.ApproxEquals(m_lastCameraRayCastCam, 0.2f)) + return; - m_doingCamRayCast = false; - if (hitYN && localid != LocalId) - { - SceneObjectGroup group = m_scene.GetGroupByPrim(localid); - bool IsPrim = group != null; - if (IsPrim) + m_lastCameraRayCastCam = CameraPosition; + m_lastCameraRayCastPos = posAdjusted; + + Vector3 tocam = CameraPosition - posAdjusted; + + float distTocamlen = tocam.LengthSquared(); + if (distTocamlen > 0.01f && distTocamlen < 400) + { + distTocamlen = (float)Math.Sqrt(distTocamlen); + tocam *= (1.0f / distTocamlen); + + m_doingCamRayCast = true; + m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback); + return; + } + + if (CameraConstraintActive) + { + Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... + UpdateCameraCollisionPlane(plane); + CameraConstraintActive = false; + } + } + + private void UpdateCameraCollisionPlane(Vector4 plane) + { + if (m_lastCameraCollisionPlane != plane) + { + m_lastCameraCollisionPlane = plane; + ControllingClient.SendCameraConstraint(plane); + } + } + + public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal) + { + if (hitYN && localid != LocalId) + { + if (localid != 0) { - SceneObjectPart part = group.GetPart(localid); + SceneObjectPart part = m_scene.GetSceneObjectPart(localid); if (part != null && !part.VolumeDetectActive) { CameraConstraintActive = true; @@ -1897,13 +2473,14 @@ namespace OpenSim.Region.Framework.Scenes UpdateCameraCollisionPlane(plane); } } - else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || - !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) + else if(CameraConstraintActive) { Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -9000f); // not right... UpdateCameraCollisionPlane(plane); CameraConstraintActive = false; } + + m_doingCamRayCast = false; } /// @@ -1921,12 +2498,17 @@ namespace OpenSim.Region.Framework.Scenes return; } + if (IsInTransit) + return; + #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { - RemoveFromPhysicalScene(); + bool isphysical = PhysicsActor != null; + if(isphysical) + RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); m_pos = m_LastFinitePos; @@ -1938,7 +2520,8 @@ namespace OpenSim.Region.Framework.Scenes m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); } - AddToPhysicalScene(false); + if(isphysical) + AddToPhysicalScene(false); } else { @@ -1953,18 +2536,18 @@ namespace OpenSim.Region.Framework.Scenes // The Agent's Draw distance setting // When we get to the point of re-computing neighbors everytime this - // changes, then start using the agent's drawdistance rather than the + // changes, then start using the agent's drawdistance rather than the // region's draw distance. + DrawDistance = agentData.Far; - // DrawDistance = Scene.DefaultDrawDistance; m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; // FIXME: This does not work as intended because the viewer only sends the lbutton down when the button // is first pressed, not whilst it is held down. If this is required in the future then need to look - // for an AGENT_CONTROL_LBUTTON_UP event and make sure to handle cases where an initial DOWN is not + // for an AGENT_CONTROL_LBUTTON_UP event and make sure to handle cases where an initial DOWN is not // received (e.g. on holding LMB down on the avatar in a viewer). -// m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; + m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; #endregion Inputs @@ -1977,6 +2560,7 @@ namespace OpenSim.Region.Framework.Scenes // (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) // m_updateCount = UPDATE_COUNT; + if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(); @@ -1984,38 +2568,8 @@ namespace OpenSim.Region.Framework.Scenes // Raycast from the avatar's head to the camera to see if there's anything blocking the view // this exclude checks may not be complete - - if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast()) - { - if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0) - { - Vector3 posAdjusted = AbsolutePosition; -// posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f; - posAdjusted.Z += 1.0f; // viewer current camera focus point - Vector3 tocam = CameraPosition - posAdjusted; - tocam.X = (float)Math.Round(tocam.X, 1); - tocam.Y = (float)Math.Round(tocam.Y, 1); - tocam.Z = (float)Math.Round(tocam.Z, 1); - - float distTocamlen = tocam.Length(); - if (distTocamlen > 0.3f) - { - tocam *= (1.0f / distTocamlen); - posAdjusted.X = (float)Math.Round(posAdjusted.X, 1); - posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1); - posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1); - - m_doingCamRayCast = true; - m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback); - } - } - else if (CameraConstraintActive && (m_mouseLook || ParentID != 0)) - { - Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... - UpdateCameraCollisionPlane(plane); - CameraConstraintActive = false; - } - } + if(agentData.NeedsCameraCollision) // condition parentID may be wrong + checkCameraCollision(); uint flagsForScripts = (uint)flags; flags = RemoveIgnoredControls(flags, IgnoredControls); @@ -2032,7 +2586,7 @@ namespace OpenSim.Region.Framework.Scenes // We need to send this back to the client in order to stop the edit beams if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None) - ControllingClient.SendAgentTerseUpdate(this); + SendAgentTerseUpdate(this); PhysicsActor actor = PhysicsActor; @@ -2046,9 +2600,7 @@ namespace OpenSim.Region.Framework.Scenes if (AllowMovement && !SitGround) { // m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name); - bool update_rotation = false; - if (agentData.BodyRotation != Rotation) { Rotation = agentData.BodyRotation; @@ -2056,31 +2608,26 @@ namespace OpenSim.Region.Framework.Scenes } bool update_movementflag = false; - - // If we were just made root agent then we must perform movement updates for the first AgentUpdate that - // we get - if (MovementFlag == ForceUpdateMovementFlagValue) - { - MovementFlag = 0; - update_movementflag = true; - } - + bool mvToTarget = m_movingToTarget; if (agentData.UseClientAgentPosition) { - MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; - MoveToPositionTarget = agentData.ClientAgentPosition; + m_movingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).LengthSquared() > 0.04f; + m_moveToPositionTarget = agentData.ClientAgentPosition; + m_moveToSpeed = -1f; } int i = 0; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; - bool newFlying = actor.Flying; + bool newFlying = false; if (ForceFly) newFlying = true; else if (FlyDisabled) newFlying = false; + else if(mvToTarget) + newFlying = actor.Flying; else newFlying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); @@ -2096,6 +2643,15 @@ namespace OpenSim.Region.Framework.Scenes { bool bAllowUpdateMoveToPosition = false; + Vector3[] dirVectors; + + // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying + // this prevents 'jumping' in inappropriate situations. +// if (!Flying && (m_mouseLook || m_leftButtonDown)) +// dirVectors = GetWalkDirectionVectors(); +// else + dirVectors = Dir_Vectors; + // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { @@ -2105,9 +2661,7 @@ namespace OpenSim.Region.Framework.Scenes try { - // Don't slide against ground when crouching if camera is panned around avatar - if (Flying || DCF != Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN) - agent_control_v3 += Dir_Vectors[i]; + agent_control_v3 += Dir_Vectors[i]; //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); } catch (IndexOutOfRangeException) @@ -2115,10 +2669,10 @@ namespace OpenSim.Region.Framework.Scenes // Why did I get this? } - if (((MovementFlag & (uint)DCF) == 0) & !AgentControlStopActive) - { + if (((MovementFlag & (uint)DCF) == 0)) + { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); - MovementFlag += (uint)DCF; + MovementFlag |= (uint)DCF; update_movementflag = true; } } @@ -2127,7 +2681,7 @@ namespace OpenSim.Region.Framework.Scenes if ((MovementFlag & (uint)DCF) != 0) { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); - MovementFlag -= (uint)DCF; + MovementFlag &= (uint)~DCF; update_movementflag = true; /* @@ -2154,7 +2708,7 @@ namespace OpenSim.Region.Framework.Scenes update_movementflag = true; } - if (MovingToTarget) + if (m_movingToTarget) { // If the user has pressed a key then we want to cancel any move to target. if (DCFlagKeyPressed) @@ -2167,7 +2721,7 @@ namespace OpenSim.Region.Framework.Scenes // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a // certain position. It's only check for tolerance on returning to that position is 0.2 // rather than 1, at which point it removes its force target. - if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2 : 1, ref agent_control_v3)) + if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2f : 1f, ref agent_control_v3)) update_movementflag = true; } } @@ -2180,11 +2734,11 @@ namespace OpenSim.Region.Framework.Scenes if (Flying && !ForceFly) { // Need to stop in mid air if user holds down AGENT_CONTROL_STOP - if (AgentControlStopActive) - { - agent_control_v3 = Vector3.Zero; - } - else + // if (AgentControlStopActive) + // { + // agent_control_v3 = Vector3.Zero; + // } + // else { // Landing detection code @@ -2192,38 +2746,43 @@ namespace OpenSim.Region.Framework.Scenes bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); - //m_log.Debug("[CONTROL]: " +flags); + //m_log.Debug("[CONTROL]: " +flags); // Applies a satisfying roll effect to the avatar when flying. if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) { ApplyFlyingRoll( - FLY_ROLL_RADIANS_PER_UPDATE, - (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, + FLY_ROLL_RADIANS_PER_UPDATE, + (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); - } + } else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) { ApplyFlyingRoll( - -FLY_ROLL_RADIANS_PER_UPDATE, - (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, - (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); + -FLY_ROLL_RADIANS_PER_UPDATE, + (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, + (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); } else { if (m_AngularVelocity.Z != 0) - m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); - } - - if (Flying && IsColliding && controlland) - { - // nesting this check because LengthSquared() is expensive and we don't - // want to do it every step when flying. - if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) - StopFlying(); + m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); } + + /* + if (Flying && IsColliding && controlland) + { + // nesting this check because LengthSquared() is expensive and we don't + // want to do it every step when flying. + if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) + StopFlying(); + } + */ } } + else if (IsColliding && agent_control_v3.Z < 0f) + agent_control_v3.Z = 0; +// else if(AgentControlStopActive %% Velocity.Z <0.01f) // m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name); @@ -2231,54 +2790,60 @@ namespace OpenSim.Region.Framework.Scenes // which occurs later in the main scene loop // We also need to update if the user rotates their avatar whilst it is slow walking/running (if they // held down AGENT_CONTROL_STOP whilst normal walking/running). However, we do not want to update - // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the + // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the // avatar location in place). - if (update_movementflag + + if (update_movementflag || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0))) { -// if (update_movementflag || !AgentControlStopActive || MovementFlag != 0) -// { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, mf = {4}, ur = {5}", -// m_scene.RegionInfo.RegionName, agent_control_v3, Name, -// update_movementflag, MovementFlag, update_rotation); - float speedModifier; - - if (AgentControlStopActive) - speedModifier = AgentControlStopSlowWhilstMoving; + if (AgentControlStopActive) + { + // if (MovementFlag == 0 && Animator.Falling) + if (MovementFlag == 0 && Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling) + { + AddNewMovement(agent_control_v3, AgentControlStopSlowVel, true); + } else - speedModifier = 1; - - AddNewMovement(agent_control_v3, speedModifier); -// } + AddNewMovement(agent_control_v3, AgentControlStopSlowVel); + } + else + { + if(m_movingToTarget || + (Animator.currentControlState != ScenePresenceAnimator.motionControlStates.flying && + Animator.currentControlState != ScenePresenceAnimator.motionControlStates.onsurface) + ) + AddNewMovement(agent_control_v3); + else + { + if (MovementFlag != 0) + AddNewMovement(agent_control_v3); + else + m_delayedStop = Util.GetTimeStampMS() + 200.0; + } + } } -// else -// { -// if (!update_movementflag) -// { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: In {0} ignoring requested update of {1} for {2} as update_movementflag = false", -// m_scene.RegionInfo.RegionName, agent_control_v3, Name); -// } -// } - - if (update_movementflag && ParentID == 0) +/* + if (update_movementflag && ParentID == 0 && m_delayedStop < 0) { // m_log.DebugFormat("[SCENE PRESENCE]: Updating movement animations for {0}", Name); Animator.UpdateMovementAnimations(); } - +*/ SendControlsToScripts(flagsForScripts); } // We need to send this back to the client in order to see the edit beams if ((State & (uint)AgentState.Editing) != 0) - ControllingClient.SendAgentTerseUpdate(this); + SendAgentTerseUpdate(this); - m_scene.EventManager.TriggerOnClientMovement(this); +// m_scene.EventManager.TriggerOnClientMovement(this); } + private void HandleAgentFOV(IClientAPI remoteClient, float _fov) + { + m_FOV = _fov; + } /// /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering. @@ -2290,60 +2855,37 @@ namespace OpenSim.Region.Framework.Scenes // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); if (IsChildAgent) - { - // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); return; - } - ++m_movementUpdateCount; - if (m_movementUpdateCount < 1) - m_movementUpdateCount = 1; + if(IsInTransit) + return; // AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; // Camera location in world. We'll need to raytrace // from this location from time to time. CameraPosition = agentData.CameraCenter; - if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance) - { - ReprioritizeUpdates(); - m_lastCameraPosition = CameraPosition; - } - // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion + + // this may need lock CameraAtAxis = agentData.CameraAtAxis; CameraLeftAxis = agentData.CameraLeftAxis; CameraUpAxis = agentData.CameraUpAxis; - - // The Agent's Draw distance setting - // When we get to the point of re-computing neighbors everytime this - // changes, then start using the agent's drawdistance rather than the - // region's draw distance. DrawDistance = agentData.Far; - // DrawDistance = Scene.DefaultDrawDistance; - - // Check if Client has camera in 'follow cam' or 'build' mode. - Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation); - - m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f) - && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false; + CameraAtAxis.Normalize(); + CameraLeftAxis.Normalize(); + CameraUpAxis.Normalize(); + Quaternion camRot = Util.Axes2Rot(CameraAtAxis, CameraLeftAxis, CameraUpAxis); + CameraRotation = camRot; - //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto); - // Raycast from the avatar's head to the camera to see if there's anything blocking the view - if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast()) - { - if (m_followCamAuto) - { - Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT; - m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback); - } - } + if(agentData.NeedsCameraCollision) + checkCameraCollision(); TriggerScenePresenceUpdated(); } - + /// /// Calculate an update to move the presence to the set target. /// @@ -2352,125 +2894,158 @@ namespace OpenSim.Region.Framework.Scenes /// /// Cumulative agent movement that this method will update. /// True if movement has been updated in some way. False otherwise. - public bool HandleMoveToTargetUpdate(double tolerance, ref Vector3 agent_control_v3) + public bool HandleMoveToTargetUpdate(float tolerance, ref Vector3 agent_control_v3) { // m_log.DebugFormat("[SCENE PRESENCE]: Called HandleMoveToTargetUpdate() for {0}", Name); bool updated = false; + Vector3 LocalVectorToTarget3D = m_moveToPositionTarget - AbsolutePosition; + // m_log.DebugFormat( // "[SCENE PRESENCE]: bAllowUpdateMoveToPosition {0}, m_moveToPositionInProgress {1}, m_autopilotMoving {2}", // allowUpdate, m_moveToPositionInProgress, m_autopilotMoving); - double distanceToTarget = Util.GetDistanceTo(AbsolutePosition, MoveToPositionTarget); + float distanceToTarget; + if(Flying && !LandAtTarget) + { + distanceToTarget = LocalVectorToTarget3D.Length(); + } + else + { + distanceToTarget = (float)Math.Sqrt(LocalVectorToTarget3D.X * LocalVectorToTarget3D.X + + LocalVectorToTarget3D.Y * LocalVectorToTarget3D.Y); + } -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}", -// Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget); + // m_log.DebugFormat( + // "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}", + // Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget); // Check the error term of the current position in relation to the target position if (distanceToTarget <= tolerance) { // We are close enough to the target - AbsolutePosition = MoveToPositionTarget; + Velocity = Vector3.Zero; + AbsolutePosition = m_moveToPositionTarget; + if (Flying) + { + if (LandAtTarget) + Flying = false; + + // A horrible hack to stop the avatar dead in its tracks rather than having them overshoot + // the target if flying. + // We really need to be more subtle (slow the avatar as it approaches the target) or at + // least be able to set collision status once, rather than 5 times to give it enough + // weighting so that that PhysicsActor thinks it really is colliding. + for (int i = 0; i < 5; i++) + IsColliding = true; + } ResetMoveToTarget(); - updated = true; + return false; } - else + + if(m_moveToSpeed > 0 && distanceToTarget <= m_moveToSpeed * Scene.FrameTime) + m_moveToSpeed = distanceToTarget / Scene.FrameTime; + + try { - try - { - // move avatar in 3D at one meter/second towards target, in avatar coordinate frame. - // This movement vector gets added to the velocity through AddNewMovement(). - // Theoretically we might need a more complex PID approach here if other - // unknown forces are acting on the avatar and we need to adaptively respond - // to such forces, but the following simple approach seems to works fine. - Vector3 LocalVectorToTarget3D = - (MoveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords - * Matrix4.CreateFromQuaternion(Quaternion.Inverse(Rotation)); // change to avatar coords - // Ignore z component of vector -// Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); - LocalVectorToTarget3D.Normalize(); - - // update avatar movement flags. the avatar coordinate system is as follows: - // - // +X (forward) - // - // ^ - // | - // | - // | - // | - // (left) +Y <--------o--------> -Y - // avatar - // | - // | - // | - // | - // v - // -X - // + // move avatar in 3D towards target, in avatar coordinate frame. + // This movement vector gets added to the velocity through AddNewMovement(). + // Theoretically we might need a more complex PID approach here if other + // unknown forces are acting on the avatar and we need to adaptively respond + // to such forces, but the following simple approach seems to works fine. - // based on the above avatar coordinate system, classify the movement into - // one of left/right/back/forward. - if (LocalVectorToTarget3D.X < 0) //MoveBack - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; - updated = true; - } - else if (LocalVectorToTarget3D.X > 0) //Move Forward - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; - updated = true; - } + float angle = 0.5f * (float)Math.Atan2(LocalVectorToTarget3D.Y, LocalVectorToTarget3D.X); + Quaternion rot = new Quaternion(0,0, (float)Math.Sin(angle),(float)Math.Cos(angle)); + Rotation = rot; + LocalVectorToTarget3D = LocalVectorToTarget3D * Quaternion.Inverse(rot); // change to avatar coords + LocalVectorToTarget3D.Normalize(); - if (LocalVectorToTarget3D.Y > 0) //MoveLeft - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; - updated = true; - } - else if (LocalVectorToTarget3D.Y < 0) //MoveRight - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; - updated = true; - } + // update avatar movement flags. the avatar coordinate system is as follows: + // + // +X (forward) + // + // ^ + // | + // | + // | + // | + // (left) +Y <--------o--------> -Y + // avatar + // | + // | + // | + // | + // v + // -X + // - if (LocalVectorToTarget3D.Z > 0) //Up - { - // Don't set these flags for up or down - doing so will make the avatar crouch or - // keep trying to jump even if walking along level ground - //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; - //AgentControlFlags - //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; - updated = true; - } - else if (LocalVectorToTarget3D.Z < 0) //Down - { - //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; - //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; - updated = true; - } + // based on the above avatar coordinate system, classify the movement into + // one of left/right/back/forward. + + const uint noMovFlagsMask = (uint)(~(Dir_ControlFlags.DIR_CONTROL_FLAG_BACK | + Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD | Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT | + Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT | Dir_ControlFlags.DIR_CONTROL_FLAG_UP | + Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN)); + + MovementFlag &= noMovFlagsMask; + uint tmpAgentControlFlags = (uint)m_AgentControlFlags; + tmpAgentControlFlags &= noMovFlagsMask; + if (LocalVectorToTarget3D.X < 0) //MoveBack + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; + updated = true; + } + else if (LocalVectorToTarget3D.X > 0) //Move Forward + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; + updated = true; + } + + if (LocalVectorToTarget3D.Y > 0) //MoveLeft + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; + updated = true; + } + else if (LocalVectorToTarget3D.Y < 0) //MoveRight + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; + updated = true; + } + + if (LocalVectorToTarget3D.Z > 0) //Up + updated = true; + + else if (LocalVectorToTarget3D.Z < 0) //Down + updated = true; + // m_log.DebugFormat( // "[SCENE PRESENCE]: HandleMoveToTargetUpdate adding {0} to move vector {1} for {2}", // LocalVectorToTarget3D, agent_control_v3, Name); + m_AgentControlFlags = (AgentManager.ControlFlags) tmpAgentControlFlags; + if(updated) agent_control_v3 += LocalVectorToTarget3D; - } - catch (Exception e) - { - //Avoid system crash, can be slower but... - m_log.DebugFormat("Crash! {0}", e.ToString()); - } + } + catch (Exception e) + { + //Avoid system crash, can be slower but... + m_log.DebugFormat("Crash! {0}", e.ToString()); } return updated; +// AddNewMovement(agent_control_v3); } + public void MoveToTargetHandle(Vector3 pos, bool noFly, bool landAtTarget) + { + MoveToTarget(pos, noFly, landAtTarget); + } /// /// Move to the given target over time. /// @@ -2483,8 +3058,10 @@ namespace OpenSim.Region.Framework.Scenes /// /// If true and the avatar starts flying during the move then land at the target. /// - public void MoveToTarget(Vector3 pos, bool noFly, bool landAtTarget) - { + public void MoveToTarget(Vector3 pos, bool noFly, bool landAtTarget, float tau = -1f) + { + m_delayedStop = -1; + if (SitGround) StandUp(); @@ -2494,89 +3071,61 @@ namespace OpenSim.Region.Framework.Scenes // Allow move to another sub-region within a megaregion Vector2 regionSize; - IRegionCombinerModule regionCombinerModule = m_scene.RequestModuleInterface(); - if (regionCombinerModule != null) - regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); - else - regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY); + regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY); if (pos.X < 0 || pos.X >= regionSize.X || pos.Y < 0 || pos.Y >= regionSize.Y || pos.Z < 0) return; + float terrainHeight; Scene targetScene = m_scene; + terrainHeight = m_scene.GetGroundHeight(pos.X, pos.Y); -// Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2); -// pos += heightAdjust; -// -// // Anti duck-walking measure -// if (Math.Abs(pos.Z - AbsolutePosition.Z) < 0.2f) -// { -//// m_log.DebugFormat("[SCENE PRESENCE]: Adjusting MoveToPosition from {0} to {1}", pos, AbsolutePosition); -// pos.Z = AbsolutePosition.Z; -// } - - // Get terrain height for sub-region in a megaregion if necessary - - //COMMENT: If its only nessesary in a megaregion, why do it on normal region's too? - - if (regionCombinerModule != null) - { - int x = (int)((m_scene.RegionInfo.WorldLocX) + pos.X); - int y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y); - GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, x, y); - - // If X and Y is NaN, target_region will be null - if (target_region == null) - return; - - SceneManager.Instance.TryGetScene(target_region.RegionID, out targetScene); - } - - float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)]; - pos.Z = Math.Max(terrainHeight, pos.Z); + // dont try to land underground + terrainHeight += Appearance.AvatarHeight * 0.5f + 0.2f; - // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is - // always slightly higher than the actual terrain height. - // FIXME: This constrains NPC movements as well, so should be somewhere else. - if (pos.Z - terrainHeight < 0.2) + if(terrainHeight > pos.Z) pos.Z = terrainHeight; - if (noFly) - Flying = false; - else if (pos.Z > terrainHeight) - Flying = true; - // m_log.DebugFormat( // "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}", // Name, pos, terrainHeight, m_scene.RegionInfo.RegionName); - if (noFly) - Flying = false; - - LandAtTarget = landAtTarget; - MovingToTarget = true; - MoveToPositionTarget = pos; + terrainHeight += Appearance.AvatarHeight; // so 1.5 * AvatarHeight above ground at target + bool shouldfly = Flying; + if (noFly) + shouldfly = false; + else if (pos.Z > terrainHeight || Flying) + shouldfly = true; - // Rotate presence around the z-axis to point in same direction as movement. - // Ignore z component of vector Vector3 localVectorToTarget3D = pos - AbsolutePosition; - Vector3 localVectorToTarget2D = new Vector3((float)(localVectorToTarget3D.X), (float)(localVectorToTarget3D.Y), 0f); -// m_log.DebugFormat("[SCENE PRESENCE]: Local vector to target is {0}", localVectorToTarget2D); +// m_log.DebugFormat("[SCENE PRESENCE]: Local vector to target is {0},[1}", localVectorToTarget3D.X,localVectorToTarget3D.Y); + + m_movingToTarget = true; + LandAtTarget = landAtTarget; + m_moveToPositionTarget = pos; + if(tau > 0) + { + if(tau < Scene.FrameTime) + tau = Scene.FrameTime; + m_moveToSpeed = localVectorToTarget3D.Length() / tau; + if(m_moveToSpeed < 0.5f) //to tune + m_moveToSpeed = 0.5f; + else if(m_moveToSpeed > 50f) + m_moveToSpeed = 50f; - // Calculate the yaw. - Vector3 angle = new Vector3(0, 0, (float)(Math.Atan2(localVectorToTarget2D.Y, localVectorToTarget2D.X))); + SetAlwaysRun = false; + } + else + m_moveToSpeed = 4.096f * m_speedModifier; -// m_log.DebugFormat("[SCENE PRESENCE]: Angle is {0}", angle); + Flying = shouldfly; - Rotation = Quaternion.CreateFromEulers(angle); -// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, Rotation); - - Vector3 agent_control_v3 = new Vector3(); - HandleMoveToTargetUpdate(1, ref agent_control_v3); - AddNewMovement(agent_control_v3); + Vector3 control = Vector3.Zero; + if(HandleMoveToTargetUpdate(1f, ref control)) + AddNewMovement(control); } /// @@ -2586,9 +3135,11 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name); - MovingToTarget = false; + m_movingToTarget = false; + m_moveToSpeed = -1f; // MoveToPositionTarget = Vector3.Zero; - m_forceToApply = null; // cancel possible last action +// lock(m_forceToApplyLock) +// m_forceToApplyValid = false; // cancel possible last action // We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct // resting animation (e.g. hover or stand). NPCs don't have a client that will quickly reset this flag. @@ -2629,69 +3180,65 @@ namespace OpenSim.Region.Framework.Scenes } } +// part.ParentGroup.DeleteAvatar(UUID); + + Quaternion standRotation = part.ParentGroup.RootPart.RotationOffset; + Vector3 sitPartWorldPosition = part.ParentGroup.AbsolutePosition + m_pos * standRotation; ControllingClient.SendClearFollowCamProperties(part.ParentUUID); ParentID = 0; ParentPart = null; - Quaternion standRotation; - if (part.SitTargetAvatar == UUID) - { - standRotation = part.GetWorldRotation(); + standRotation = standRotation * part.SitTargetOrientation; + else + standRotation = standRotation * m_bodyRot; - if (!part.IsRoot) - standRotation = standRotation * part.SitTargetOrientation; -// standRotation = part.RotationOffset * part.SitTargetOrientation; -// else -// standRotation = part.SitTargetOrientation; + m_bodyRot = standRotation; + Quaternion standRotationZ = new Quaternion(0,0,standRotation.Z,standRotation.W); + + float t = standRotationZ.W * standRotationZ.W + standRotationZ.Z * standRotationZ.Z; + if (t > 0) + { + t = 1.0f / (float)Math.Sqrt(t); + standRotationZ.W *= t; + standRotationZ.Z *= t; } else { - standRotation = Rotation; + standRotationZ.W = 1.0f; + standRotationZ.Z = 0f; } - //Vector3 standPos = ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight); - //Vector3 standPos = ParentPosition; - -// Vector3 standPositionAdjustment -// = part.SitTargetPosition + new Vector3(0.5f, 0f, m_sitAvatarHeight / 2f); - Vector3 adjustmentForSitPosition = OffsetPosition * part.ParentGroup.GroupRotation - SIT_TARGET_ADJUSTMENT * part.GetWorldRotation(); - - // XXX: This is based on the physics capsule sizes. Need to find a better way to read this rather than - // hardcoding here. - Vector3 adjustmentForSitPose = new Vector3(0.74f, 0f, 0f) * standRotation; + Vector3 adjustmentForSitPose = new Vector3(0.75f, 0, m_sitAvatarHeight + .3f) * standRotationZ; - Vector3 standPos = part.ParentGroup.AbsolutePosition + adjustmentForSitPosition + adjustmentForSitPose; + Vector3 standPos = sitPartWorldPosition + adjustmentForSitPose; + m_pos = standPos; -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Setting stand to pos {0}, (adjustmentForSitPosition {1}, adjustmentForSitPose {2}) rotation {3} for {4} in {5}", -// standPos, adjustmentForSitPosition, adjustmentForSitPose, standRotation, Name, Scene.Name); - - Rotation = standRotation; - AbsolutePosition = standPos; } - // We need to wait until we have calculated proper stand positions before sitting up the physical + // We need to wait until we have calculated proper stand positions before sitting up the physical // avatar to avoid race conditions. if (PhysicsActor == null) AddToPhysicalScene(false); if (satOnObject) { - SendAvatarDataToAllClients(); m_requestedSitTargetID = 0; - part.RemoveSittingAvatar(this); - part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); + + SendAvatarDataToAllAgents(); + m_scene.EventManager.TriggerParcelPrimCountTainted(); // update select/ sat on } - else if (PhysicsActor == null) - AddToPhysicalScene(false); + // reset to default sitAnimation + sitAnimation = "SIT"; + +// Animator.TrySetMovementAnimation("STAND"); + Animator.SetMovementAnimations("STAND"); - Animator.TrySetMovementAnimation("STAND"); TriggerScenePresenceUpdated(); } @@ -2746,28 +3293,14 @@ namespace OpenSim.Region.Framework.Scenes if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied", -// Name, part.Name, part.LocalId); - offset = part.SitTargetPosition; sitOrientation = part.SitTargetOrientation; - if (!part.IsRoot) - { - // m_log.DebugFormat("Old sit orient {0}", sitOrientation); - sitOrientation = part.RotationOffset * sitOrientation; - // m_log.DebugFormat("New sit orient {0}", sitOrientation); -// m_log.DebugFormat("Old sit offset {0}", offset); - offset = offset * part.RotationOffset; -// m_log.DebugFormat("New sit offset {0}", offset); - } - canSit = true; } else { - if (PhysicsSit(part,offset)) // physics engine + if (PhysicsSit(part,offset)) // physics engine return; Vector3 pos = part.AbsolutePosition + offset; @@ -2781,55 +3314,45 @@ namespace OpenSim.Region.Framework.Scenes if (canSit) { - if (PhysicsActor != null) { // We can remove the physicsActor until they stand up. RemoveFromPhysicalScene(); } - if (MovingToTarget) + if (m_movingToTarget) ResetMoveToTarget(); Velocity = Vector3.Zero; + m_AngularVelocity = Vector3.Zero; part.AddSittingAvatar(this); cameraAtOffset = part.GetCameraAtOffset(); - - if (!part.IsRoot && cameraAtOffset == Vector3.Zero) - cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); - - bool cameraEyeOffsetFromRootForChild = false; cameraEyeOffset = part.GetCameraEyeOffset(); - if (!part.IsRoot && cameraEyeOffset == Vector3.Zero) - { - cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); - cameraEyeOffsetFromRootForChild = true; - } + forceMouselook = part.GetForceMouselook(); - if ((cameraEyeOffset != Vector3.Zero && !cameraEyeOffsetFromRootForChild) || cameraAtOffset != Vector3.Zero) + if (!part.IsRoot) { - if (!part.IsRoot) + sitOrientation = part.RotationOffset * sitOrientation; + offset = offset * part.RotationOffset; + offset += part.OffsetPosition; + + if (cameraAtOffset == Vector3.Zero && cameraEyeOffset == Vector3.Zero) { - cameraEyeOffset = cameraEyeOffset * part.RotationOffset; + cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); + cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); + } + else + { + cameraAtOffset = cameraAtOffset * part.RotationOffset; cameraAtOffset += part.OffsetPosition; + cameraEyeOffset = cameraEyeOffset * part.RotationOffset; + cameraEyeOffset += part.OffsetPosition; } - - cameraEyeOffset += part.OffsetPosition; } -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Using cameraAtOffset {0}, cameraEyeOffset {1} for sit on {2} by {3} in {4}", -// cameraAtOffset, cameraEyeOffset, part.Name, Name, Scene.Name); - - forceMouselook = part.GetForceMouselook(); - - // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is - // being sat upon. - offset += part.OffsetPosition; - ControllingClient.SendSitResponse( part.ParentGroup.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); @@ -2840,6 +3363,7 @@ namespace OpenSim.Region.Framework.Scenes // Moved here to avoid a race with default sit anim // The script event needs to be raised after the default sit anim is set. part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); + m_scene.EventManager.TriggerParcelPrimCountTainted(); // update select/ sat on } } @@ -2862,7 +3386,6 @@ namespace OpenSim.Region.Framework.Scenes { m_requestedSitTargetID = part.LocalId; m_requestedSitTargetUUID = part.UUID; - } else { @@ -2875,13 +3398,8 @@ namespace OpenSim.Region.Framework.Scenes // returns false if does not suport so older sit can be tried public bool PhysicsSit(SceneObjectPart part, Vector3 offset) { -// TODO: Pull in these bits - return false; -/* if (part == null || part.ParentGroup.IsAttachment) - { return true; - } if ( m_scene.PhysicsScene == null) return false; @@ -2893,24 +3411,20 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); else { // non physical phantom TODO - ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); +// ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); return false; } return true; } - - // not doing autopilot - m_requestedSitTargetID = 0; - if (m_scene.PhysicsScene.SitAvatar(part.PhysActor, AbsolutePosition, CameraPosition, offset, new Vector3(0.35f, 0, 0.65f), PhysicsSitResponse) != 0) + { return true; + } return false; -*/ } - private bool CanEnterLandPosition(Vector3 testPos) { ILandObject land = m_scene.LandChannel.GetLandObject(testPos.X, testPos.Y); @@ -2939,7 +3453,7 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) return; - Vector3 targetPos = part.GetWorldPosition() + offset * part.GetWorldRotation(); + Vector3 targetPos = part.GetWorldPosition() + offset * part.GetWorldRotation(); if(!CanEnterLandPosition(targetPos)) { ControllingClient.SendAlertMessage(" Sit position on restricted land, try another spot"); @@ -2948,36 +3462,58 @@ namespace OpenSim.Region.Framework.Scenes RemoveFromPhysicalScene(); - if (MovingToTarget) + if (m_movingToTarget) ResetMoveToTarget(); Velocity = Vector3.Zero; + m_AngularVelocity = Vector3.Zero; + m_requestedSitTargetID = 0; part.AddSittingAvatar(this); + ParentPart = part; + ParentID = part.LocalId; + Vector3 cameraAtOffset = part.GetCameraAtOffset(); Vector3 cameraEyeOffset = part.GetCameraEyeOffset(); bool forceMouselook = part.GetForceMouselook(); - ControllingClient.SendSitResponse( - part.UUID, offset, Orientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); + if (!part.IsRoot) + { + Orientation = part.RotationOffset * Orientation; + offset = offset * part.RotationOffset; + offset += part.OffsetPosition; - // not using autopilot + if (cameraAtOffset == Vector3.Zero && cameraEyeOffset == Vector3.Zero) + { + cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); + cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); + } + else + { + cameraAtOffset = cameraAtOffset * part.RotationOffset; + cameraAtOffset += part.OffsetPosition; + cameraEyeOffset = cameraEyeOffset * part.RotationOffset; + cameraEyeOffset += part.OffsetPosition; + } + } - Rotation = Orientation; + m_bodyRot = Orientation; m_pos = offset; - m_requestedSitTargetID = 0; + ControllingClient.SendSitResponse( + part.ParentGroup.UUID, offset, Orientation, true, cameraAtOffset, cameraEyeOffset, forceMouselook); - ParentPart = part; - ParentID = part.LocalId; - if(status == 3) - Animator.TrySetMovementAnimation("SIT_GROUND"); + SendAvatarDataToAllAgents(); + + if (status == 3) + sitAnimation = "SIT_GROUND"; else - Animator.TrySetMovementAnimation("SIT"); - SendAvatarDataToAllClients(); + sitAnimation = "SIT"; + Animator.SetMovementAnimations("SIT"); part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); + m_scene.EventManager.TriggerParcelPrimCountTainted(); // update select/ sat on } public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) @@ -2985,7 +3521,7 @@ namespace OpenSim.Region.Framework.Scenes if (IsChildAgent) return; - SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); + SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); if (part != null) { @@ -3007,45 +3543,77 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: Sitting {0} at sit target {1}, {2} on {3} {4}", // Name, sitTargetPos, sitTargetOrient, part.Name, part.LocalId); - //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0); - //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w); - - //Quaternion result = (sitTargetOrient * vq) * nq; + double x, y, z, m; + Vector3 sitOffset; + Quaternion r = sitTargetOrient; - double x, y, z, m1, m2; + Vector3 newPos; - Quaternion r = sitTargetOrient; - m1 = r.X * r.X + r.Y * r.Y; - m2 = r.Z * r.Z + r.W * r.W; - - // Rotate the vector <0, 0, 1> - x = 2 * (r.X * r.Z + r.Y * r.W); - y = 2 * (-r.X * r.W + r.Y * r.Z); - z = m2 - m1; - - // Set m to be the square of the norm of r. - double m = m1 + m2; - - // This constant is emperically determined to be what is used in SL. - // See also http://opensimulator.org/mantis/view.php?id=7096 - double offset = 0.05; - - // Normally m will be ~ 1, but if someone passed a handcrafted quaternion - // to llSitTarget with values so small that squaring them is rounded off - // to zero, then m could be zero. The result of this floating point - // round off error (causing us to skip this impossible normalization) - // is only 5 cm. - if (m > 0.000001) + if (LegacySitOffsets) { - offset /= m; + double m1,m2; + + m1 = r.X * r.X + r.Y * r.Y; + m2 = r.Z * r.Z + r.W * r.W; + + // Rotate the vector <0, 0, 1> + x = 2 * (r.X * r.Z + r.Y * r.W); + y = 2 * (-r.X * r.W + r.Y * r.Z); + z = m2 - m1; + + // Set m to be the square of the norm of r. + m = m1 + m2; + + // This constant is emperically determined to be what is used in SL. + // See also http://opensimulator.org/mantis/view.php?id=7096 + double offset = 0.05; + + // Normally m will be ~ 1, but if someone passed a handcrafted quaternion + // to llSitTarget with values so small that squaring them is rounded off + // to zero, then m could be zero. The result of this floating point + // round off error (causing us to skip this impossible normalization) + // is only 5 cm. + if (m > 0.000001) + { + offset /= m; + } + + Vector3 up = new Vector3((float)x, (float)y, (float)z); + sitOffset = up * (float)offset; + newPos = sitTargetPos - sitOffset + SIT_TARGET_ADJUSTMENT; } + else + { + m = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W; + + if (Math.Abs(1.0 - m) > 0.000001) + { + if(m != 0) + { + m = 1.0 / Math.Sqrt(m); + r.X *= (float)m; + r.Y *= (float)m; + r.Z *= (float)m; + r.W *= (float)m; + } + else + { + r.X = 0.0f; + r.Y = 0.0f; + r.Z = 0.0f; + r.W = 1.0f; + m = 1.0f; + } + } - Vector3 up = new Vector3((float)x, (float)y, (float)z); - Vector3 sitOffset = up * (float)offset; + x = 2 * (r.X * r.Z + r.Y * r.W); + y = 2 * (-r.X * r.W + r.Y * r.Z); + z = -r.X * r.X - r.Y * r.Y + r.Z * r.Z + r.W * r.W; + Vector3 up = new Vector3((float)x, (float)y, (float)z); + sitOffset = up * Appearance.AvatarHeight * 0.02638f; + newPos = sitTargetPos + sitOffset + SIT_TARGET_ADJUSTMENT; + } - // sitOffset is in Avatar Center coordinates: from origin to 'sitTargetPos + SIT_TARGET_ADJUSTMENT'. - // So, we need to _substract_ it to get to the origin of the Avatar Center. - Vector3 newPos = sitTargetPos + SIT_TARGET_ADJUSTMENT - sitOffset; Quaternion newRot; if (part.IsRoot) @@ -3078,19 +3646,25 @@ namespace OpenSim.Region.Framework.Scenes // Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId); } + part.AddSittingAvatar(this); ParentPart = part; ParentID = m_requestedSitTargetID; + + RemoveFromPhysicalScene(); m_AngularVelocity = Vector3.Zero; Velocity = Vector3.Zero; - RemoveFromPhysicalScene(); - String sitAnimation = "SIT"; + m_requestedSitTargetID = 0; + + SendAvatarDataToAllAgents(); + + sitAnimation = "SIT"; if (!String.IsNullOrEmpty(part.SitAnimation)) { sitAnimation = part.SitAnimation; } - Animator.TrySetMovementAnimation(sitAnimation); - SendAvatarDataToAllClients(); +// Animator.TrySetMovementAnimation(sitAnimation); + Animator.SetMovementAnimations("SIT"); TriggerScenePresenceUpdated(); } } @@ -3101,11 +3675,17 @@ namespace OpenSim.Region.Framework.Scenes return; // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. - m_AngularVelocity = Vector3.Zero; - Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); - TriggerScenePresenceUpdated(); + sitAnimation = "SIT_GROUND_CONSTRAINED"; +// Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); +// TriggerScenePresenceUpdated(); SitGround = true; RemoveFromPhysicalScene(); + + m_AngularVelocity = Vector3.Zero; + Velocity = Vector3.Zero; + + Animator.SetMovementAnimations("SITGROUND"); + TriggerScenePresenceUpdated(); } /// @@ -3129,86 +3709,84 @@ namespace OpenSim.Region.Framework.Scenes TriggerScenePresenceUpdated(); } + public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) + { + Animator.avnChangeAnim(animID, addRemove, sendPack); + } + /// /// Rotate the avatar to the given rotation and apply a movement in the given relative vector /// /// The vector in which to move. This is relative to the rotation argument /// /// Optional additional speed modifier for this particular add. Default is 1 - public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1) + public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1, bool breaking = false) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}", -// vec, Rotation, thisAddSpeedModifier, Name); - + // m_log.DebugFormat( + // "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}", + // vec, Rotation, thisAddSpeedModifier, Name); + m_delayedStop = -1; + // rotate from avatar coord space to world Quaternion rot = Rotation; if (!Flying && PresenceType != PresenceType.Npc) { - // The only situation in which we care about X and Y is avatar flying. The rest of the time - // these parameters are not relevant for determining avatar movement direction and cause issues such - // as wrong walk speed if the camera is rotated. + // force rotation to be around Z only, if not flying + // needed for mouselook rot.X = 0; rot.Y = 0; - rot.Normalize(); } Vector3 direc = vec * rot; direc.Normalize(); - if (Flying != FlyingOld) // add for fly velocity control - { - FlyingOld = Flying; // add for fly velocity control - if (!Flying) - WasFlying = true; // add for fly velocity control - } - - if (IsColliding) - WasFlying = false; // add for fly velocity control - if ((vec.Z == 0f) && !Flying) direc.Z = 0f; // Prevent camera WASD up. - direc *= 0.03f * 128f * SpeedModifier * thisAddSpeedModifier; + bool notmvtrgt = !m_movingToTarget || m_moveToSpeed <= 0; + // odd rescalings + if(notmvtrgt) + direc *= 4.096f * SpeedModifier * thisAddSpeedModifier; + else + direc *= m_moveToSpeed; -// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name); + // m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name); - if (PhysicsActor != null) + if (Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling + && (PhysicsActor == null || !PhysicsActor.PIDHoverActive)) { - if (Flying) - { + if (breaking) + direc.Z = -9999f; //hack to tell physics to stop on Z + else + direc = Vector3.Zero; + } + else if (Flying) + { + if (IsColliding && direc.Z < 0) + // landing situation, prevent avatar moving or it may fail to land + // animator will handle this condition and do the land + direc = Vector3.Zero; + else if(notmvtrgt) direc *= 4.0f; - //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); - //if (controlland) - // m_log.Info("[AGENT]: landCommand"); - //if (IsColliding) - // m_log.Info("[AGENT]: colliding"); - //if (Flying && IsColliding && controlland) - //{ - // StopFlying(); - // m_log.Info("[AGENT]: Stop Flying"); - //} - } - if (Animator.Falling && WasFlying) // if falling from flying, disable motion add - { - direc *= 0.0f; - } - else if (!Flying && IsColliding) + } + else if (IsColliding) + { + if (direc.Z > 2.0f && notmvtrgt) // reinforce jumps { - if (direc.Z > 2.0f) - { - direc.Z *= 2.6f; - - // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. -// Animator.TrySetMovementAnimation("PREJUMP"); -// Animator.TrySetMovementAnimation("JUMP"); - } + direc.Z *= 2.6f; } + else if (direc.Z < 0) // on a surface moving down (pg down) only changes animation + direc.Z = 0; } -// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); - - // TODO: Add the force instead of only setting it to support multiple forces per frame? - m_forceToApply = direc; + // m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); +/* + lock(m_forceToApplyLock) + { + m_forceToApply = direc; + m_forceToApplyValid = true; + } +*/ + TargetVelocity = direc; Animator.UpdateMovementAnimations(); } @@ -3216,51 +3794,116 @@ namespace OpenSim.Region.Framework.Scenes #region Overridden Methods + const float ROTATION_TOLERANCE = 0.01f; + const float VELOCITY_TOLERANCE = 0.1f; + const float LOWVELOCITYSQ = 0.1f; + const float POSITION_LARGETOLERANCE = 5f; + const float POSITION_SMALLTOLERANCE = 0.05f; + public override void Update() { - if (IsChildAgent == false) - { - // NOTE: Velocity is not the same as m_velocity. Velocity will attempt to - // grab the latest PhysicsActor velocity, whereas m_velocity is often - // storing a requested force instead of an actual traveling velocity - if (Appearance.AvatarSize != m_lastSize && !IsLoggingIn) - SendAvatarDataToAllClients(); + if(IsChildAgent || IsDeleted) + return; - // Allow any updates for sitting avatars to that llSetPrimitiveLinkParams() can work for very - // small increments (e.g. sit position adjusters). An alternative may be to eliminate the tolerance - // checks on all updates but the ramifications of this would need careful consideration. - bool updateClients - = IsSatOnObject && (Rotation != m_lastRotation || Velocity != m_lastVelocity || m_pos != m_lastPosition); - - if (!updateClients) - updateClients - = !Rotation.ApproxEquals(m_lastRotation, Scene.RootRotationUpdateTolerance) - || !Velocity.ApproxEquals(m_lastVelocity, Scene.RootVelocityUpdateTolerance) - || !m_pos.ApproxEquals(m_lastPosition, Scene.RootPositionUpdateTolerance); + CheckForBorderCrossing(); + + if (IsInTransit || IsLoggingIn) + return; - if (updateClients) + if(m_movingToTarget) + { + m_delayedStop = -1; + Vector3 control = Vector3.Zero; + if(HandleMoveToTargetUpdate(1f, ref control)) + AddNewMovement(control); + } + else if(m_delayedStop > 0) + { + if(IsSatOnObject) + m_delayedStop = -1; + else + if(Util.GetTimeStampMS() > m_delayedStop) + AddNewMovement(Vector3.Zero); + } + + if (Appearance.AvatarSize != m_lastSize) + SendAvatarDataToAllAgents(); + + // Send terse position update if not sitting and position, velocity, or rotation + // has changed significantly from last sent update + if (!IsSatOnObject) + { + // this does need to be more complex later + Vector3 vel = Velocity; + Vector3 dpos = m_pos - m_lastPosition; + if( State != m_lastState || + Math.Abs(vel.X - m_lastVelocity.X) > VELOCITY_TOLERANCE || + Math.Abs(vel.Y - m_lastVelocity.Y) > VELOCITY_TOLERANCE || + Math.Abs(vel.Z - m_lastVelocity.Z) > VELOCITY_TOLERANCE || + + Math.Abs(m_bodyRot.X - m_lastRotation.X) > ROTATION_TOLERANCE || + Math.Abs(m_bodyRot.Y - m_lastRotation.Y) > ROTATION_TOLERANCE || + Math.Abs(m_bodyRot.Z - m_lastRotation.Z) > ROTATION_TOLERANCE || + + (vel == Vector3.Zero && m_lastVelocity != Vector3.Zero) || + + Math.Abs(dpos.X) > POSITION_LARGETOLERANCE || + Math.Abs(dpos.Y) > POSITION_LARGETOLERANCE || + Math.Abs(dpos.Z) > POSITION_LARGETOLERANCE || + + ( (Math.Abs(dpos.X) > POSITION_SMALLTOLERANCE || + Math.Abs(dpos.Y) > POSITION_SMALLTOLERANCE || + Math.Abs(dpos.Z) > POSITION_SMALLTOLERANCE) + && vel.LengthSquared() < LOWVELOCITYSQ + ) || + + Math.Abs(CollisionPlane.X - m_lastCollisionPlane.X) > POSITION_SMALLTOLERANCE || + Math.Abs(CollisionPlane.Y - m_lastCollisionPlane.Y) > POSITION_SMALLTOLERANCE || + Math.Abs(CollisionPlane.W - m_lastCollisionPlane.W) > POSITION_SMALLTOLERANCE + ) { SendTerseUpdateToAllClients(); - - // Update the "last" values - m_lastPosition = m_pos; - m_lastRotation = Rotation; - m_lastVelocity = Velocity; } - - if (Scene.AllowAvatarCrossing) - CheckForBorderCrossing(); - - CheckForSignificantMovement(); // sends update to the modules. } + CheckForSignificantMovement(); } #endregion #region Update Client(s) + public void SendUpdateToAgent(ScenePresence p) + { + IClientAPI remoteClient = p.ControllingClient; + + if (remoteClient.IsActive) + { + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate(this, PrimUpdateFlags.FullUpdate); + m_scene.StatsReporter.AddAgentUpdates(1); + } + } + + public void SendFullUpdateToClient(IClientAPI remoteClient) + { + if (remoteClient.IsActive) + { + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate(this, PrimUpdateFlags.FullUpdate); + m_scene.StatsReporter.AddAgentUpdates(1); + } + } + + // this is diferente from SendTerseUpdateToClient + // this sends bypassing entities updates + public void SendAgentTerseUpdate(ISceneEntity p) + { + ControllingClient.SendAgentTerseUpdate(p); + } + /// /// Sends a location update to the client connected to this scenePresence + /// via entity updates /// /// public void SendTerseUpdateToClient(IClientAPI remoteClient) @@ -3269,31 +3912,7 @@ namespace OpenSim.Region.Framework.Scenes // server. if (remoteClient.IsActive) { - if (Scene.RootTerseUpdatePeriod > 1) - { -// Console.WriteLine( -// "{0} {1} {2} {3} {4} {5} for {6} to {7}", -// remoteClient.AgentId, UUID, remoteClient.SceneAgent.IsChildAgent, m_terseUpdateCount, Scene.RootTerseUpdatePeriod, Velocity.ApproxEquals(Vector3.Zero, 0.001f), Name, remoteClient.Name); - if (remoteClient.AgentId != UUID - && !remoteClient.SceneAgent.IsChildAgent - && m_terseUpdateCount % Scene.RootTerseUpdatePeriod != 0 - && !Velocity.ApproxEquals(Vector3.Zero, 0.001f)) - { -// m_log.DebugFormat("[SCENE PRESENCE]: Discarded update from {0} to {1}, args {2} {3} {4} {5} {6} {7}", -// Name, remoteClient.Name, remoteClient.AgentId, UUID, remoteClient.SceneAgent.IsChildAgent, m_terseUpdateCount, Scene.RootTerseUpdatePeriod, Velocity.ApproxEquals(Vector3.Zero, 0.001f)); - - return; - } - } - - if (Scene.ChildTerseUpdatePeriod > 1 - && remoteClient.SceneAgent.IsChildAgent - && m_terseUpdateCount % Scene.ChildTerseUpdatePeriod != 0 - && !Velocity.ApproxEquals(Vector3.Zero, 0.001f)) - return; - //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); - remoteClient.SendEntityUpdate( this, PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity @@ -3303,59 +3922,51 @@ namespace OpenSim.Region.Framework.Scenes } } - - // vars to support reduced update frequency when velocity is unchanged - private Vector3 lastVelocitySentToAllClients = Vector3.Zero; - private Vector3 lastPositionSentToAllClients = Vector3.Zero; - private int lastTerseUpdateToAllClientsTick = Util.EnvironmentTickCount(); - - /// - /// Send a location/velocity/accelleration update to all agents in scene - /// - public void SendTerseUpdateToAllClients() + public void SendTerseUpdateToAgent(ScenePresence p) { - int currentTick = Util.EnvironmentTickCount(); - - // Decrease update frequency when avatar is moving but velocity is - // not changing. - // If there is a mismatch between distance travelled and expected - // distance based on last velocity sent and velocity hasnt changed, - // then send a new terse update + IClientAPI remoteClient = p.ControllingClient; - float timeSinceLastUpdate = (currentTick - lastTerseUpdateToAllClientsTick) * 0.001f; - - Vector3 expectedPosition = lastPositionSentToAllClients + lastVelocitySentToAllClients * timeSinceLastUpdate; - - float distanceError = Vector3.Distance(OffsetPosition, expectedPosition); + if (!remoteClient.IsActive) + return; - float speed = Velocity.Length(); - float velocityDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity); + if (ParcelHideThisAvatar && p.currentParcelUUID != currentParcelUUID && !p.IsViewerUIGod) + return; -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Delta-v {0}, lastVelocity {1}, Velocity {2} for {3} in {4}", -// velocidyDiff, lastVelocitySentToAllClients, Velocity, Name, Scene.Name); + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate( + this, + PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity); - // assuming 5 ms. worst case precision for timer, use 2x that - // for distance error threshold - float distanceErrorThreshold = speed * 0.01f; + m_scene.StatsReporter.AddAgentUpdates(1); + } - if (speed < 0.01f // allow rotation updates if avatar position is unchanged - || Math.Abs(distanceError) > distanceErrorThreshold - || velocityDiff > 0.01f) // did velocity change from last update? + public void SendTerseUpdateToAgentNF(ScenePresence p) + { + IClientAPI remoteClient = p.ControllingClient; + if (remoteClient.IsActive) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Update triggered with speed {0}, distanceError {1}, distanceThreshold {2}, delta-v {3} for {4} in {5}", -// speed, distanceError, distanceErrorThreshold, velocidyDiff, Name, Scene.Name); - - lastVelocitySentToAllClients = Velocity; - lastTerseUpdateToAllClientsTick = currentTick; - lastPositionSentToAllClients = OffsetPosition; + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate(this, + PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity); + m_scene.StatsReporter.AddAgentUpdates(1); + } + } - m_terseUpdateCount++; + /// + /// Send a location/velocity/accelleration update to all agents in scene + /// + public void SendTerseUpdateToAllClients() + { + m_lastState = State; + m_lastPosition = m_pos; + m_lastRotation = m_bodyRot; + m_lastVelocity = Velocity; + m_lastCollisionPlane = CollisionPlane; -// Console.WriteLine("Scheduled update for {0} in {1}", Name, Scene.Name); - m_scene.ForEachClient(SendTerseUpdateToClient); - } + m_scene.ForEachScenePresence(SendTerseUpdateToAgent); + // Update the "last" values TriggerScenePresenceUpdated(); } @@ -3379,89 +3990,75 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations); } - public void SendInitialDataToClient() + public void SendInitialDataToMe() { - SentInitialDataToClient = true; - // Send all scene object to the new client - WorkManager.RunJob("SendInitialDataToClient", delegate + SentInitialData = true; + Util.FireAndForget(delegate { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Sending initial data to {0} agent {1} in {2}, tp flags {3}", -// IsChildAgent ? "child" : "root", Name, Scene.Name, m_teleportFlags); - // we created a new ScenePresence (a new child agent) in a fresh region. // Request info about all the (root) agents in this region // Note: This won't send data *to* other clients in that region (children don't send) - SendOtherAgentsAvatarDataToClient(); - SendOtherAgentsAppearanceToClient(); + if (m_teleportFlags <= 0) + { + Scene.SendLayerData(ControllingClient); + + ILandChannel landch = m_scene.LandChannel; + if (landch != null) + { + landch.sendClientInitialLandInfo(ControllingClient); + } + } + SendOtherAgentsAvatarFullToMe(); EntityBase[] entities = Scene.Entities.GetEntities(); foreach (EntityBase e in entities) { - if (e != null && e is SceneObjectGroup) + if (e != null && e is SceneObjectGroup && !((SceneObjectGroup)e).IsAttachment) ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); } - }, null, string.Format("SendInitialDataToClient ({0} in {1})", Name, Scene.Name), false, true); + + m_reprioritizationLastPosition = AbsolutePosition; + m_reprioritizationLastDrawDistance = DrawDistance; + m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it + m_reprioritizationBusy = false; + + }); } /// - /// Do everything required once a client completes its movement into a region and becomes - /// a root agent. + /// Send avatar full data appearance and animations for all other root agents to this agent, this agent + /// can be either a child or root /// - private void ValidateAndSendAppearanceAndAgentData() + public void SendOtherAgentsAvatarFullToMe() { - //m_log.DebugFormat("[SCENE PRESENCE] SendInitialData: {0} ({1})", Name, UUID); - // Moved this into CompleteMovement to ensure that Appearance is initialized before - // the inventory arrives - // m_scene.GetAvatarAppearance(ControllingClient, out Appearance); - - bool cachedappearance = false; - - // We have an appearance but we may not have the baked textures. Check the asset cache - // to see if all the baked textures are already here. - if (m_scene.AvatarFactory != null) - cachedappearance = m_scene.AvatarFactory.ValidateBakedTextureCache(this); - - // If we aren't using a cached appearance, then clear out the baked textures - if (!cachedappearance) + int count = 0; + m_scene.ForEachRootScenePresence(delegate(ScenePresence p) { - Appearance.ResetAppearance(); - if (m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(UUID); - } - - // This agent just became root. We are going to tell everyone about it. The process of - // getting other avatars information was initiated elsewhere immediately after the child circuit connected... don't do it - // again here... this comes after the cached appearance check because the avatars - // appearance goes into the avatar update packet - SendAvatarDataToAllClients(); + // only send information about other root agents + if (p.UUID == UUID) + return; - // This invocation always shows up in the viewer logs as an error. Is it needed? - SendAppearanceToClient(this); + // get the avatar, then a kill if can't see it + p.SendInitialAvatarDataToAgent(this); - // If we are using the the cached appearance then send it out to everyone - if (cachedappearance) - { - m_log.DebugFormat("[SCENE PRESENCE]: Baked textures are in the cache for {0} in {1}", Name, m_scene.Name); + if (p.ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !IsViewerUIGod) + return; - // If the avatars baked textures are all in the cache, then we have a - // complete appearance... send it out, if not, then we'll send it when - // the avatar finishes updating its appearance - SendAppearanceToAllOtherClients(); - } - } + p.SendAppearanceToAgentNF(this); + p.SendAnimPackToAgentNF(this); + p.SendAttachmentsToAgentNF(this); + count++; + }); - public void SendAvatarDataToAllClients() - { - SendAvatarDataToAllClients(true); + m_scene.StatsReporter.AddAgentUpdates(count); } /// /// Send this agent's avatar data to all other root and child agents in the scene - /// This agent must be root. This avatar will receive its own update. + /// This agent must be root. This avatar will receive its own update. /// - public void SendAvatarDataToAllClients(bool full) + public void SendAvatarDataToAllAgents() { //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); // only send update from root agents to other clients; children are only "listening posts" @@ -3470,64 +4067,73 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[SCENE PRESENCE]: Attempt to send avatar data from a child agent for {0} in {1}", Name, Scene.RegionInfo.RegionName); - return; } m_lastSize = Appearance.AvatarSize; - int count = 0; + m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence) { - if (full) - SendAvatarDataToClient(scenePresence); - else - scenePresence.ControllingClient.SendAvatarDataImmediate(this); + SendAvatarDataToAgent(scenePresence); count++; }); m_scene.StatsReporter.AddAgentUpdates(count); } - - /// - /// Send avatar data for all other root agents to this agent, this agent - /// can be either a child or root - /// - public void SendOtherAgentsAvatarDataToClient() + // sends avatar object to all clients so they cross it into region + // then sends kills to hide + public void SendInitialAvatarDataToAllAgents(List presences) { + m_lastSize = Appearance.AvatarSize; int count = 0; - m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) - { - // only send information about other root agents - if (scenePresence.UUID == UUID) - return; - - scenePresence.SendAvatarDataToClient(this); - count++; - }); - + foreach (ScenePresence p in presences) + { + p.ControllingClient.SendEntityFullUpdateImmediate(this); + if (p != this && ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + // either just kill the object + // p.ControllingClient.SendKillObject(new List {LocalId}); + // or also attachments viewer may still know about + SendKillTo(p); + count++; + } m_scene.StatsReporter.AddAgentUpdates(count); } + public void SendInitialAvatarDataToAgent(ScenePresence p) + { + p.ControllingClient.SendEntityFullUpdateImmediate(this); + if (p != this && ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + // either just kill the object + // p.ControllingClient.SendKillObject(new List {LocalId}); + // or also attachments viewer may still know about + SendKillTo(p); + } + /// /// Send avatar data to an agent. /// /// - public void SendAvatarDataToClient(ScenePresence avatar) + public void SendAvatarDataToAgent(ScenePresence avatar) { - //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToClient from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); + //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); + if (ParcelHideThisAvatar && currentParcelUUID != avatar.currentParcelUUID && !avatar.IsViewerUIGod) + return; + avatar.ControllingClient.SendEntityFullUpdateImmediate(this); + } - avatar.ControllingClient.SendAvatarDataImmediate(this); - Animator.SendAnimPackToClient(avatar.ControllingClient); + public void SendAvatarDataToAgentNF(ScenePresence avatar) + { + avatar.ControllingClient.SendEntityFullUpdateImmediate(this); } /// /// Send this agent's appearance to all other root and child agents in the scene /// This agent must be root. /// - public void SendAppearanceToAllOtherClients() + public void SendAppearanceToAllOtherAgents() { -// m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherClients: {0} {1}", Name, UUID); + // m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherAgents: {0} {1}", Name, UUID); // only send update from root agents to other clients; children are only "listening posts" if (IsChildAgent) @@ -3538,115 +4144,223 @@ namespace OpenSim.Region.Framework.Scenes return; } - + int count = 0; m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence) - { - // only send information to other root agents - if (scenePresence.UUID == UUID) - return; - - SendAppearanceToClient(scenePresence); - count++; - }); + { + // only send information to other root agents + if (scenePresence.UUID == UUID) + return; + SendAppearanceToAgent(scenePresence); + count++; + }); m_scene.StatsReporter.AddAgentUpdates(count); } - /// - /// Send appearance from all other root agents to this agent. this agent - /// can be either root or child - /// - public void SendOtherAgentsAppearanceToClient() + public void SendAppearanceToAgent(ScenePresence avatar) { -// m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToClient {0} {1}", Name, UUID); - - int count = 0; - m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) - { - // only send information about other root agents - if (scenePresence.UUID == UUID) - return; - - scenePresence.SendAppearanceToClient(this); - count++; - }); - - m_scene.StatsReporter.AddAgentUpdates(count); + // m_log.DebugFormat( + // "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID); + if (ParcelHideThisAvatar && currentParcelUUID != avatar.currentParcelUUID && !avatar.IsViewerUIGod) + return; + SendAppearanceToAgentNF(avatar); } - /// - /// Send appearance data to an agent. - /// - /// - public void SendAppearanceToClient(ScenePresence avatar) + public void SendAppearanceToAgentNF(ScenePresence avatar) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID); - avatar.ControllingClient.SendAppearance( UUID, Appearance.VisualParams, Appearance.Texture.GetBytes()); - - } - #endregion - - #region Significant Movement Method - - /// - /// This checks for a significant movement and sends a coarselocationchange update - /// - protected void CheckForSignificantMovement() + public void SendAnimPackToAgent(ScenePresence p) { - if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > SIGNIFICANT_MOVEMENT) - { - posLastSignificantMove = AbsolutePosition; - m_scene.EventManager.TriggerSignificantClientMovement(this); - } - - // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m - if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance) - { - m_lastChildAgentUpdatePosition = AbsolutePosition; -// m_lastChildAgentUpdateCamPosition = CameraPosition; + if (IsChildAgent || Animator == null) + return; - ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); - cadu.ActiveGroupID = UUID.Zero.Guid; - cadu.AgentID = UUID.Guid; - cadu.alwaysrun = SetAlwaysRun; - cadu.AVHeight = Appearance.AvatarHeight; - cadu.cameraPosition = CameraPosition; - cadu.drawdistance = DrawDistance; - cadu.GroupAccess = 0; - cadu.Position = AbsolutePosition; - cadu.regionHandle = RegionHandle; + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; - // Throttles - float multiplier = 1; - int childRegions = KnownRegionCount; - if (childRegions != 0) - multiplier = 1f / childRegions; + Animator.SendAnimPackToClient(p.ControllingClient); + } - // Minimum throttle for a child region is 1/4 of the root region throttle - if (multiplier <= 0.25f) - multiplier = 0.25f; + public void SendAnimPackToAgent(ScenePresence p, UUID[] animations, int[] seqs, UUID[] objectIDs) + { + if (IsChildAgent) + return; - cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier); - cadu.Velocity = Velocity; + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; - AgentPosition agentpos = new AgentPosition(); - agentpos.CopyFrom(cadu, ControllingClient.SessionId); + p.ControllingClient.SendAnimations(animations, seqs, ControllingClient.AgentId, objectIDs); + } - // Let's get this out of the update loop - Util.FireAndForget( - o => m_scene.SendOutChildAgentUpdates(agentpos, this), null, "ScenePresence.SendOutChildAgentUpdates"); - } + public void SendAnimPackToAgentNF(ScenePresence p) + { + if (IsChildAgent || Animator == null) + return; + Animator.SendAnimPackToClient(p.ControllingClient); } - #endregion + public void SendAnimPackToAgentNF(ScenePresence p, UUID[] animations, int[] seqs, UUID[] objectIDs) + { + p.ControllingClient.SendAnimations(animations, seqs, ControllingClient.AgentId, objectIDs); + } - #region Border Crossing Methods + public void SendAnimPack(UUID[] animations, int[] seqs, UUID[] objectIDs) + { + if (IsChildAgent) + return; + + m_scene.ForEachScenePresence(delegate(ScenePresence p) + { + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; + p.ControllingClient.SendAnimations(animations, seqs, ControllingClient.AgentId, objectIDs); + }); + } + + #endregion + + #region Significant Movement Method + + private void checkRePrioritization() + { + if(IsDeleted || !ControllingClient.IsActive) + return; + + if(!SentInitialData) + { + SendInitialDataToMe(); + return; + } + + if(m_reprioritizationBusy) + return; + + float limit = Scene.ReprioritizationDistance; + bool byDrawdistance = Scene.ObjectsCullingByDistance; + if(byDrawdistance) + { + float minregionSize = (float)Scene.RegionInfo.RegionSizeX; + if(minregionSize > (float)Scene.RegionInfo.RegionSizeY) + minregionSize = (float)Scene.RegionInfo.RegionSizeY; + minregionSize *= 0.5f; + if(DrawDistance > minregionSize && m_reprioritizationLastDrawDistance > minregionSize) + byDrawdistance = false; + else + byDrawdistance = (Math.Abs(DrawDistance - m_reprioritizationLastDrawDistance) > 0.5f * limit); + } + + int tdiff = Util.EnvironmentTickCountSubtract(m_reprioritizationLastTime); + if(!byDrawdistance && tdiff < Scene.ReprioritizationInterval) + return; + // priority uses avatar position + Vector3 pos = AbsolutePosition; + Vector3 diff = pos - m_reprioritizationLastPosition; + limit *= limit; + if (!byDrawdistance && diff.LengthSquared() < limit) + return; + + m_reprioritizationBusy = true; + m_reprioritizationLastPosition = pos; + m_reprioritizationLastDrawDistance = DrawDistance; + + Util.FireAndForget( + o => + { + ControllingClient.ReprioritizeUpdates(); + m_reprioritizationLastTime = Util.EnvironmentTickCount(); + m_reprioritizationBusy = false; + }, null, "ScenePresence.Reprioritization"); + } + /// + /// This checks for a significant movement and sends a coarselocationchange update + /// + protected void CheckForSignificantMovement() + { + Vector3 pos = AbsolutePosition; + + Vector3 diff = pos - posLastMove; + if (diff.LengthSquared() > MOVEMENT) + { + posLastMove = pos; + m_scene.EventManager.TriggerOnClientMovement(this); + } + + diff = pos - posLastSignificantMove; + if (diff.LengthSquared() > SIGNIFICANT_MOVEMENT) + { + posLastSignificantMove = pos; + m_scene.EventManager.TriggerSignificantClientMovement(this); + } + + // updates priority recalc + checkRePrioritization(); + + if(m_childUpdatesBusy) + return; + + //possible KnownRegionHandles always contains current region and this check is not needed + int minhandles = 0; + if(KnownRegionHandles.Contains(RegionHandle)) + minhandles++; + + if(KnownRegionHandles.Count > minhandles) + { + int tdiff = Util.EnvironmentTickCountSubtract(m_lastChildUpdatesTime); + if(tdiff < CHILDUPDATES_TIME) + return; + + bool doUpdate = false; + if(m_lastChildAgentUpdateGodLevel != GodController.ViwerUIGodLevel) + doUpdate = true; + + if(!doUpdate && Math.Abs(DrawDistance - m_lastChildAgentUpdateDrawDistance) > 32.0f) + doUpdate = true; + + if(!doUpdate) + { + diff = pos - m_lastChildAgentUpdatePosition; + if (diff.LengthSquared() > CHILDUPDATES_MOVEMENT) + doUpdate = true; + } + + if(doUpdate) + { + m_childUpdatesBusy = true; + m_lastChildAgentUpdatePosition = pos; + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_lastChildAgentUpdateDrawDistance = DrawDistance; +// m_lastChildAgentUpdateCamPosition = CameraPosition; + + AgentPosition agentpos = new AgentPosition(); + agentpos.AgentID = new UUID(UUID.Guid); + agentpos.SessionID = ControllingClient.SessionId; + agentpos.Size = Appearance.AvatarSize; + agentpos.Center = CameraPosition; + agentpos.Far = DrawDistance; + agentpos.Position = AbsolutePosition; + agentpos.Velocity = Velocity; + agentpos.RegionHandle = RegionHandle; + agentpos.GodData = GodController.State(); + agentpos.Throttles = ControllingClient.GetThrottlesPacked(1); + + // Let's get this out of the update loop + Util.FireAndForget( + o => + { + m_scene.SendOutChildAgentUpdates(agentpos, this); + m_lastChildUpdatesTime = Util.EnvironmentTickCount(); + m_childUpdatesBusy = false; + }, null, "ScenePresence.SendOutChildAgentUpdates"); + } + } + } + + #endregion + + #region Border Crossing Methods /// /// Starts the process of moving an avatar into another region if they are crossing the border. @@ -3657,7 +4371,7 @@ namespace OpenSim.Region.Framework.Scenes protected void CheckForBorderCrossing() { // Check that we we are not a child - if (IsChildAgent) + if (IsChildAgent || IsInTransit) return; // If we don't have a PhysActor, we can't cross anyway @@ -3667,79 +4381,71 @@ namespace OpenSim.Region.Framework.Scenes if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero) return; - if (IsInTransit) - return; - Vector3 pos2 = AbsolutePosition; - Vector3 origPosition = pos2; Vector3 vel = Velocity; - // Compute the future avatar position. - // If the avatar will be crossing, we force the crossing to happen now - // in the hope that this will make the avatar movement smoother when crossing. - pos2 += vel * 0.05f; - - if (m_scene.PositionIsInCurrentRegion(pos2)) - return; - - m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}", - LogHeader, Name, Scene.Name, pos2); + float timeStep = 0.1f; + pos2.X += vel.X * timeStep; + pos2.Y += vel.Y * timeStep; + pos2.Z += vel.Z * timeStep; - // Disconnect from the current region - bool isFlying = Flying; - RemoveFromPhysicalScene(); +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}", +// pos2, Name, Scene.Name); - // pos2 is the forcasted position so make that the 'current' position so the crossing - // code will move us into the newly addressed region. - m_pos = pos2; + if (Scene.PositionIsInCurrentRegion(pos2)) + return; - if (CrossToNewRegion()) - { - AddToPhysicalScene(isFlying); - } - else + if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero) { - // Tried to make crossing happen but it failed. - if (m_requestedSitTargetUUID == UUID.Zero) - { - m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader); - - Velocity = Vector3.Zero; - AbsolutePosition = EnforceSanityOnPosition(origPosition); + // we don't have entity transfer module + Vector3 pos = AbsolutePosition; + vel = Velocity; + float px = pos.X; + if (px < 0) + pos.X += vel.X * 2; + else if (px > m_scene.RegionInfo.RegionSizeX) + pos.X -= vel.X * 2; + + float py = pos.Y; + if (py < 0) + pos.Y += vel.Y * 2; + else if (py > m_scene.RegionInfo.RegionSizeY) + pos.Y -= vel.Y * 2; - AddToPhysicalScene(isFlying); - } + Velocity = Vector3.Zero; + m_AngularVelocity = Vector3.Zero; + AbsolutePosition = pos; } } - // Given a position, make sure it is within the current region. - // If just outside some border, the returned position will be just inside the border on that side. - private Vector3 EnforceSanityOnPosition(Vector3 origPosition) + public void CrossToNewRegionFail() { - const float borderFudge = 0.1f; - Vector3 ret = origPosition; - - // Sanity checking on the position to make sure it is in the region we couldn't cross from - float extentX = (float)m_scene.RegionInfo.RegionSizeX; - float extentY = (float)m_scene.RegionInfo.RegionSizeY; - IRegionCombinerModule combiner = m_scene.RequestModuleInterface(); - if (combiner != null) + if (m_requestedSitTargetUUID == UUID.Zero) { - // If a mega-region, the size could be much bigger - Vector2 megaExtent = combiner.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); - extentX = megaExtent.X; - extentY = megaExtent.Y; - } - if (ret.X < 0) - ret.X = borderFudge; - else if (ret.X >= extentX) - ret.X = extentX - borderFudge; - if (ret.Y < 0) - ret.Y = borderFudge; - else if (ret.Y >= extentY) - ret.Y = extentY - borderFudge; + bool isFlying = Flying; + RemoveFromPhysicalScene(); + + Vector3 pos = AbsolutePosition; + Vector3 vel = Velocity; + float px = pos.X; + if (px < 0) + pos.X += vel.X * 2; + else if (px > m_scene.RegionInfo.RegionSizeX) + pos.X -= vel.X * 2; + + float py = pos.Y; + if (py < 0) + pos.Y += vel.Y * 2; + else if (py > m_scene.RegionInfo.RegionSizeY) + pos.Y -= vel.Y * 2; + + Velocity = Vector3.Zero; + m_AngularVelocity = Vector3.Zero; + AbsolutePosition = pos; - return ret; + AddToPhysicalScene(isFlying); + } } /// @@ -3750,62 +4456,93 @@ namespace OpenSim.Region.Framework.Scenes /// protected bool CrossToNewRegion() { + bool result = false; +// parcelRegionCross(false); try { - return m_scene.CrossAgentToNewRegion(this, Flying); + result = m_scene.CrossAgentToNewRegion(this, Flying); } catch { - return m_scene.CrossAgentToNewRegion(this, false); +// result = m_scene.CrossAgentToNewRegion(this, false); + return false; } - } - - public void Reset() - { -// m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName); + // if(!result) + // parcelRegionCross(true); - // Put the child agent back at the center - AbsolutePosition - = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70); + return result; - Animator.ResetAnimations(); } /// /// Computes which child agents to close when the scene presence moves to another region. /// Removes those regions from m_knownRegions. /// - /// The new region's x on the map - /// The new region's y on the map + /// The new region's handle + /// The new region's size x + /// The new region's size y /// - public void CloseChildAgents(uint newRegionX, uint newRegionY) + public List GetChildAgentsToClose(ulong newRegionHandle, int newRegionSizeX, int newRegionSizeY) { + ulong curRegionHandle = m_scene.RegionInfo.RegionHandle; List byebyeRegions = new List(); + + if(newRegionHandle == curRegionHandle) //?? + return byebyeRegions; + + uint newRegionX, newRegionY; List knownRegions = KnownRegionHandles; m_log.DebugFormat( - "[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}", + "[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}", knownRegions.Count, Scene.RegionInfo.RegionName); - //DumpKnownRegions(); + + Util.RegionHandleToRegionLoc(newRegionHandle, out newRegionX, out newRegionY); + uint x, y; + spRegionSizeInfo regInfo; foreach (ulong handle in knownRegions) { - // Don't close the agent on this region yet - if (handle != Scene.RegionInfo.RegionHandle) + if(newRegionY == 0) // HG + byebyeRegions.Add(handle); + else if(handle == curRegionHandle) { - uint x, y; - Util.RegionHandleToRegionLoc(handle, out x, out y); - -// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); -// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); - float dist = (float)Math.Max(Scene.DefaultDrawDistance, - (float)Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY)); - if (Util.IsOutsideView(dist, x, newRegionX, y, newRegionY)) + RegionInfo curreg = m_scene.RegionInfo; + if (Util.IsOutsideView(255, curreg.RegionLocX, newRegionX, curreg.RegionLocY, newRegionY, + (int)curreg.RegionSizeX, (int)curreg.RegionSizeX, newRegionSizeX, newRegionSizeY)) { byebyeRegions.Add(handle); } } + else + { + Util.RegionHandleToRegionLoc(handle, out x, out y); + if (m_knownChildRegionsSizeInfo.TryGetValue(handle, out regInfo)) + { +// if (Util.IsOutsideView(RegionViewDistance, x, newRegionX, y, newRegionY, + // for now need to close all but first order bc RegionViewDistance it the target value not ours + if (Util.IsOutsideView(255, x, newRegionX, y, newRegionY, + regInfo.sizeX, regInfo.sizeY, newRegionSizeX, newRegionSizeY)) + { + byebyeRegions.Add(handle); + } + } + else + { +// if (Util.IsOutsideView(RegionViewDistance, x, newRegionX, y, newRegionY, + if (Util.IsOutsideView(255, x, newRegionX, y, newRegionY, + (int)Constants.RegionSize, (int)Constants.RegionSize, newRegionSizeX, newRegionSizeY)) + { + byebyeRegions.Add(handle); + } + } + } } - + return byebyeRegions; + } + + public void CloseChildAgents(List byebyeRegions) + { + byebyeRegions.Remove(Scene.RegionInfo.RegionHandle); if (byebyeRegions.Count > 0) { m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); @@ -3814,43 +4551,56 @@ namespace OpenSim.Region.Framework.Scenes string auth = string.Empty; if (acd != null) auth = acd.SessionID.ToString(); - m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); + m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); } - + foreach (ulong handle in byebyeRegions) { RemoveNeighbourRegion(handle); + Scene.CapsModule.DropChildSeed(UUID, handle); } } - #endregion - - /// - /// This allows the Sim owner the abiility to kick users from their sim currently. - /// It tells the client that the agent has permission to do so. - /// - public void GrantGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godStatus) + public void closeAllChildAgents() { - if (godStatus) + List byebyeRegions = new List(); + List knownRegions = KnownRegionHandles; + foreach (ulong handle in knownRegions) { - // For now, assign god level 200 to anyone - // who is granted god powers, but has no god level set. - // - UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, agentID); - if (account != null) + if (handle != Scene.RegionInfo.RegionHandle) { - if (account.UserLevel > 0) - GodLevel = account.UserLevel; - else - GodLevel = 200; + byebyeRegions.Add(handle); + RemoveNeighbourRegion(handle); + Scene.CapsModule.DropChildSeed(UUID, handle); } } - else + + if (byebyeRegions.Count > 0) { - GodLevel = 0; + m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); + + AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID); + string auth = string.Empty; + if (acd != null) + auth = acd.SessionID.ToString(); + m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); } + } + + #endregion + + /// + /// handle god level requests. + /// + public void GrantGodlikePowers(UUID token, bool godStatus) + { + if (IsNPC) + return; - ControllingClient.SendAdminResponse(token, (uint)GodLevel); + bool wasgod = IsViewerUIGod; + GodController.RequestGodMode(godStatus); + if (wasgod != IsViewerUIGod) + parcelGodCheck(m_currentParcelUUID); } #region Child Agent Updates @@ -3862,12 +4612,16 @@ namespace OpenSim.Region.Framework.Scenes return; CopyFrom(cAgentData); - m_updateAgentReceivedAfterTransferEvent.Set(); } private static Vector3 marker = new Vector3(-1f, -1f, -1f); + private void RaiseUpdateThrottles() + { + m_scene.EventManager.TriggerThrottleUpdate(this); + } + /// /// This updates important decision making data about a child agent /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region @@ -3877,44 +4631,59 @@ namespace OpenSim.Region.Framework.Scenes if (!IsChildAgent) return; -// m_log.DebugFormat( -// "[SCENE PRESENCE]: ChildAgentPositionUpdate for {0} in {1}, tRegion {2},{3}, rRegion {4},{5}, pos {6}", -// Name, Scene.Name, tRegionX, tRegionY, rRegionX, rRegionY, cAgentData.Position); + GodController.SetState(cAgentData.GodData); + + RegionHandle = cAgentData.RegionHandle; - // Find the distance (in meters) between the two regions - // XXX: We cannot use Util.RegionLocToHandle() here because a negative value will silently overflow the - // uint - int shiftx = (int)(((int)rRegionX - (int)tRegionX) * Constants.RegionSize); - int shifty = (int)(((int)rRegionY - (int)tRegionY) * Constants.RegionSize); + //m_log.Debug(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY); + int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize; + int shifty = ((int)rRegionY - (int)tRegionY) * (int)Constants.RegionSize; Vector3 offset = new Vector3(shiftx, shifty, 0f); - // When we get to the point of re-computing neighbors everytime this - // changes, then start using the agent's drawdistance rather than the - // region's draw distance. DrawDistance = cAgentData.Far; - // DrawDistance = Scene.DefaultDrawDistance; if (cAgentData.Position != marker) // UGH!! m_pos = cAgentData.Position + offset; - if (Vector3.Distance(AbsolutePosition, posLastSignificantMove) >= Scene.ChildReprioritizationDistance) + CameraPosition = cAgentData.Center + offset; + + if ((cAgentData.Throttles != null) && cAgentData.Throttles.Length > 0) { - posLastSignificantMove = AbsolutePosition; - ReprioritizeUpdates(); + // some scaling factor + float x = m_pos.X; + if (x > m_scene.RegionInfo.RegionSizeX) + x -= m_scene.RegionInfo.RegionSizeX; + float y = m_pos.Y; + if (y > m_scene.RegionInfo.RegionSizeY) + y -= m_scene.RegionInfo.RegionSizeY; + + x = x * x + y * y; + + const float distScale = 0.4f / Constants.RegionSize / Constants.RegionSize; + float factor = 1.0f - distScale * x; + if (factor < 0.2f) + factor = 0.2f; + + ControllingClient.SetChildAgentThrottle(cAgentData.Throttles,factor); } - CameraPosition = cAgentData.Center + offset; + if(cAgentData.ChildrenCapSeeds != null && cAgentData.ChildrenCapSeeds.Count >0) + { + if (Scene.CapsModule != null) + { + Scene.CapsModule.SetChildrenSeed(UUID, cAgentData.ChildrenCapSeeds); + } - if ((cAgentData.Throttles != null) && cAgentData.Throttles.Length > 0) - ControllingClient.SetChildAgentThrottle(cAgentData.Throttles); + KnownRegions = cAgentData.ChildrenCapSeeds; + } //cAgentData.AVHeight; - RegionHandle = cAgentData.RegionHandle; //m_velocity = cAgentData.Velocity; + checkRePrioritization(); } - public void CopyTo(AgentData cAgent) + public void CopyTo(AgentData cAgent, bool isCrossUpdate) { cAgent.CallbackURI = m_callbackURI; @@ -3930,35 +4699,23 @@ namespace OpenSim.Region.Framework.Scenes cAgent.UpAxis = CameraUpAxis; cAgent.Far = DrawDistance; + cAgent.GodData = GodController.State(); - // Throttles - float multiplier = 1; - int childRegions = KnownRegionCount; - if (childRegions != 0) - multiplier = 1f / childRegions; - - // Minimum throttle for a child region is 1/4 of the root region throttle - if (multiplier <= 0.25f) - multiplier = 0.25f; - - cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier); + // Throttles + cAgent.Throttles = ControllingClient.GetThrottlesPacked(1); cAgent.HeadRotation = m_headrotation; cAgent.BodyRotation = Rotation; cAgent.ControlFlags = (uint)m_AgentControlFlags; - if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) - cAgent.GodLevel = (byte)GodLevel; - else - cAgent.GodLevel = (byte) 0; - cAgent.AlwaysRun = SetAlwaysRun; - cAgent.Appearance = new AvatarAppearance(Appearance); + // make clear we want the all thing + cAgent.Appearance = new AvatarAppearance(Appearance,true,true); cAgent.ParentPart = ParentUUID; cAgent.SitOffset = PrevSitOffset; - + lock (scriptedcontrols) { ControllerData[] controls = new ControllerData[scriptedcontrols.Count]; @@ -3980,8 +4737,36 @@ namespace OpenSim.Region.Framework.Scenes cAgent.DefaultAnim = Animator.Animations.DefaultAnimation; cAgent.AnimState = Animator.Animations.ImplicitDefaultAnimation; + cAgent.MovementAnimationOverRides = Overrides.CloneAOPairs(); + + cAgent.MotionState = (byte)Animator.currentControlState; + if (Scene.AttachmentsModule != null) Scene.AttachmentsModule.CopyAttachments(this, cAgent); + + if(isCrossUpdate) + { + cAgent.CrossingFlags = crossingFlags; + cAgent.CrossingFlags |= 1; + cAgent.CrossExtraFlags = 0; + if((LastCommands & ScriptControlled.CONTROL_LBUTTON) != 0) + cAgent.CrossExtraFlags |= 1; + if((LastCommands & ScriptControlled.CONTROL_ML_LBUTTON) != 0) + cAgent.CrossExtraFlags |= 2; + } + else + cAgent.CrossingFlags = 0; + + if(isCrossUpdate) + { + cAgent.agentCOF = COF; + cAgent.ActiveGroupID = ControllingClient.ActiveGroupId; + cAgent.ActiveGroupName = ControllingClient.ActiveGroupName; + if(Grouptitle == null) + cAgent.ActiveGroupTitle = String.Empty; + else + cAgent.ActiveGroupTitle = Grouptitle; + } } private void CopyFrom(AgentData cAgent) @@ -3991,40 +4776,59 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", // Name, m_scene.RegionInfo.RegionName, m_callbackURI); + GodController.SetState(cAgent.GodData); + m_pos = cAgent.Position; m_velocity = cAgent.Velocity; CameraPosition = cAgent.Center; CameraAtAxis = cAgent.AtAxis; CameraLeftAxis = cAgent.LeftAxis; CameraUpAxis = cAgent.UpAxis; + + Quaternion camRot = Util.Axes2Rot(CameraAtAxis, CameraLeftAxis, CameraUpAxis); + CameraRotation = camRot; + ParentUUID = cAgent.ParentPart; PrevSitOffset = cAgent.SitOffset; // When we get to the point of re-computing neighbors everytime this - // changes, then start using the agent's drawdistance rather than the + // changes, then start using the agent's drawdistance rather than the // region's draw distance. DrawDistance = cAgent.Far; - // DrawDistance = Scene.DefaultDrawDistance; + //DrawDistance = Scene.DefaultDrawDistance; + + if (cAgent.ChildrenCapSeeds != null && cAgent.ChildrenCapSeeds.Count > 0) + { + if (Scene.CapsModule != null) + { + Scene.CapsModule.SetChildrenSeed(UUID, cAgent.ChildrenCapSeeds); + } + KnownRegions = cAgent.ChildrenCapSeeds; + } if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0) ControllingClient.SetChildAgentThrottle(cAgent.Throttles); m_headrotation = cAgent.HeadRotation; Rotation = cAgent.BodyRotation; - m_AgentControlFlags = (AgentManager.ControlFlags)cAgent.ControlFlags; + m_AgentControlFlags = (AgentManager.ControlFlags)cAgent.ControlFlags; - if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) - GodLevel = cAgent.GodLevel; SetAlwaysRun = cAgent.AlwaysRun; Appearance = new AvatarAppearance(cAgent.Appearance); +/* + bool isFlying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); + if (PhysicsActor != null) { - bool isFlying = Flying; RemoveFromPhysicalScene(); AddToPhysicalScene(isFlying); } - +*/ + + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.CopyAttachments(cAgent, this); + try { lock (scriptedcontrols) @@ -4032,6 +4836,7 @@ namespace OpenSim.Region.Framework.Scenes if (cAgent.Controllers != null) { scriptedcontrols.Clear(); + IgnoredControls = ScriptControlled.CONTROL_ZERO; foreach (ControllerData c in cAgent.Controllers) { @@ -4042,40 +4847,63 @@ namespace OpenSim.Region.Framework.Scenes sc.eventControls = (ScriptControlled)c.EventControls; scriptedcontrols[sc.itemID] = sc; + IgnoredControls |= sc.ignoreControls; // this is not correct, aparently only last applied should count } } } } catch { } + Animator.ResetAnimations(); + + Overrides.CopyAOPairsFrom(cAgent.MovementAnimationOverRides); + // FIXME: Why is this null check necessary? Where are the cases where we get a null Anims object? - if (cAgent.Anims != null) - Animator.Animations.FromArray(cAgent.Anims); if (cAgent.DefaultAnim != null) Animator.Animations.SetDefaultAnimation(cAgent.DefaultAnim.AnimID, cAgent.DefaultAnim.SequenceNum, UUID.Zero); if (cAgent.AnimState != null) Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero); + if (cAgent.Anims != null) + Animator.Animations.FromArray(cAgent.Anims); + if (cAgent.MotionState != 0) + Animator.currentControlState = (ScenePresenceAnimator.motionControlStates) cAgent.MotionState; - if (Scene.AttachmentsModule != null) + + crossingFlags = cAgent.CrossingFlags; + gotCrossUpdate = (crossingFlags != 0); + if(gotCrossUpdate) { - // If the JobEngine is running we can schedule this job now and continue rather than waiting for all - // attachments to copy, which might take a long time in the Hypergrid case as the entire inventory - // graph is inspected for each attachments and assets possibly fetched. - // - // We don't need to worry about a race condition as the job to later start the scripts is also - // JobEngine scheduled and so will always occur after this task. - // XXX: This will not be true if JobEngine ever gets more than one thread. - WorkManager.RunJob( - "CopyAttachments", - o => Scene.AttachmentsModule.CopyAttachments(cAgent, this), - null, - string.Format("Copy attachments for {0} entering {1}", Name, Scene.Name), - true); - } - - // This must occur after attachments are copied or scheduled to be copied, as it releases the CompleteMovement() calling thread - // originating from the client completing a teleport. Otherwise, CompleteMovement() code to restart - // script attachments can outrace this thread. + LastCommands &= ~(ScriptControlled.CONTROL_LBUTTON | ScriptControlled.CONTROL_ML_LBUTTON); + if((cAgent.CrossExtraFlags & 1) != 0) + LastCommands |= ScriptControlled.CONTROL_LBUTTON; + if((cAgent.CrossExtraFlags & 2) != 0) + LastCommands |= ScriptControlled.CONTROL_ML_LBUTTON; + MouseDown = (cAgent.CrossExtraFlags & 3) != 0; + } + + haveGroupInformation = false; + // using this as protocol detection don't want to mess with the numbers for now + if(cAgent.ActiveGroupTitle != null) + { + haveGroupInformation = true; + COF = cAgent.agentCOF; + if(ControllingClient.IsGroupMember(cAgent.ActiveGroupID)) + { + ControllingClient.ActiveGroupId = cAgent.ActiveGroupID; + ControllingClient.ActiveGroupName = cAgent.ActiveGroupName; + Grouptitle = cAgent.ActiveGroupTitle; + ControllingClient.ActiveGroupPowers = + ControllingClient.GetGroupPowers(cAgent.ActiveGroupID); + } + else + { + // we got a unknown active group so get what groups thinks about us + IGroupsModule gm = m_scene.RequestModuleInterface(); + if (gm != null) + gm.SendAgentGroupDataUpdate(ControllingClient); + } + } + lock (m_originRegionIDAccessLock) m_originRegionID = cAgent.RegionID; } @@ -4083,7 +4911,7 @@ namespace OpenSim.Region.Framework.Scenes public bool CopyAgent(out IAgentData agent) { agent = new CompleteAgentData(); - CopyTo((AgentData)agent); + CopyTo((AgentData)agent, false); return true; } @@ -4094,15 +4922,21 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateMovement() { - if (m_forceToApply.HasValue) - { - Vector3 force = m_forceToApply.Value; +/* + if (IsInTransit) + return; - Velocity = force; + lock(m_forceToApplyLock) + { + if (m_forceToApplyValid) + { + Velocity = m_forceToApply; - m_forceToApply = null; - TriggerScenePresenceUpdated(); + m_forceToApplyValid = false; + TriggerScenePresenceUpdated(); + } } +*/ } /// @@ -4124,22 +4958,23 @@ namespace OpenSim.Region.Framework.Scenes if (Appearance.AvatarHeight == 0) // Appearance.SetHeight(); Appearance.SetSize(new Vector3(0.45f,0.6f,1.9f)); - -/* - PhysicsActor = scene.AddAvatar( - LocalId, Firstname + "." + Lastname, pVec, - new Vector3(0.45f, 0.6f, Appearance.AvatarHeight), isFlying); -*/ - PhysicsActor = m_scene.PhysicsScene.AddAvatar( - LocalId, Firstname + "." + Lastname, AbsolutePosition, Velocity, - Appearance.AvatarBoxSize, isFlying); +// lock(m_forceToApplyLock) +// m_forceToApplyValid = false; + PhysicsScene scene = m_scene.PhysicsScene; + Vector3 pVec = AbsolutePosition; + + PhysicsActor = scene.AddAvatar( + LocalId, Firstname + "." + Lastname, pVec, + Appearance.AvatarBoxSize,Appearance.AvatarFeetOffset, isFlying); + PhysicsActor.Orientation = m_bodyRot; //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong PhysicsActor.SubscribeEvents(100); PhysicsActor.LocalID = LocalId; + PhysicsActor.SetAlwaysRun = m_setAlwaysRun; } private void OutOfBoundsCall(Vector3 pos) @@ -4152,7 +4987,6 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendAgentAlertMessage("Physics is having a problem with your avatar. You may not be able to move until you relog.", true); } - /// /// Event called by the physics plugin to tell the avatar about a collision. /// @@ -4166,24 +5000,26 @@ namespace OpenSim.Region.Framework.Scenes /// public void PhysicsCollisionUpdate(EventArgs e) { - if (IsChildAgent || Animator == null) + if (IsChildAgent) + return; + + if(IsInTransit) return; - + //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) // The Physics Scene will send updates every 500 ms grep: PhysicsActor.SubscribeEvents( // as of this comment the interval is set in AddToPhysicalScene // if (m_updateCount > 0) // { - if (Animator.UpdateMovementAnimations()) - TriggerScenePresenceUpdated(); +// if (Animator != null && Animator.UpdateMovementAnimations()) +// TriggerScenePresenceUpdated(); // m_updateCount--; // } CollisionEventUpdate collisionData = (CollisionEventUpdate)e; Dictionary coldata = collisionData.m_objCollisionList; - // // No collisions at all means we may be flying. Update always // // to make falling work // if (m_lastColCount != coldata.Count || coldata.Count == 0) @@ -4192,81 +5028,98 @@ namespace OpenSim.Region.Framework.Scenes // m_lastColCount = coldata.Count; // } - CollisionPlane = Vector4.UnitW; + if (coldata.Count != 0) + { + ContactPoint lowest; + lowest.SurfaceNormal = Vector3.Zero; + lowest.Position = Vector3.Zero; + lowest.Position.Z = float.MaxValue; - // Gods do not take damage and Invulnerable is set depending on parcel/region flags - if (Invulnerable || GodLevel > 0) - return; + foreach (ContactPoint contact in coldata.Values) + { + if (contact.CharacterFeet && contact.Position.Z < lowest.Position.Z) + lowest = contact; + } - // The following may be better in the ICombatModule - // probably tweaking of the values for ground and normal prim collisions will be needed - float starthealth = Health; - uint killerObj = 0; - SceneObjectPart part = null; - foreach (uint localid in coldata.Keys) - { - if (localid == 0) + if (lowest.Position.Z != float.MaxValue) { - part = null; + lowest.SurfaceNormal = -lowest.SurfaceNormal; + CollisionPlane = new Vector4(lowest.SurfaceNormal, Vector3.Dot(lowest.Position, lowest.SurfaceNormal)); } else + CollisionPlane = Vector4.UnitW; + } + else + CollisionPlane = Vector4.UnitW; + + RaiseCollisionScriptEvents(coldata); + + // Gods do not take damage and Invulnerable is set depending on parcel/region flags + if (Invulnerable || IsViewerUIGod) + return; + + // The following may be better in the ICombatModule + // probably tweaking of the values for ground and normal prim collisions will be needed + float startHealth = Health; + if(coldata.Count > 0) + { + uint killerObj = 0; + SceneObjectPart part = null; + float rvel; // relative velocity, negative on approch + foreach (uint localid in coldata.Keys) { - part = Scene.GetSceneObjectPart(localid); - } - if (part != null) - { - // Ignore if it has been deleted or volume detect - if (!part.ParentGroup.IsDeleted && !part.ParentGroup.IsVolumeDetect) + if (localid == 0) { - if (part.ParentGroup.Damage > 0.0f) + // 0 is the ground + rvel = coldata[0].RelativeSpeed; + if(rvel < -5.0f) + Health -= 0.01f * rvel * rvel; + } + else + { + part = Scene.GetSceneObjectPart(localid); + + if(part != null && !part.ParentGroup.IsVolumeDetect) { - // Something with damage... - Health -= part.ParentGroup.Damage; - part.ParentGroup.Scene.DeleteSceneObject(part.ParentGroup, false); + if (part.ParentGroup.Damage > 0.0f) + { + // Something with damage... + Health -= part.ParentGroup.Damage; + part.ParentGroup.Scene.DeleteSceneObject(part.ParentGroup, false); + } + else + { + // An ordinary prim + rvel = coldata[localid].RelativeSpeed; + if(rvel < -5.0f) + { + Health -= 0.005f * rvel * rvel; + } + } } else { - // An ordinary prim - if (coldata[localid].PenetrationDepth >= 0.10f) - Health -= coldata[localid].PenetrationDepth * 5.0f; + } } - } - else - { - // 0 is the ground - // what about collisions with other avatars? - if (localid == 0 && coldata[localid].PenetrationDepth >= 0.10f) - Health -= coldata[localid].PenetrationDepth * 5.0f; - } - - if (Health <= 0.0f) - { - if (localid != 0) - killerObj = localid; - } - //m_log.Debug("[AVATAR]: Collision with localid: " + localid.ToString() + " at depth: " + coldata[localid].ToString()); - } - //Health = 100; - if (!Invulnerable) - { - if (starthealth != Health) - { - ControllingClient.SendHealth(Health); + if (Health <= 0.0f) + { + if (localid != 0) + killerObj = localid; + } } + if (Health <= 0) { - m_scene.EventManager.TriggerAvatarKill(killerObj, this); - } - if (starthealth == Health && Health < 100.0f) - { - Health += 0.03f; - if (Health > 100.0f) - Health = 100.0f; ControllingClient.SendHealth(Health); + m_scene.EventManager.TriggerAvatarKill(killerObj, this); + return; } } + + if(Math.Abs(Health - startHealth) > 1.0) + ControllingClient.SendHealth(Health); } public void setHealthWithUpdate(float health) @@ -4280,25 +5133,25 @@ namespace OpenSim.Region.Framework.Scenes // Clear known regions KnownRegions = new Dictionary(); - lock (m_reprioritization_timer) - { - m_reprioritization_timer.Enabled = false; - m_reprioritization_timer.Elapsed -= new ElapsedEventHandler(Reprioritize); - } - // I don't get it but mono crashes when you try to dispose of this timer, // unsetting the elapsed callback should be enough to allow for cleanup however. - // m_reprioritizationTimer.Dispose(); + // m_reprioritizationTimer.Dispose(); RemoveFromPhysicalScene(); - + m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; + RemoveClientEvents(); // if (Animator != null) // Animator.Close(); Animator = null; + scriptedcontrols.Clear(); + ControllingClient = null; LifecycleState = ScenePresenceState.Removed; + IsDeleted = true; + m_updateAgentReceivedAfterTransferEvent.Dispose(); + m_updateAgentReceivedAfterTransferEvent = null; } public void AddAttachment(SceneObjectGroup gobj) @@ -4311,6 +5164,10 @@ namespace OpenSim.Region.Framework.Scenes m_attachments.Add(gobj); } + + IBakedTextureModule bakedModule = m_scene.RequestModuleInterface(); + if (bakedModule != null) + bakedModule.UpdateMeshAvatar(m_uuid); } /// @@ -4343,7 +5200,7 @@ namespace OpenSim.Region.Framework.Scenes } } } - + return attachments; } @@ -4474,6 +5331,287 @@ namespace OpenSim.Region.Framework.Scenes return validated; } + public void SendAttachmentsToAllAgents() + { + lock (m_attachments) + { + foreach (SceneObjectGroup sog in m_attachments) + { + m_scene.ForEachScenePresence(delegate(ScenePresence p) + { + if (p != this && sog.HasPrivateAttachmentPoint) + return; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; + + SendTerseUpdateToAgentNF(p); + SendAttachmentFullUpdateToAgentNF(sog, p); + }); + } + } + } + + // send attachments to a client without filters except for huds + // for now they are checked in several places down the line... + public void SendAttachmentsToAgentNF(ScenePresence p) + { + SendTerseUpdateToAgentNF(p); +// SendAvatarDataToAgentNF(this); + lock (m_attachments) + { + foreach (SceneObjectGroup sog in m_attachments) + { + SendAttachmentFullUpdateToAgentNF(sog, p); + } + } + } + + public void SendAttachmentFullUpdateToAgentNF(SceneObjectGroup sog, ScenePresence p) + { + if (p != this && sog.HasPrivateAttachmentPoint) + return; + + SceneObjectPart[] parts = sog.Parts; + SceneObjectPart rootpart = sog.RootPart; + + p.ControllingClient.SendEntityUpdate(rootpart, PrimUpdateFlags.FullUpdate); + + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part == rootpart) + continue; + p.ControllingClient.SendEntityUpdate(part, PrimUpdateFlags.FullUpdate); + } + } + + public void SendAttachmentScheduleUpdate(SceneObjectGroup sog) + { + if (IsChildAgent || IsInTransit) + return; + + SceneObjectPart[] origparts = sog.Parts; + SceneObjectPart[] parts = new SceneObjectPart[origparts.Length]; + PrimUpdateFlags[] flags = new PrimUpdateFlags[origparts.Length]; + + SceneObjectPart rootpart = sog.RootPart; + UpdateRequired rootreq = sog.RootPart.UpdateFlag; + + int j = 0; + bool allterse = true; + for (int i = 0; i < origparts.Length; i++) + { + if (origparts[i] != rootpart) + { + switch (origparts[i].UpdateFlag) + { + case UpdateRequired.NONE: + break; + + case UpdateRequired.TERSE: + flags[j] = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + parts[j] = origparts[i]; + j++; + break; + + case UpdateRequired.FULL: + flags[j] = PrimUpdateFlags.FullUpdate; + allterse = false; + parts[j] = origparts[i]; + j++; + break; + } + } + origparts[i].UpdateFlag = 0; + } + + if (j == 0 && rootreq == UpdateRequired.NONE) + return; + + PrimUpdateFlags rootflag = PrimUpdateFlags.FullUpdate; + + if (rootreq != UpdateRequired.FULL && allterse) + { + rootflag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + } + + int nparts = j; + + ControllingClient.SendEntityUpdate(rootpart, rootflag); + + for (int i = 0; i < nparts; i++) + { + ControllingClient.SendEntityUpdate(parts[i], flags[i]); + } + + if (sog.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(rootpart, rootflag); + + for (int i = 0; i < nparts; i++) + { + p.ControllingClient.SendEntityUpdate(parts[i], flags[i]); + } + } + } + + public void SendAttachmentUpdate(SceneObjectGroup sog, UpdateRequired UpdateFlag) + { + if (IsChildAgent || IsInTransit) + return; + + PrimUpdateFlags flag; + switch (UpdateFlag) + { + case UpdateRequired.TERSE: + flag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + break; + + case UpdateRequired.FULL: + flag = PrimUpdateFlags.FullUpdate; + break; + + default: + return; + } + + SceneObjectPart[] parts = sog.Parts; + SceneObjectPart rootpart = sog.RootPart; + +// rootpart.UpdateFlag = 0; + + ControllingClient.SendEntityUpdate(rootpart, flag); + + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part == rootpart) + continue; + ControllingClient.SendEntityUpdate(part, flag); +// part.UpdateFlag = 0; + } + + if (sog.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(rootpart, flag); + + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part == rootpart) + continue; + p.ControllingClient.SendEntityUpdate(part, flag); + } + } + } + + public void SendAttachmentScheduleUpdate(SceneObjectPart part) + { + if (IsChildAgent || IsInTransit) + return; + + + PrimUpdateFlags flag; + switch (part.UpdateFlag) + { + case UpdateRequired.TERSE: + flag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + break; + + case UpdateRequired.FULL: + flag = PrimUpdateFlags.FullUpdate; + break; + + default: + return; + } + + part.UpdateFlag = 0; + + ControllingClient.SendEntityUpdate(part, flag); + + if (part.ParentGroup.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(part, flag); + } + } + + + public void SendAttachmentUpdate(SceneObjectPart part, UpdateRequired UpdateFlag) + { + if (IsChildAgent || IsInTransit) + return; + + PrimUpdateFlags flag; + switch (UpdateFlag) + { + case UpdateRequired.TERSE: + flag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + break; + + case UpdateRequired.FULL: + flag = PrimUpdateFlags.FullUpdate; + break; + + default: + return; + } + +// part.UpdateFlag = 0; + + ControllingClient.SendEntityUpdate(part, flag); + + if (part.ParentGroup.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(part, flag); + } + } + /// /// Send a script event to this scene presence's attachments /// @@ -4530,10 +5668,21 @@ namespace OpenSim.Region.Framework.Scenes } } + CameraData physActor_OnPhysicsRequestingCameraData() + { + return new CameraData + { + Valid = true, + MouseLook = this.m_mouseLook, + CameraRotation = this.CameraRotation, + CameraAtAxis = this.CameraAtAxis + }; + } + public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID) { - SceneObjectPart p = m_scene.GetSceneObjectPart(Obj_localID); - if (p == null) + SceneObjectPart part = m_scene.GetSceneObjectPart(Obj_localID); + if (part == null) return; ControllingClient.SendTakeControls(controls, false, false); @@ -4543,7 +5692,7 @@ namespace OpenSim.Region.Framework.Scenes obj.ignoreControls = ScriptControlled.CONTROL_ZERO; obj.eventControls = ScriptControlled.CONTROL_ZERO; - obj.objectID = p.ParentGroup.UUID; + obj.objectID = part.ParentGroup.UUID; obj.itemID = Script_item_UUID; if (pass_on == 0 && accept == 0) { @@ -4562,7 +5711,6 @@ namespace OpenSim.Region.Framework.Scenes { IgnoredControls = ScriptControlled.CONTROL_ZERO; obj.eventControls = (ScriptControlled)controls; - obj.ignoreControls = ScriptControlled.CONTROL_ZERO; } lock (scriptedcontrols) @@ -4571,19 +5719,52 @@ namespace OpenSim.Region.Framework.Scenes { IgnoredControls &= ~(ScriptControlled)controls; if (scriptedcontrols.ContainsKey(Script_item_UUID)) - scriptedcontrols.Remove(Script_item_UUID); + RemoveScriptFromControlNotifications(Script_item_UUID, part); } else { - scriptedcontrols[Script_item_UUID] = obj; + AddScriptToControlNotifications(Script_item_UUID, part, ref obj); } } ControllingClient.SendTakeControls(controls, pass_on == 1 ? true : false, true); } + private void AddScriptToControlNotifications(OpenMetaverse.UUID Script_item_UUID, SceneObjectPart part, ref ScriptControllers obj) + { + scriptedcontrols[Script_item_UUID] = obj; + + PhysicsActor physActor = part.ParentGroup.RootPart.PhysActor; + if (physActor != null) + { + physActor.OnPhysicsRequestingCameraData -= physActor_OnPhysicsRequestingCameraData; + physActor.OnPhysicsRequestingCameraData += physActor_OnPhysicsRequestingCameraData; + } + } + + private void RemoveScriptFromControlNotifications(OpenMetaverse.UUID Script_item_UUID, SceneObjectPart part) + { + scriptedcontrols.Remove(Script_item_UUID); + + if (part != null) + { + PhysicsActor physActor = part.ParentGroup.RootPart.PhysActor; + if (physActor != null) + { + physActor.OnPhysicsRequestingCameraData -= physActor_OnPhysicsRequestingCameraData; + } + } + } + public void HandleForceReleaseControls(IClientAPI remoteClient, UUID agentID) { + foreach (ScriptControllers c in scriptedcontrols.Values) + { + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(c.objectID); + if(sog != null && !sog.IsDeleted && sog.RootPart.PhysActor != null) + sog.RootPart.PhysActor.OnPhysicsRequestingCameraData -= physActor_OnPhysicsRequestingCameraData; + } + IgnoredControls = ScriptControlled.CONTROL_ZERO; lock (scriptedcontrols) { @@ -4592,7 +5773,36 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendTakeControls(int.MaxValue, false, false); } - private void UnRegisterSeatControls(UUID obj) + public void HandleRevokePermissions(UUID objectID, uint permissions ) + { + + // still skeleton code + if((permissions & (16 | 0x8000 )) == 0) //PERMISSION_TRIGGER_ANIMATION | PERMISSION_OVERRIDE_ANIMATIONS + return; + if(objectID == m_scene.RegionInfo.RegionID) // for all objects + { + + } + else + { + SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); + if(part != null) + { + + } + } + } + + public void ClearControls() + { + IgnoredControls = ScriptControlled.CONTROL_ZERO; + lock (scriptedcontrols) + { + scriptedcontrols.Clear(); + } + } + + public void UnRegisterSeatControls(UUID obj) { List takers = new List(); @@ -4610,17 +5820,18 @@ namespace OpenSim.Region.Framework.Scenes public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID) { ScriptControllers takecontrols; + SceneObjectPart part = m_scene.GetSceneObjectPart(Obj_localID); lock (scriptedcontrols) { if (scriptedcontrols.TryGetValue(Script_item_UUID, out takecontrols)) { - ScriptControlled sctc = takecontrols.eventControls; + ScriptControlled sctc = takecontrols.eventControls; ControllingClient.SendTakeControls((int)sctc, false, false); ControllingClient.SendTakeControls((int)sctc, true, false); - scriptedcontrols.Remove(Script_item_UUID); + RemoveScriptFromControlNotifications(Script_item_UUID, part); IgnoredControls = ScriptControlled.CONTROL_ZERO; foreach (ScriptControllers scData in scriptedcontrols.Values) { @@ -4639,46 +5850,38 @@ namespace OpenSim.Region.Framework.Scenes if (scriptedcontrols.Count <= 0) return; - ScriptControlled allflags = ScriptControlled.CONTROL_ZERO; - - if (MouseDown) + ScriptControlled allflags; + // convert mouse from edge to level + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || + (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0) { - allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON); - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0) - { - allflags = ScriptControlled.CONTROL_ZERO; - MouseDown = true; - } + allflags = ScriptControlled.CONTROL_ZERO; } - + else // recover last state of mouse + allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON); + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN) != 0) - { allflags |= ScriptControlled.CONTROL_ML_LBUTTON; - MouseDown = true; - } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0) - { allflags |= ScriptControlled.CONTROL_LBUTTON; - MouseDown = true; - } - + // find all activated controls, whether the scripts are interested in them or not if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) != 0) { allflags |= ScriptControlled.CONTROL_FWD; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) != 0) { allflags |= ScriptControlled.CONTROL_BACK; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS) != 0) { allflags |= ScriptControlled.CONTROL_UP; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0) { allflags |= ScriptControlled.CONTROL_DOWN; @@ -4688,17 +5891,17 @@ namespace OpenSim.Region.Framework.Scenes { allflags |= ScriptControlled.CONTROL_LEFT; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) != 0) { allflags |= ScriptControlled.CONTROL_RIGHT; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) { allflags |= ScriptControlled.CONTROL_ROT_RIGHT; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) { allflags |= ScriptControlled.CONTROL_ROT_LEFT; @@ -4711,7 +5914,7 @@ namespace OpenSim.Region.Framework.Scenes { UUID scriptUUID = kvp.Key; ScriptControllers scriptControlData = kvp.Value; - + ScriptControlled localHeld = allflags & scriptControlData.eventControls; // the flags interesting for us ScriptControlled localLast = LastCommands & scriptControlData.eventControls; // the activated controls in the last cycle ScriptControlled localChange = localHeld ^ localLast; // the changed bits @@ -4723,8 +5926,9 @@ namespace OpenSim.Region.Framework.Scenes } } } - + LastCommands = allflags; + MouseDown = (allflags & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON)) != 0; } } @@ -4765,191 +5969,252 @@ namespace OpenSim.Region.Framework.Scenes return flags; } - private void ReprioritizeUpdates() + // returns true it local teleport allowed and sets the destiny position into pos + + private bool CheckLocalTPLandingPoint(ref Vector3 pos) { - if (Scene.IsReprioritizationEnabled && Scene.UpdatePrioritizationScheme != UpdatePrioritizationSchemes.Time) - { - lock (m_reprioritization_timer) - { - if (!m_reprioritizing) - m_reprioritization_timer.Enabled = m_reprioritizing = true; - else - m_reprioritization_called = true; - } - } - } + // Never constrain lures + if ((TeleportFlags & TeleportFlags.ViaLure) != 0) + return true; - private void Reprioritize(object sender, ElapsedEventArgs e) - { - ControllingClient.ReprioritizeUpdates(); + if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) + return true; - lock (m_reprioritization_timer) + // do not constrain gods and estate managers + if(m_scene.Permissions.IsGod(m_uuid) || + m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) + return true; + + // will teleport to a telehub spawn point or landpoint if that results in getting closer to target + // if not the local teleport fails. + + float currDistanceSQ = Vector3.DistanceSquared(AbsolutePosition, pos); + + // first check telehub + + UUID TelehubObjectID = m_scene.RegionInfo.RegionSettings.TelehubObject; + if ( TelehubObjectID != UUID.Zero) { - m_reprioritization_timer.Enabled = m_reprioritizing = m_reprioritization_called; - m_reprioritization_called = false; - } - } + SceneObjectGroup telehubSOG = m_scene.GetSceneObjectGroup(TelehubObjectID); + if(telehubSOG != null) + { + Vector3 spawnPos; + float spawnDistSQ; - private void CheckLandingPoint(ref Vector3 pos) - { - // Never constrain lures - if ((TeleportFlags & TeleportFlags.ViaLure) != 0) - return; + SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); + if(spawnPoints.Length == 0) + { + spawnPos = new Vector3(128.0f, 128.0f, pos.Z); + spawnDistSQ = Vector3.DistanceSquared(spawnPos, pos); + } + else + { + Vector3 hubPos = telehubSOG.AbsolutePosition; + Quaternion hubRot = telehubSOG.GroupRotation; - if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) - return; + spawnPos = spawnPoints[0].GetLocation(hubPos, hubRot); + spawnDistSQ = Vector3.DistanceSquared(spawnPos, pos); + + float testDistSQ; + Vector3 testSpawnPos; + for(int i = 1; i< spawnPoints.Length; i++) + { + testSpawnPos = spawnPoints[i].GetLocation(hubPos, hubRot); + testDistSQ = Vector3.DistanceSquared(testSpawnPos, pos); + + if(testDistSQ < spawnDistSQ) + { + spawnPos = testSpawnPos; + spawnDistSQ = testDistSQ; + } + } + } + if (currDistanceSQ < spawnDistSQ) + { + // we are already close + ControllingClient.SendAlertMessage("Can't teleport closer to destination"); + return false; + } + else + { + pos = spawnPos; + return true; + } + } + } ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); - if (land.LandData.LandingType == (byte)LandingType.LandingPoint && - land.LandData.UserLocation != Vector3.Zero && - land.LandData.OwnerID != m_uuid && - (!m_scene.Permissions.IsGod(m_uuid)) && - (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))) + if (land.LandData.LandingType != (byte)LandingType.LandingPoint + || land.LandData.OwnerID == m_uuid) + return true; + + Vector3 landLocation = land.LandData.UserLocation; + if(landLocation == Vector3.Zero) + return true; + + if (currDistanceSQ < Vector3.DistanceSquared(landLocation, pos)) { - float curr = Vector3.Distance(AbsolutePosition, pos); - if (Vector3.Distance(land.LandData.UserLocation, pos) < curr) - pos = land.LandData.UserLocation; - else - ControllingClient.SendAlertMessage("Can't teleport closer to destination"); + ControllingClient.SendAlertMessage("Can't teleport closer to destination"); + return false; } + + pos = land.LandData.UserLocation; + return true; } - private void CheckAndAdjustTelehub(SceneObjectGroup telehub, ref Vector3 pos) + const TeleportFlags TeleHubTPFlags = TeleportFlags.ViaLogin + | TeleportFlags.ViaHGLogin | TeleportFlags.ViaLocation; + + private bool CheckAndAdjustTelehub(SceneObjectGroup telehub, ref Vector3 pos, ref bool positionChanged) { - if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == - (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) || - (m_scene.TelehubAllowLandmarks == true ? false : ((m_teleportFlags & TeleportFlags.ViaLandmark) != 0 )) || - (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || - (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) + // forcing telehubs on any tp that reachs this + if ((m_teleportFlags & TeleHubTPFlags) != 0 || + (m_scene.TelehubAllowLandmarks == true ? false : ((m_teleportFlags & TeleportFlags.ViaLandmark) != 0 ))) { + ILandObject land; + Vector3 teleHubPosition = telehub.AbsolutePosition; - if (GodLevel < 200 && - ((!m_scene.Permissions.IsGod(m_uuid) && - !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || - (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || - (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)) + SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); + if(spawnPoints.Length == 0) { - SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); - if (spawnPoints.Length == 0) + land = m_scene.LandChannel.GetLandObject(teleHubPosition.X,teleHubPosition.Y); + if(land != null) { - if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) - { - pos.X = 128.0f; - pos.Y = 128.0f; - } - return; + pos = teleHubPosition; + if(land.IsEitherBannedOrRestricted(UUID)) + return false; + positionChanged = true; + return true; } + else + return false; + } - int index; - bool selected = false; - - switch (m_scene.SpawnPointRouting) - { - case "random": + int index; + int tries; + bool selected = false; + bool validhub = false; + Vector3 spawnPosition; - if (spawnPoints.Length == 0) - return; - do - { - index = Util.RandomClass.Next(spawnPoints.Length - 1); - - Vector3 spawnPosition = spawnPoints[index].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - // SpawnPoint sp = spawnPoints[index]; + Quaternion teleHubRotation = telehub.GroupRotation; - ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); + switch(m_scene.SpawnPointRouting) + { + case "random": + tries = spawnPoints.Length; + if(tries < 3) // no much sense in random with a few points when there same can have bans + goto case "sequence"; + do + { + index = Util.RandomClass.Next(spawnPoints.Length - 1); - if (land == null || land.IsEitherBannedOrRestricted(UUID)) - selected = false; - else - selected = true; + spawnPosition = spawnPoints[index].GetLocation(teleHubPosition, teleHubRotation); + land = m_scene.LandChannel.GetLandObject(spawnPosition.X,spawnPosition.Y); + if(land != null && !land.IsEitherBannedOrRestricted(UUID)) + selected = true; - } while ( selected == false); + } while(selected == false && --tries > 0 ); - pos = spawnPoints[index].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - return; + if(tries <= 0) + goto case "sequence"; - case "sequence": + pos = spawnPosition; + return true; - do + case "sequence": + tries = spawnPoints.Length; + selected = false; + validhub = false; + do + { + index = m_scene.SpawnPoint(); + spawnPosition = spawnPoints[index].GetLocation(teleHubPosition, teleHubRotation); + land = m_scene.LandChannel.GetLandObject(spawnPosition.X,spawnPosition.Y); + if(land != null) { - index = m_scene.SpawnPoint(); - - Vector3 spawnPosition = spawnPoints[index].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - // SpawnPoint sp = spawnPoints[index]; - - ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); - if (land == null || land.IsEitherBannedOrRestricted(UUID)) + validhub = true; + if(land.IsEitherBannedOrRestricted(UUID)) selected = false; else selected = true; + } - } while (selected == false); + } while(selected == false && --tries > 0); - pos = spawnPoints[index].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); - ; - return; + if(!validhub) + return false; - default: - case "closest": + pos = spawnPosition; - float distance = 9999; - int closest = -1; - - for (int i = 0; i < spawnPoints.Length; i++) - { - Vector3 spawnPosition = spawnPoints[i].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - Vector3 offset = spawnPosition - pos; - float d = Vector3.Mag(offset); - if (d >= distance) - continue; - ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); - if (land == null) - continue; - if (land.IsEitherBannedOrRestricted(UUID)) - continue; - distance = d; - closest = i; - } - if (closest == -1) - return; - - pos = spawnPoints[closest].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); - return; + if(!selected) + return false; + positionChanged = true; + return true; - } + default: + case "closest": + float distancesq = float.MaxValue; + int closest = -1; + validhub = false; + + for(int i = 0; i < spawnPoints.Length; i++) + { + spawnPosition = spawnPoints[i].GetLocation(teleHubPosition, teleHubRotation); + Vector3 offset = spawnPosition - pos; + float dsq = offset.LengthSquared(); + land = m_scene.LandChannel.GetLandObject(spawnPosition.X,spawnPosition.Y); + if(land == null) + continue; + + validhub = true; + if(land.IsEitherBannedOrRestricted(UUID)) + continue; + + if(dsq >= distancesq) + continue; + distancesq = dsq; + closest = i; + } + + if(!validhub) + return false; + + if(closest < 0) + { + pos = spawnPoints[0].GetLocation(teleHubPosition, teleHubRotation); + positionChanged = true; + return false; + } + + pos = spawnPoints[closest].GetLocation(teleHubPosition, teleHubRotation); + positionChanged = true; + return true; } } + return false; } + const TeleportFlags adicionalLandPointFlags = TeleportFlags.ViaLandmark | + TeleportFlags.ViaLocation | TeleportFlags.ViaHGLogin; + // Modify landing point based on possible banning, telehubs or parcel restrictions. - private void CheckAndAdjustLandingPoint(ref Vector3 pos) + // This is the behavior in OpenSim for a very long time, different from SL + private bool CheckAndAdjustLandingPoint_OS(ref Vector3 pos, ref Vector3 lookat, ref bool positionChanged) { string reason; // Honor bans if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y)) - return; + return false; SceneObjectGroup telehub = null; if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) { if (!m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) { - CheckAndAdjustTelehub(telehub, ref pos); - return; + CheckAndAdjustTelehub(telehub, ref pos, ref positionChanged); + return true; } } @@ -4964,27 +6229,84 @@ namespace OpenSim.Region.Framework.Scenes // to ignore them. if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) || - (m_teleportFlags & TeleportFlags.ViaLandmark) != 0 || - (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || - (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) + (m_teleportFlags & adicionalLandPointFlags) != 0) { // Don't restrict gods, estate managers, or land owners to // the TP point. This behaviour mimics agni. if (land.LandData.LandingType == (byte)LandingType.LandingPoint && land.LandData.UserLocation != Vector3.Zero && - GodLevel < 200 && - ((land.LandData.OwnerID != m_uuid && + !IsViewerUIGod && + ((land.LandData.OwnerID != m_uuid && !m_scene.Permissions.IsGod(m_uuid) && - !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || + !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)) { pos = land.LandData.UserLocation; + positionChanged = true; } } - + land.SendLandUpdateToClient(ControllingClient); } + + return true; + } + + // Modify landing point based on telehubs or parcel restrictions. + // This is a behavior coming from AVN, somewhat mimicking SL + private bool CheckAndAdjustLandingPoint_SL(ref Vector3 pos, ref Vector3 lookat, ref bool positionChanged) + { + string reason; + + // dont mess with gods + if(IsGod) + return true; + + // respect region owner and managers +// if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) +// return true; + + if (!m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) + { + SceneObjectGroup telehub = null; + if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) + { + if(CheckAndAdjustTelehub(telehub, ref pos, ref positionChanged)) + return true; + } + } + + // Honor bans, actually we don't honour them + if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y)) + return false; + + ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); + if (land != null) + { + if (Scene.DebugTeleporting) + TeleportFlagsDebug(); + + // If we come in via login, landmark or map, we want to + // honor landing points. If we come in via Lure, we want + // to ignore them. + if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == + (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) + || (m_teleportFlags & adicionalLandPointFlags) != 0) + { + if (land.LandData.LandingType == (byte)LandingType.LandingPoint && + land.LandData.UserLocation != Vector3.Zero ) + // && + // land.LandData.OwnerID != m_uuid ) + { + pos = land.LandData.UserLocation; + if(land.LandData.UserLookAt != Vector3.Zero) + lookat = land.LandData.UserLookAt; + positionChanged = true; + } + } + } + return true; } private DetectedObject CreateDetObject(SceneObjectPart obj) @@ -4998,6 +6320,7 @@ namespace OpenSim.Region.Framework.Scenes detobj.velVector = obj.Velocity; detobj.colliderType = 0; detobj.groupUUID = obj.GroupID; + detobj.linkNumber = 0; return detobj; } @@ -5011,8 +6334,13 @@ namespace OpenSim.Region.Framework.Scenes detobj.posVector = av.AbsolutePosition; detobj.rotQuat = av.Rotation; detobj.velVector = av.Velocity; - detobj.colliderType = 0; + detobj.colliderType = av.IsNPC ? 0x20 : 0x1; // OpenSim\Region\ScriptEngine\Shared\Helpers.cs + if(av.IsSatOnObject) + detobj.colliderType |= 0x4; //passive + else if(detobj.velVector != Vector3.Zero) + detobj.colliderType |= 0x2; //active detobj.groupUUID = av.ControllingClient.ActiveGroupId; + detobj.linkNumber = 0; return detobj; } @@ -5028,7 +6356,7 @@ namespace OpenSim.Region.Framework.Scenes detobj.velVector = Vector3.Zero; detobj.colliderType = 0; detobj.groupUUID = UUID.Zero; - + detobj.linkNumber = 0; return detobj; } @@ -5095,29 +6423,404 @@ namespace OpenSim.Region.Framework.Scenes } } + private void RaiseCollisionScriptEvents(Dictionary coldata) + { + try + { + List thisHitColliders = new List(); + List endedColliders = new List(); + List startedColliders = new List(); + + if (coldata.Count == 0) + { + if (m_lastColliders.Count == 0) + return; // nothing to do + + foreach (uint localID in m_lastColliders) + { + endedColliders.Add(localID); + } + m_lastColliders.Clear(); + } + else + { + List soundinfolist = new List(); + if(ParcelAllowThisAvatarSounds) + { + CollisionForSoundInfo soundinfo; + ContactPoint curcontact; + + foreach (uint id in coldata.Keys) + { + thisHitColliders.Add(id); + if (!m_lastColliders.Contains(id)) + { + startedColliders.Add(id); + curcontact = coldata[id]; + if (Math.Abs(curcontact.RelativeSpeed) > 0.2) + { + soundinfo = new CollisionForSoundInfo(); + soundinfo.colliderID = id; + soundinfo.position = curcontact.Position; + soundinfo.relativeVel = curcontact.RelativeSpeed; + soundinfolist.Add(soundinfo); + } + } + } + } + else + { + foreach (uint id in coldata.Keys) + { + thisHitColliders.Add(id); + if (!m_lastColliders.Contains(id)) + startedColliders.Add(id); + } + } + // calculate things that ended colliding + foreach (uint localID in m_lastColliders) + { + if (!thisHitColliders.Contains(localID)) + { + endedColliders.Add(localID); + } + } + //add the items that started colliding this time to the last colliders list. + foreach (uint localID in startedColliders) + { + m_lastColliders.Add(localID); + } + // remove things that ended colliding from the last colliders list + foreach (uint localID in endedColliders) + { + m_lastColliders.Remove(localID); + } + + if (soundinfolist.Count > 0) + CollisionSounds.AvatarCollisionSound(this, soundinfolist); + } + + foreach (SceneObjectGroup att in GetAttachments()) + { + SendCollisionEvent(att, scriptEvents.collision_start, startedColliders, m_scene.EventManager.TriggerScriptCollidingStart); + SendCollisionEvent(att, scriptEvents.collision , m_lastColliders , m_scene.EventManager.TriggerScriptColliding); + SendCollisionEvent(att, scriptEvents.collision_end , endedColliders , m_scene.EventManager.TriggerScriptCollidingEnd); + + if (startedColliders.Contains(0)) + SendLandCollisionEvent(att, scriptEvents.land_collision_start, m_scene.EventManager.TriggerScriptLandCollidingStart); + if (m_lastColliders.Contains(0)) + SendLandCollisionEvent(att, scriptEvents.land_collision, m_scene.EventManager.TriggerScriptLandColliding); + if (endedColliders.Contains(0)) + SendLandCollisionEvent(att, scriptEvents.land_collision_end, m_scene.EventManager.TriggerScriptLandCollidingEnd); + } + } + catch { } +// finally +// { +// m_collisionEventFlag = false; +// } + } + private void TeleportFlagsDebug() { - + // Some temporary debugging help to show all the TeleportFlags we have... bool HG = false; if((m_teleportFlags & TeleportFlags.ViaHGLogin) == TeleportFlags.ViaHGLogin) HG = true; - + m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); - + uint i = 0u; for (int x = 0; x <= 30 ; x++, i = 1u << x) { i = 1u << x; - + if((m_teleportFlags & (TeleportFlags)i) == (TeleportFlags)i) if (HG == false) m_log.InfoFormat("[SCENE PRESENCE]: Teleport Flags include {0}", ((TeleportFlags) i).ToString()); else m_log.InfoFormat("[SCENE PRESENCE]: HG Teleport Flags include {0}", ((TeleportFlags)i).ToString()); } - + m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); - + + } + + private void parcelGodCheck(UUID currentParcelID) + { + List allpresences = m_scene.GetScenePresences(); + + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p.IsChildAgent || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + if (p.ParcelHideThisAvatar && p.currentParcelUUID != currentParcelID) + { + if (IsViewerUIGod) + p.SendViewTo(this); + else + p.SendKillTo(this); + } + } + } + + private void ParcelCrossCheck(UUID currentParcelID,UUID previusParcelID, + bool currentParcelHide, bool previusParcelHide, bool oldhide, bool check) + { + List killsToSendto = new List(); + List killsToSendme = new List(); + List viewsToSendto = new List(); + List viewsToSendme = new List(); + List allpresences = null; + + if (IsInTransit || IsChildAgent) + return; + + if (check) + { + // check is relative to current parcel only + if (oldhide == currentParcelHide) + return; + + allpresences = m_scene.GetScenePresences(); + + if (oldhide) + { // where private + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // those on not on parcel see me + if (currentParcelID != p.currentParcelUUID) + { + viewsToSendto.Add(p); // they see me + } + } + } // where private end + + else + { // where public + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // those not on parcel dont see me + if (currentParcelID != p.currentParcelUUID && !p.IsViewerUIGod) + { + killsToSendto.Add(p); // they dont see me + } + } + } // where public end + + allpresences.Clear(); + } + else + { + if (currentParcelHide) + { + // now on a private parcel + allpresences = m_scene.GetScenePresences(); + + if (previusParcelHide && previusParcelID != UUID.Zero) + { + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // only those on previus parcel need receive kills + if (previusParcelID == p.currentParcelUUID) + { + if(!p.IsViewerUIGod) + killsToSendto.Add(p); // they dont see me + if(!IsViewerUIGod) + killsToSendme.Add(p); // i dont see them + } + // only those on new parcel need see + if (currentParcelID == p.currentParcelUUID) + { + viewsToSendto.Add(p); // they see me + viewsToSendme.Add(p); // i see them + } + } + } + else + { + //was on a public area + allpresences = m_scene.GetScenePresences(); + + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // those not on new parcel dont see me + if (currentParcelID != p.currentParcelUUID && !p.IsViewerUIGod) + { + killsToSendto.Add(p); // they dont see me + } + else + { + viewsToSendme.Add(p); // i see those on it + } + } + } + allpresences.Clear(); + } // now on a private parcel end + + else + { + // now on public parcel + if (previusParcelHide && previusParcelID != UUID.Zero) + { + // was on private area + allpresences = m_scene.GetScenePresences(); + + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + // only those old parcel need kills + if (previusParcelID == p.currentParcelUUID && !IsViewerUIGod) + { + killsToSendme.Add(p); // i dont see them + } + else + { + viewsToSendto.Add(p); // they see me + } + } + } + else + return; // was on a public area also + } // now on public parcel end + } + + // send the things + + if (killsToSendto.Count > 0) + { + foreach (ScenePresence p in killsToSendto) + { +// m_log.Debug("[AVATAR]: killTo: " + Lastname + " " + p.Lastname); + SendKillTo(p); + } + } + + if (killsToSendme.Count > 0) + { + foreach (ScenePresence p in killsToSendme) + { +// m_log.Debug("[AVATAR]: killToMe: " + Lastname + " " + p.Lastname); + p.SendKillTo(this); + } + } + + if (viewsToSendto.Count > 0) + { + foreach (ScenePresence p in viewsToSendto) + { + SendViewTo(p); + } + } + + if (viewsToSendme.Count > 0 ) + { + foreach (ScenePresence p in viewsToSendme) + { + if (p.IsChildAgent) + continue; +// m_log.Debug("[AVATAR]: viewMe: " + Lastname + "<-" + p.Lastname); + p.SendViewTo(this); + } + } + } + + public void HasMovedAway(bool nearRegion) + { + if (nearRegion) + { + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.DeleteAttachmentsFromScene(this, true); + + if (!ParcelHideThisAvatar || IsViewerUIGod) + return; + + List allpresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.IsChildAgent || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + if (p.currentParcelUUID == m_currentParcelUUID) + { + p.SendKillTo(this); + } + } + } + else + { + GodController.HasMovedAway(); + List allpresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allpresences) + { + if (p == this) + continue; + SendKillTo(p); + if (!p.IsChildAgent) + p.SendKillTo(this); + } + + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.DeleteAttachmentsFromScene(this, true); + } + } + + +// kill with attachs root kills + public void SendKillTo(ScenePresence p) + { + List ids = new List(m_attachments.Count + 1); + foreach (SceneObjectGroup sog in m_attachments) + { + ids.Add(sog.RootPart.LocalId); + } + + ids.Add(LocalId); + p.ControllingClient.SendKillObject(ids); + } + +/* +// kill with hack + public void SendKillTo(ScenePresence p) + { + foreach (SceneObjectGroup sog in m_attachments) + p.ControllingClient.SendPartFullUpdate(sog.RootPart, LocalId + 1); + p.ControllingClient.SendKillObject(new List { LocalId }); + } +*/ + public void SendViewTo(ScenePresence p) + { + SendAvatarDataToAgentNF(p); + SendAppearanceToAgent(p); + if (Animator != null) + Animator.SendAnimPackToClient(p.ControllingClient); + SendAttachmentsToAgentNF(p); + } + + public void SetAnimationOverride(string animState, UUID animID) + { + Overrides.SetOverride(animState, animID); +// Animator.SendAnimPack(); + Animator.ForceUpdateMovementAnimations(); + } + + public UUID GetAnimationOverride(string animState) + { + return Overrides.GetOverriddenAnimation(animState); } } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs index cae7fe5..e7b09ea 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs @@ -40,7 +40,7 @@ namespace OpenSim.Region.Framework.Scenes /// Running => PreRemove, Removing /// PreRemove => Running, Removing /// Removing => Removed - /// + /// /// All other methods should only see the scene presence in running state - this is the normal operational state /// Removed state occurs when the presence has been removed. This is the end state with no exit. /// @@ -89,13 +89,13 @@ namespace OpenSim.Region.Framework.Scenes else if (newState == ScenePresenceState.PreRemove && m_state == ScenePresenceState.Running) transitionOkay = true; else if (newState == ScenePresenceState.Removing) - { + { if (m_state == ScenePresenceState.Running || m_state == ScenePresenceState.PreRemove) transitionOkay = true; } else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing) transitionOkay = true; - } + } if (!transitionOkay) { diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index f45158b..abcb573 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization List coaObjects = coa.Objects; // m_log.DebugFormat( -// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", +// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", // coaObjects.Count); // This is weak - we're relying on the set of coalesced objects still being identical @@ -86,9 +86,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteStartElement("CoalescedObject"); - writer.WriteAttributeString("x", size.X.ToString()); - writer.WriteAttributeString("y", size.Y.ToString()); - writer.WriteAttributeString("z", size.Z.ToString()); + writer.WriteAttributeString("x", size.X.ToString(Culture.FormatProvider)); + writer.WriteAttributeString("y", size.Y.ToString(Culture.FormatProvider)); + writer.WriteAttributeString("z", size.Z.ToString(Culture.FormatProvider)); // Embed the offsets into the group XML for (int i = 0; i < coaObjects.Count; i++) @@ -96,13 +96,13 @@ namespace OpenSim.Region.Framework.Scenes.Serialization SceneObjectGroup obj = coaObjects[i]; // m_log.DebugFormat( -// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing offset for object {0}, {1}", +// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing offset for object {0}, {1}", // i, obj.Name); writer.WriteStartElement("SceneObjectGroup"); - writer.WriteAttributeString("offsetx", offsets[i].X.ToString()); - writer.WriteAttributeString("offsety", offsets[i].Y.ToString()); - writer.WriteAttributeString("offsetz", offsets[i].Z.ToString()); + writer.WriteAttributeString("offsetx", offsets[i].X.ToString(Culture.FormatProvider)); + writer.WriteAttributeString("offsety", offsets[i].Y.ToString(Culture.FormatProvider)); + writer.WriteAttributeString("offsetz", offsets[i].Z.ToString(Culture.FormatProvider)); SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, doScriptStates); @@ -133,12 +133,14 @@ namespace OpenSim.Region.Framework.Scenes.Serialization { using (XmlTextReader reader = new XmlTextReader(sr)) { + reader.ProhibitDtd = true; + reader.MoveToContent(); // skip possible xml declaration if (reader.Name != "CoalescedObject") { // m_log.DebugFormat( - // "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", + // "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", // reader.Name); return false; @@ -147,6 +149,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } XmlDocument doc = new XmlDocument(); + doc.XmlResolver=null; doc.LoadXml(xml); XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); if (e == null) @@ -166,10 +169,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } else { - // XXX: Possibly we should fail outright here rather than continuing if a particular component of the + // XXX: Possibly we should fail outright here rather than continuing if a particular component of the // coalesced object fails to load. m_log.WarnFormat( - "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.", + "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.", i); } @@ -178,9 +181,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } catch (Exception e) { - m_log.Error("[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed "); -//// m_log.Error("[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed ", e); -//// Util.LogFailedXML("[COALESCED SCENE OBJECTS SERIALIZER]:", xml); + m_log.Error("[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed ", e); + Util.LogFailedXML("[COALESCED SCENE OBJECTS SERIALIZER]:", xml); return false; } diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 1ff788e..c5a3a22 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -63,16 +63,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization String fixedData = ExternalRepresentationUtils.SanitizeXml(xmlData); using (XmlTextReader wrappedReader = new XmlTextReader(fixedData, XmlNodeType.Element, null)) { - using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment })) + using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment, ProhibitDtd = true })) { - try { + try + { return FromOriginalXmlFormat(reader); } catch (Exception e) { - m_log.Error("[SERIALIZER]: Deserialization of xml failed "); -//// m_log.Error("[SERIALIZER]: Deserialization of xml failed ", e); -//// Util.LogFailedXML("[SERIALIZER]:", fixedData); + m_log.Error("[SERIALIZER]: Deserialization of xml failed ", e); + Util.LogFailedXML("[SERIALIZER]:", fixedData); return null; } } @@ -110,12 +110,24 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } while (reader.ReadToNextSibling("Part")); + reader.ReadEndElement(); } + if (reader.Name == "KeyframeMotion" && reader.NodeType == XmlNodeType.Element) + { + + string innerkeytxt = reader.ReadElementContentAsString(); + sceneObject.RootPart.KeyframeMotion = + KeyframeMotion.FromData(sceneObject, Convert.FromBase64String(innerkeytxt)); + } + else + sceneObject.RootPart.KeyframeMotion = null; + // Script state may, or may not, exist. Not having any, is NOT // ever a problem. sceneObject.LoadScriptState(reader); + sceneObject.InvalidateDeepEffectivePerms(); return sceneObject; } @@ -211,9 +223,19 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteEndElement(); // OtherParts + if (sceneObject.RootPart.KeyframeMotion != null) + { + Byte[] data = sceneObject.RootPart.KeyframeMotion.Serialize(); + + writer.WriteStartElement(String.Empty, "KeyframeMotion", String.Empty); + writer.WriteBase64(data, 0, data.Length); + writer.WriteEndElement(); + } + if (doScriptStates) sceneObject.SaveScriptedState(writer); + if (!noRootElement) writer.WriteEndElement(); // SceneObjectGroup @@ -233,6 +255,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization try { XmlDocument doc = new XmlDocument(); + doc.XmlResolver=null; doc.LoadXml(xmlData); XmlNodeList parts = doc.GetElementsByTagName("SceneObjectPart"); @@ -244,18 +267,28 @@ namespace OpenSim.Region.Framework.Scenes.Serialization return null; } - StringReader sr = new StringReader(parts[0].OuterXml); - XmlTextReader reader = new XmlTextReader(sr); - SceneObjectGroup sceneObject = new SceneObjectGroup(SceneObjectPart.FromXml(reader)); - reader.Close(); - sr.Close(); + SceneObjectGroup sceneObject; + using(StringReader sr = new StringReader(parts[0].OuterXml)) + { + using(XmlTextReader reader = new XmlTextReader(sr)) + { + reader.ProhibitDtd = true; + + sceneObject = new SceneObjectGroup(SceneObjectPart.FromXml(reader)); + } + } // Then deal with the rest + SceneObjectPart part; for (int i = 1; i < parts.Count; i++) { - sr = new StringReader(parts[i].OuterXml); - reader = new XmlTextReader(sr); - SceneObjectPart part = SceneObjectPart.FromXml(reader); + using(StringReader sr = new StringReader(parts[i].OuterXml)) + { + using(XmlTextReader reader = new XmlTextReader(sr)) + { + part = SceneObjectPart.FromXml(reader); + } + } int originalLinkNum = part.LinkNum; @@ -266,8 +299,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization if (originalLinkNum != 0) part.LinkNum = originalLinkNum; - reader.Close(); - sr.Close(); } XmlNodeList keymotion = doc.GetElementsByTagName("KeyframeMotion"); @@ -279,14 +310,13 @@ namespace OpenSim.Region.Framework.Scenes.Serialization // Script state may, or may not, exist. Not having any, is NOT // ever a problem. sceneObject.LoadScriptState(doc); - +// sceneObject.AggregatePerms(); return sceneObject; } catch (Exception e) { - m_log.Error("[SERIALIZER]: Deserialization of xml failed "); -//// m_log.Error("[SERIALIZER]: Deserialization of xml failed ", e); -//// Util.LogFailedXML("[SERIALIZER]:", xmlData); + m_log.Error("[SERIALIZER]: Deserialization of xml failed ", e); + Util.LogFailedXML("[SERIALIZER]:", xmlData); return null; } } @@ -309,7 +339,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } - /// /// Modifies a SceneObjectGroup. /// @@ -330,7 +359,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization CoalescedSceneObjects coa = null; string xmlData = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(data)); - if (CoalescedSceneObjectsSerializer.TryFromXml(xmlData, out coa)) { // m_log.DebugFormat("[SERIALIZER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count); @@ -376,7 +404,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization return data; } - #region manual serialization private static Dictionary> m_SOPXmlProcessors @@ -433,6 +460,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("GroupID", ProcessGroupID); m_SOPXmlProcessors.Add("OwnerID", ProcessOwnerID); m_SOPXmlProcessors.Add("LastOwnerID", ProcessLastOwnerID); + m_SOPXmlProcessors.Add("RezzerID", ProcessRezzerID); m_SOPXmlProcessors.Add("BaseMask", ProcessBaseMask); m_SOPXmlProcessors.Add("OwnerMask", ProcessOwnerMask); m_SOPXmlProcessors.Add("GroupMask", ProcessGroupMask); @@ -452,11 +480,29 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3); m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4); + m_SOPXmlProcessors.Add("Buoyancy", ProcessBuoyancy); + m_SOPXmlProcessors.Add("Force", ProcessForce); + m_SOPXmlProcessors.Add("Torque", ProcessTorque); + m_SOPXmlProcessors.Add("VolumeDetectActive", ProcessVolumeDetectActive); + + m_SOPXmlProcessors.Add("Vehicle", ProcessVehicle); + + m_SOPXmlProcessors.Add("PhysicsInertia", ProcessPhysicsInertia); + + m_SOPXmlProcessors.Add("RotationAxisLocks", ProcessRotationAxisLocks); m_SOPXmlProcessors.Add("PhysicsShapeType", ProcessPhysicsShapeType); m_SOPXmlProcessors.Add("Density", ProcessDensity); m_SOPXmlProcessors.Add("Friction", ProcessFriction); m_SOPXmlProcessors.Add("Bounce", ProcessBounce); m_SOPXmlProcessors.Add("GravityModifier", ProcessGravityModifier); + m_SOPXmlProcessors.Add("CameraEyeOffset", ProcessCameraEyeOffset); + m_SOPXmlProcessors.Add("CameraAtOffset", ProcessCameraAtOffset); + + m_SOPXmlProcessors.Add("SoundID", ProcessSoundID); + m_SOPXmlProcessors.Add("SoundGain", ProcessSoundGain); + m_SOPXmlProcessors.Add("SoundFlags", ProcessSoundFlags); + m_SOPXmlProcessors.Add("SoundRadius", ProcessSoundRadius); + m_SOPXmlProcessors.Add("SoundQueueing", ProcessSoundQueueing); #endregion @@ -686,6 +732,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.ClickAction = (byte)reader.ReadElementContentAsInt("ClickAction", String.Empty); } + private static void ProcessRotationAxisLocks(SceneObjectPart obj, XmlReader reader) + { + obj.RotationAxisLocks = (byte)reader.ReadElementContentAsInt("RotationAxisLocks", String.Empty); + } + private static void ProcessPhysicsShapeType(SceneObjectPart obj, XmlReader reader) { obj.PhysicsShapeType = (byte)reader.ReadElementContentAsInt("PhysicsShapeType", String.Empty); @@ -711,6 +762,75 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.GravityModifier = reader.ReadElementContentAsFloat("GravityModifier", String.Empty); } + private static void ProcessCameraEyeOffset(SceneObjectPart obj, XmlReader reader) + { + obj.SetCameraEyeOffset(Util.ReadVector(reader, "CameraEyeOffset")); + } + + private static void ProcessCameraAtOffset(SceneObjectPart obj, XmlReader reader) + { + obj.SetCameraAtOffset(Util.ReadVector(reader, "CameraAtOffset")); + } + + private static void ProcessSoundID(SceneObjectPart obj, XmlReader reader) + { + obj.Sound = Util.ReadUUID(reader, "SoundID"); + } + + private static void ProcessSoundGain(SceneObjectPart obj, XmlReader reader) + { + obj.SoundGain = reader.ReadElementContentAsDouble("SoundGain", String.Empty); + } + + private static void ProcessSoundFlags(SceneObjectPart obj, XmlReader reader) + { + obj.SoundFlags = (byte)reader.ReadElementContentAsInt("SoundFlags", String.Empty); + } + + private static void ProcessSoundRadius(SceneObjectPart obj, XmlReader reader) + { + obj.SoundRadius = reader.ReadElementContentAsDouble("SoundRadius", String.Empty); + } + + private static void ProcessSoundQueueing(SceneObjectPart obj, XmlReader reader) + { + obj.SoundQueueing = Util.ReadBoolean(reader); + } + + private static void ProcessVehicle(SceneObjectPart obj, XmlReader reader) + { + SOPVehicle vehicle = SOPVehicle.FromXml2(reader); + + if (vehicle == null) + { + obj.VehicleParams = null; + m_log.DebugFormat( + "[SceneObjectSerializer]: Parsing Vehicle for object part {0} {1} encountered errors. Please see earlier log entries.", + obj.Name, obj.UUID); + } + else + { + obj.VehicleParams = vehicle; + } + } + + private static void ProcessPhysicsInertia(SceneObjectPart obj, XmlReader reader) + { + PhysicsInertiaData pdata = PhysicsInertiaData.FromXml2(reader); + + if (pdata == null) + { + obj.PhysicsInertia = null; + m_log.DebugFormat( + "[SceneObjectSerializer]: Parsing PhysicsInertiaData for object part {0} {1} encountered errors. Please see earlier log entries.", + obj.Name, obj.UUID); + } + else + { + obj.PhysicsInertia = pdata; + } + } + private static void ProcessShape(SceneObjectPart obj, XmlReader reader) { List errorNodeNames; @@ -795,6 +915,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.LastOwnerID = Util.ReadUUID(reader, "LastOwnerID"); } + private static void ProcessRezzerID(SceneObjectPart obj, XmlReader reader) + { + obj.RezzerID = Util.ReadUUID(reader, "RezzerID"); + } + private static void ProcessBaseMask(SceneObjectPart obj, XmlReader reader) { obj.BaseMask = (uint)reader.ReadElementContentAsInt("BaseMask", String.Empty); @@ -885,6 +1010,25 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty); } + private static void ProcessBuoyancy(SceneObjectPart obj, XmlReader reader) + { + obj.Buoyancy = (float)reader.ReadElementContentAsFloat("Buoyancy", String.Empty); + } + + private static void ProcessForce(SceneObjectPart obj, XmlReader reader) + { + obj.Force = Util.ReadVector(reader, "Force"); + } + private static void ProcessTorque(SceneObjectPart obj, XmlReader reader) + { + obj.Torque = Util.ReadVector(reader, "Torque"); + } + + private static void ProcessVolumeDetectActive(SceneObjectPart obj, XmlReader reader) + { + obj.VolumeDetectActive = Util.ReadBoolean(reader); + } + #endregion #region TaskInventoryXmlProcessors @@ -1249,8 +1393,27 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessShpMedia(PrimitiveBaseShape shp, XmlReader reader) { - string value = reader.ReadElementContentAsString("Media", String.Empty); - shp.Media = PrimitiveBaseShape.MediaList.FromXml(value); + string value = String.Empty; + try + { + // The STANDARD content of Media elemet is escaped XML string (with > etc). + value = reader.ReadElementContentAsString("Media", String.Empty); + shp.Media = PrimitiveBaseShape.MediaList.FromXml(value); + } + catch (XmlException e) + { + // There are versions of OAR files that contain unquoted XML. + // ie ONE comercial fork that never wanted their oars to be read by our code + try + { + value = reader.ReadInnerXml(); + shp.Media = PrimitiveBaseShape.MediaList.FromXml(value); + } + catch + { + m_log.ErrorFormat("[SERIALIZER] Failed parsing halcyon MOAP information"); + } + } } #endregion @@ -1280,6 +1443,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteEndElement(); } + writer.WriteEndElement(); } @@ -1327,10 +1491,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("Description", sop.Description); writer.WriteStartElement("Color"); - writer.WriteElementString("R", sop.Color.R.ToString(Utils.EnUsCulture)); - writer.WriteElementString("G", sop.Color.G.ToString(Utils.EnUsCulture)); - writer.WriteElementString("B", sop.Color.B.ToString(Utils.EnUsCulture)); - writer.WriteElementString("A", sop.Color.A.ToString(Utils.EnUsCulture)); + writer.WriteElementString("R", sop.Color.R.ToString(Culture.FormatProvider)); + writer.WriteElementString("G", sop.Color.G.ToString(Culture.FormatProvider)); + writer.WriteElementString("B", sop.Color.B.ToString(Culture.FormatProvider)); + writer.WriteElementString("A", sop.Color.A.ToString(Culture.FormatProvider)); writer.WriteEndElement(); writer.WriteElementString("Text", sop.Text); @@ -1343,7 +1507,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization WriteShape(writer, sop.Shape, options); WriteVector(writer, "Scale", sop.Scale); - WriteQuaternion(writer, "SitTargetOrientation", sop.SitTargetOrientation); + WriteQuaternion(writer, "SitTargetOrientation", sop.SitTargetOrientation); WriteVector(writer, "SitTargetPosition", sop.SitTargetPosition); WriteVector(writer, "SitTargetPositionLL", sop.SitTargetPositionLL); WriteQuaternion(writer, "SitTargetOrientationLL", sop.SitTargetOrientationLL); @@ -1363,6 +1527,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization UUID lastOwnerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.LastOwnerID; WriteUUID(writer, "LastOwnerID", lastOwnerID, options); + UUID rezzerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.RezzerID; + WriteUUID(writer, "RezzerID", rezzerID, options); + writer.WriteElementString("BaseMask", sop.BaseMask.ToString()); writer.WriteElementString("OwnerMask", sop.OwnerMask.ToString()); writer.WriteElementString("GroupMask", sop.GroupMask.ToString()); @@ -1370,7 +1537,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("NextOwnerMask", sop.NextOwnerMask.ToString()); WriteFlags(writer, "Flags", sop.Flags.ToString(), options); WriteUUID(writer, "CollisionSound", sop.CollisionSound, options); - writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); + writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString(Culture.FormatProvider)); if (sop.MediaUrl != null) writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); WriteVector(writer, "AttachedPos", sop.AttachedPos); @@ -1390,16 +1557,41 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString()); writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString()); - if(sop.PhysicsShapeType != sop.DefaultPhysicsShapeType()) - writer.WriteElementString("PhysicsShapeType", sop.PhysicsShapeType.ToString().ToLower()); + writer.WriteElementString("Buoyancy", sop.Buoyancy.ToString(Culture.FormatProvider)); + + WriteVector(writer, "Force", sop.Force); + WriteVector(writer, "Torque", sop.Torque); + + writer.WriteElementString("VolumeDetectActive", sop.VolumeDetectActive.ToString().ToLower()); + + if (sop.VehicleParams != null) + sop.VehicleParams.ToXml2(writer); + + if (sop.PhysicsInertia != null) + sop.PhysicsInertia.ToXml2(writer); + + if(sop.RotationAxisLocks != 0) + writer.WriteElementString("RotationAxisLocks", sop.RotationAxisLocks.ToString().ToLower()); + writer.WriteElementString("PhysicsShapeType", sop.PhysicsShapeType.ToString().ToLower()); if (sop.Density != 1000.0f) - writer.WriteElementString("Density", sop.Density.ToString().ToLower()); + writer.WriteElementString("Density", sop.Density.ToString(Culture.FormatProvider)); if (sop.Friction != 0.6f) - writer.WriteElementString("Friction", sop.Friction.ToString().ToLower()); + writer.WriteElementString("Friction", sop.Friction.ToString(Culture.FormatProvider)); if (sop.Restitution != 0.5f) - writer.WriteElementString("Bounce", sop.Restitution.ToString().ToLower()); + writer.WriteElementString("Bounce", sop.Restitution.ToString(Culture.FormatProvider)); if (sop.GravityModifier != 1.0f) - writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString().ToLower()); + writer.WriteElementString("GravityModifier", sop.GravityModifier.ToString(Culture.FormatProvider)); + WriteVector(writer, "CameraEyeOffset", sop.GetCameraEyeOffset()); + WriteVector(writer, "CameraAtOffset", sop.GetCameraAtOffset()); + + // if (sop.Sound != UUID.Zero) force it till sop crossing does clear it on child prim + { + WriteUUID(writer, "SoundID", sop.Sound, options); + writer.WriteElementString("SoundGain", sop.SoundGain.ToString(Culture.FormatProvider)); + writer.WriteElementString("SoundFlags", sop.SoundFlags.ToString().ToLower()); + writer.WriteElementString("SoundRadius", sop.SoundRadius.ToString(Culture.FormatProvider)); + } + writer.WriteElementString("SoundQueueing", sop.SoundQueueing.ToString().ToLower()); writer.WriteEndElement(); } @@ -1417,19 +1609,19 @@ namespace OpenSim.Region.Framework.Scenes.Serialization static void WriteVector(XmlTextWriter writer, string name, Vector3 vec) { writer.WriteStartElement(name); - writer.WriteElementString("X", vec.X.ToString(Utils.EnUsCulture)); - writer.WriteElementString("Y", vec.Y.ToString(Utils.EnUsCulture)); - writer.WriteElementString("Z", vec.Z.ToString(Utils.EnUsCulture)); + writer.WriteElementString("X", vec.X.ToString(Culture.FormatProvider)); + writer.WriteElementString("Y", vec.Y.ToString(Culture.FormatProvider)); + writer.WriteElementString("Z", vec.Z.ToString(Culture.FormatProvider)); writer.WriteEndElement(); } static void WriteQuaternion(XmlTextWriter writer, string name, Quaternion quat) { writer.WriteStartElement(name); - writer.WriteElementString("X", quat.X.ToString(Utils.EnUsCulture)); - writer.WriteElementString("Y", quat.Y.ToString(Utils.EnUsCulture)); - writer.WriteElementString("Z", quat.Z.ToString(Utils.EnUsCulture)); - writer.WriteElementString("W", quat.W.ToString(Utils.EnUsCulture)); + writer.WriteElementString("X", quat.X.ToString(Culture.FormatProvider)); + writer.WriteElementString("Y", quat.Y.ToString(Culture.FormatProvider)); + writer.WriteElementString("Z", quat.Z.ToString(Culture.FormatProvider)); + writer.WriteElementString("W", quat.W.ToString(Culture.FormatProvider)); writer.WriteEndElement(); } @@ -1571,22 +1763,22 @@ namespace OpenSim.Region.Framework.Scenes.Serialization // Don't serialize SculptData. It's just a copy of the asset, which can be loaded separately using 'SculptTexture'. writer.WriteElementString("FlexiSoftness", shp.FlexiSoftness.ToString()); - writer.WriteElementString("FlexiTension", shp.FlexiTension.ToString()); - writer.WriteElementString("FlexiDrag", shp.FlexiDrag.ToString()); - writer.WriteElementString("FlexiGravity", shp.FlexiGravity.ToString()); - writer.WriteElementString("FlexiWind", shp.FlexiWind.ToString()); - writer.WriteElementString("FlexiForceX", shp.FlexiForceX.ToString()); - writer.WriteElementString("FlexiForceY", shp.FlexiForceY.ToString()); - writer.WriteElementString("FlexiForceZ", shp.FlexiForceZ.ToString()); - - writer.WriteElementString("LightColorR", shp.LightColorR.ToString()); - writer.WriteElementString("LightColorG", shp.LightColorG.ToString()); - writer.WriteElementString("LightColorB", shp.LightColorB.ToString()); - writer.WriteElementString("LightColorA", shp.LightColorA.ToString()); - writer.WriteElementString("LightRadius", shp.LightRadius.ToString()); - writer.WriteElementString("LightCutoff", shp.LightCutoff.ToString()); - writer.WriteElementString("LightFalloff", shp.LightFalloff.ToString()); - writer.WriteElementString("LightIntensity", shp.LightIntensity.ToString()); + writer.WriteElementString("FlexiTension", shp.FlexiTension.ToString(Culture.FormatProvider)); + writer.WriteElementString("FlexiDrag", shp.FlexiDrag.ToString(Culture.FormatProvider)); + writer.WriteElementString("FlexiGravity", shp.FlexiGravity.ToString(Culture.FormatProvider)); + writer.WriteElementString("FlexiWind", shp.FlexiWind.ToString(Culture.FormatProvider)); + writer.WriteElementString("FlexiForceX", shp.FlexiForceX.ToString(Culture.FormatProvider)); + writer.WriteElementString("FlexiForceY", shp.FlexiForceY.ToString(Culture.FormatProvider)); + writer.WriteElementString("FlexiForceZ", shp.FlexiForceZ.ToString(Culture.FormatProvider)); + + writer.WriteElementString("LightColorR", shp.LightColorR.ToString(Culture.FormatProvider)); + writer.WriteElementString("LightColorG", shp.LightColorG.ToString(Culture.FormatProvider)); + writer.WriteElementString("LightColorB", shp.LightColorB.ToString(Culture.FormatProvider)); + writer.WriteElementString("LightColorA", shp.LightColorA.ToString(Culture.FormatProvider)); + writer.WriteElementString("LightRadius", shp.LightRadius.ToString(Culture.FormatProvider)); + writer.WriteElementString("LightCutoff", shp.LightCutoff.ToString(Culture.FormatProvider)); + writer.WriteElementString("LightFalloff", shp.LightFalloff.ToString(Culture.FormatProvider)); + writer.WriteElementString("LightIntensity", shp.LightIntensity.ToString(Culture.FormatProvider)); writer.WriteElementString("FlexiEntry", shp.FlexiEntry.ToString().ToLower()); writer.WriteElementString("LightEntry", shp.LightEntry.ToString().ToLower()); @@ -1619,6 +1811,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization reader.ReadEndElement(); // SceneObjectPart + obj.AggregateInnerPerms(); // m_log.DebugFormat("[SceneObjectSerializer]: parsed SOP {0} {1}", obj.Name, obj.UUID); return obj; } @@ -1627,12 +1820,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization { TaskInventoryDictionary tinv = new TaskInventoryDictionary(); - if (reader.IsEmptyElement) - { - reader.Read(); - return tinv; - } - reader.ReadStartElement(name, String.Empty); while (reader.Name == "TaskInventoryItem") diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs index 3c03130..0ebc645 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs @@ -49,14 +49,18 @@ namespace OpenSim.Region.Framework.Scenes.Serialization public static void LoadPrimsFromXml(Scene scene, string fileName, bool newIDS, Vector3 loadOffset) { XmlDocument doc = new XmlDocument(); + doc.XmlResolver=null; XmlNode rootNode; if (fileName.StartsWith("http:") || File.Exists(fileName)) { - XmlTextReader reader = new XmlTextReader(fileName); - reader.WhitespaceHandling = WhitespaceHandling.None; - doc.Load(reader); - reader.Close(); + using(XmlTextReader reader = new XmlTextReader(fileName)) + { + reader.WhitespaceHandling = WhitespaceHandling.None; + reader.ProhibitDtd = true; + + doc.Load(reader); + } rootNode = doc.FirstChild; foreach (XmlNode aPrimNode in rootNode.ChildNodes) { @@ -70,6 +74,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization //obj.RegenerateFullIDs(); scene.AddNewSceneObject(obj, true); + obj.InvalidateDeepEffectivePerms(); } } else @@ -265,6 +270,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization foreach (XmlNode aPrimNode in rootNode.ChildNodes) { SceneObjectGroup obj = DeserializeGroupFromXml2(aPrimNode.OuterXml); + scene.AddNewSceneObject(obj, true); if (startScripts) sceneObjects.Add(obj); } diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs old mode 100644 new mode 100755 index 3effee7..bc440fc --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Timers; +using System.Threading; using OpenMetaverse.Packets; using OpenSim.Framework; using OpenSim.Framework.Monitoring; @@ -62,8 +63,10 @@ namespace OpenSim.Region.Framework.Scenes private YourStatsAreWrong handlerStatsIncorrect; // Determines the size of the array that is used to collect StatBlocks - // for sending to the SimStats and SimExtraStatsCollector - private const int m_statisticArraySize = 28; + // for sending viewer compatible stats must be conform with sb array filling below + private const int m_statisticViewerArraySize = 38; + // size of LastReportedSimFPS with extra stats. + private const int m_statisticExtraArraySize = (int)(Stats.SimExtraCountEnd - Stats.SimExtraCountStart); /// /// These are the IDs of stats sent in the StatsPacket to the viewer. @@ -74,6 +77,7 @@ namespace OpenSim.Region.Framework.Scenes /// public enum Stats : uint { +// viewers defined IDs TimeDilation = 0, SimFPS = 1, PhysicsFPS = 2, @@ -90,7 +94,7 @@ namespace OpenSim.Region.Framework.Scenes Agents = 13, ChildAgents = 14, ActiveScripts = 15, - ScriptLinesPerSecond = 16, + LSLScriptLinesPerSecond = 16, // viewers don't like this anymore InPacketsPerSecond = 17, OutPacketsPerSecond = 18, PendingDownloads = 19, @@ -109,11 +113,24 @@ namespace OpenSim.Region.Framework.Scenes SimSpareMs = 32, SimSleepMs = 33, SimIoPumpTime = 34, - FrameDilation = 35, - UsersLoggingIn = 36, - TotalGeoPrim = 37, - TotalMesh = 38, - ThreadCount = 39 + SimPCTSscriptsRun = 35, + SimRegionIdle = 36, // dataserver only + SimRegionIdlePossible = 37, // dataserver only + SimAIStepTimeMS = 38, + SimSkippedSillouet_PS = 39, + SimSkippedCharsPerC = 40, + +// extra stats IDs irrelevant, just far from viewer defined ones + SimExtraCountStart = 1000, + + internalLSLScriptLinesPerSecond = 1000, + FrameDilation2 = 1001, + UsersLoggingIn = 1002, + TotalGeoPrim = 1003, + TotalMesh = 1004, + ThreadCount = 1005, + + SimExtraCountEnd = 1006 } /// @@ -158,19 +175,14 @@ namespace OpenSim.Region.Framework.Scenes // Sending a stats update every 3 seconds- private int m_statsUpdatesEveryMS = 3000; - private float m_statsUpdateFactor; + private double m_lastUpdateTS; + private double m_prevFrameStatsTS; + private double m_FrameStatsTS; private float m_timeDilation; private int m_fps; - /// - /// Number of the last frame on which we processed a stats udpate. - /// - private uint m_lastUpdateFrame; - - /// - /// Our nominal fps target, as expected in fps stats when a sim is running normally. - /// - private float m_nominalReportedFps = 55; + private object m_statsLock = new object(); + private object m_statsFrameLock = new object(); /// /// Parameter to adjust reported scene fps @@ -186,10 +198,10 @@ namespace OpenSim.Region.Framework.Scenes /// corresponding, with default heartbeat rate, to a value of 5. /// private float m_statisticsFPSfactor = 5.0f; - - // saved last reported value so there is something available for llGetRegionFPS + private float m_targetFrameTime = 0.1f; + // saved last reported value so there is something available for llGetRegionFPS private float lastReportedSimFPS; - private float[] lastReportedSimStats = new float[m_statisticArraySize]; + private float[] lastReportedSimStats = new float[m_statisticExtraArraySize + m_statisticViewerArraySize]; private float m_pfps; /// @@ -202,14 +214,15 @@ namespace OpenSim.Region.Framework.Scenes /// private int m_objectUpdates; - private int m_frameMS; - private int m_spareMS; - private int m_netMS; - private int m_agentMS; - private int m_physicsMS; - private int m_imageMS; - private int m_otherMS; - private int m_scriptMS; + private float m_frameMS; + + private float m_netMS; + private float m_agentMS; + private float m_physicsMS; + private float m_imageMS; + private float m_otherMS; + private float m_sleeptimeMS; + private float m_scriptTimeMS; private int m_rootAgents; private int m_childAgents; @@ -224,31 +237,11 @@ namespace OpenSim.Region.Framework.Scenes private int m_pendingUploads = 0; // FIXME: Not currently filled in private int m_activeScripts; private int m_scriptLinesPerSecond; + private int m_scriptEventsPerSecond; private int m_objectCapacity = 45000; - // This is the number of frames that will be stored and then averaged for - // the Total, Simulation, Physics, and Network Frame Time; It is set to - // 10 by default but can be changed by the OpenSim.ini configuration file - // NumberOfFrames parameter - private int m_numberFramesStored; - - // The arrays that will hold the time it took to run the past N frames, - // where N is the num_frames_to_average given by the configuration file - private double[] m_totalFrameTimeMilliseconds; - private double[] m_simulationFrameTimeMilliseconds; - private double[] m_physicsFrameTimeMilliseconds; - private double[] m_networkFrameTimeMilliseconds; - - // The location of the next time in milliseconds that will be - // (over)written when the next frame completes - private int m_nextLocation = 0; - - // The correct number of frames that have completed since the last stats - // update for physics - private int m_numberPhysicsFrames; - - // The current number of users attempting to login to the region + // The current number of users attempting to login to the region private int m_usersLoggingIn; // The last reported value of threads from the SmartThreadPool inside of @@ -259,51 +252,39 @@ namespace OpenSim.Region.Framework.Scenes private RegionInfo ReportingRegion; - private Timer m_report = new Timer(); + private System.Timers.Timer m_report = new System.Timers.Timer(); private IEstateModule estateModule; - public SimStatsReporter(Scene scene) - : this(scene, Scene.m_defaultNumberFramesStored) + public SimStatsReporter(Scene scene) { - } - - public SimStatsReporter(Scene scene, int numberOfFrames) - { - // Store the number of frames from the OpenSim.ini configuration file - m_numberFramesStored = numberOfFrames; - - // Initialize the different frame time arrays to the correct sizes - m_totalFrameTimeMilliseconds = new double[m_numberFramesStored]; - m_simulationFrameTimeMilliseconds = new double[m_numberFramesStored]; - m_physicsFrameTimeMilliseconds = new double[m_numberFramesStored]; - m_networkFrameTimeMilliseconds = new double[m_numberFramesStored]; - - // Initialize the current number of users logging into the region - m_usersLoggingIn = 0; - m_scene = scene; - - m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); + ReportingRegion = scene.RegionInfo; if(scene.Normalized55FPS) - m_statisticsFPSfactor = 55.0f * m_scene.MinFrameTicks / 1000.0f; + m_statisticsFPSfactor = 55.0f * m_scene.FrameTime; else m_statisticsFPSfactor = 1.0f; - + + m_targetFrameTime = 1000.0f * m_scene.FrameTime / m_statisticsFPSfactor; + m_objectCapacity = scene.RegionInfo.ObjectCapacity; m_report.AutoReset = true; m_report.Interval = m_statsUpdatesEveryMS; m_report.Elapsed += TriggerStatsHeartbeat; m_report.Enabled = true; + m_lastUpdateTS = Util.GetTimeStampMS(); + m_FrameStatsTS = m_lastUpdateTS; + m_prevFrameStatsTS = m_lastUpdateTS; + if (StatsManager.SimExtraStats != null) OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket; /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit /// longer than ideal (which in itself is a concern). - SlowFramesStatReportThreshold = (int)Math.Ceiling(scene.MinFrameTicks * 1.2); + SlowFramesStatReportThreshold = (int)Math.Ceiling(m_scene.FrameTime * 1000 * 1.2); SlowFramesStat = new Stat( @@ -318,7 +299,6 @@ namespace OpenSim.Region.Framework.Scenes StatVerbosity.Info); StatsManager.RegisterStat(SlowFramesStat); - } @@ -335,7 +315,6 @@ namespace OpenSim.Region.Framework.Scenes public void SetUpdateMS(int ms) { m_statsUpdatesEveryMS = ms; - m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); m_report.Interval = m_statsUpdatesEveryMS; } @@ -355,29 +334,20 @@ namespace OpenSim.Region.Framework.Scenes private void statsHeartBeat(object sender, EventArgs e) { - double totalSumFrameTime; - double simulationSumFrameTime; - double physicsSumFrameTime; - double networkSumFrameTime; - float frameDilation; - int currentFrame; - - if (!m_scene.Active) + if (!m_scene.Active) return; - // Create arrays to hold the statistics for this current scene, - // these will be passed to the SimExtraStatsCollector, they are also - // sent to the SimStats class - SimStatsPacket.StatBlock[] sb = new - SimStatsPacket.StatBlock[m_statisticArraySize]; - SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); - - // Know what's not thread safe in Mono... modifying timers. - // m_log.Debug("Firing Stats Heart Beat"); - lock (m_report) + // dont do it if if still been done + + if(Monitor.TryEnter(m_statsLock)) { + // m_log.Debug("Firing Stats Heart Beat"); + + SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[m_statisticViewerArraySize]; + SimStatsPacket.StatBlock[] sbex = new SimStatsPacket.StatBlock[m_statisticExtraArraySize]; + SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); uint regionFlags = 0; - + try { if (estateModule == null) @@ -390,22 +360,93 @@ namespace OpenSim.Region.Framework.Scenes } #region various statistic googly moogly + double timeTmp = m_lastUpdateTS; + m_lastUpdateTS = Util.GetTimeStampMS(); + float updateElapsed = (float)((m_lastUpdateTS - timeTmp)/1000.0); - int reportedFPS = (int)(m_fps * m_statisticsFPSfactor); + // factor to consider updates integration time + float updateTimeFactor = 1.0f / updateElapsed; - // save the reported value so there is something available for llGetRegionFPS - lastReportedSimFPS = reportedFPS / m_statsUpdateFactor; - // ORIGINAL code commented out until we have time to add our own - // statistics to the statistics window - //float physfps = ((m_pfps / 1000)); - float physfps = m_numberPhysicsFrames * m_statisticsFPSfactor; + // scene frame stats + float reportedFPS; + float physfps; + float timeDilation; + float agentMS; + float physicsMS; + float otherMS; + float sleeptime; + float scriptTimeMS; + float totalFrameTime; - //if (physfps > 600) - //physfps = physfps - (physfps - 600); + float invFrameElapsed; - if (physfps < 0) - physfps = 0; + // get a copy under lock and reset + lock(m_statsFrameLock) + { + timeDilation = m_timeDilation; + reportedFPS = m_fps; + physfps = m_pfps; + agentMS = m_agentMS; + physicsMS = m_physicsMS; + otherMS = m_otherMS; + sleeptime = m_sleeptimeMS; + scriptTimeMS = m_scriptTimeMS; + totalFrameTime = m_frameMS; + // still not inv + invFrameElapsed = (float)((m_FrameStatsTS - m_prevFrameStatsTS) / 1000.0); + + ResetFrameStats(); + } + + if (invFrameElapsed / updateElapsed < 0.8) + // scene is in trouble, its account of time is most likely wrong + // can even be in stall + invFrameElapsed = updateTimeFactor; + else + invFrameElapsed = 1.0f / invFrameElapsed; + + float perframefactor; + if (reportedFPS <= 0) + { + reportedFPS = 0.0f; + physfps = 0.0f; + perframefactor = 1.0f; + timeDilation = 0.0f; + } + else + { + timeDilation /= reportedFPS; + reportedFPS *= m_statisticsFPSfactor; + perframefactor = 1.0f / (float)reportedFPS; + reportedFPS *= invFrameElapsed; + physfps *= invFrameElapsed * m_statisticsFPSfactor; + } + + // some engines track frame time with error related to the simulation step size + if(physfps > reportedFPS) + physfps = reportedFPS; + + // save the reported value so there is something available for llGetRegionFPS + lastReportedSimFPS = reportedFPS; + + // scale frame stats + + totalFrameTime *= perframefactor; + sleeptime *= perframefactor; + otherMS *= perframefactor; + physicsMS *= perframefactor; + agentMS *= perframefactor; + scriptTimeMS *= perframefactor; + + // estimate spare time + float sparetime; + sparetime = m_targetFrameTime - (physicsMS + agentMS + otherMS); + + if (sparetime < 0) + sparetime = 0; + else if (sparetime > totalFrameTime) + sparetime = totalFrameTime; #endregion @@ -416,79 +457,28 @@ namespace OpenSim.Region.Framework.Scenes m_numMesh = m_scene.SceneGraph.GetTotalMeshObjectsCount(); m_activePrim = m_scene.SceneGraph.GetActiveObjectsCount(); m_activeScripts = m_scene.SceneGraph.GetActiveScriptsCount(); + m_scriptLinesPerSecond = m_scene.SceneGraph.GetScriptLPS(); - // FIXME: Checking for stat sanity is a complex approach. What we really need to do is fix the code + // FIXME: Checking for stat sanity is a complex approach. What we really need to do is fix the code // so that stat numbers are always consistent. CheckStatSanity(); - - //Our time dilation is 0.91 when we're running a full speed, - // therefore to make sure we get an appropriate range, - // we have to factor in our error. (0.10f * statsUpdateFactor) - // multiplies the fix for the error times the amount of times it'll occur a second - // / 10 divides the value by the number of times the sim heartbeat runs (10fps) - // Then we divide the whole amount by the amount of seconds pass in between stats updates. - - // 'statsUpdateFactor' is how often stats packets are sent in seconds. Used below to change - // values to X-per-second values. - - uint thisFrame = m_scene.Frame; - uint numFrames = thisFrame - m_lastUpdateFrame; - float framesUpdated = (float)numFrames * m_statisticsFPSfactor; - m_lastUpdateFrame = thisFrame; - - // Avoid div-by-zero if somehow we've not updated any frames. - if (framesUpdated == 0) - framesUpdated = 1; - - for (int i = 0; i < m_statisticArraySize; i++) - { - sb[i] = new SimStatsPacket.StatBlock(); - } - // Resetting the sums of the frame times to prevent any errors - // in calculating the moving average for frame time - totalSumFrameTime = 0; - simulationSumFrameTime = 0; - physicsSumFrameTime = 0; - networkSumFrameTime = 0; - - // Loop through all the frames that were stored for the current - // heartbeat to process the moving average of frame times - for (int i = 0; i < m_numberFramesStored; i++) + for (int i = 0; i < m_statisticViewerArraySize; i++) { - // Sum up each frame time in order to calculate the moving - // average of frame time - totalSumFrameTime += m_totalFrameTimeMilliseconds[i]; - simulationSumFrameTime += - m_simulationFrameTimeMilliseconds[i]; - physicsSumFrameTime += m_physicsFrameTimeMilliseconds[i]; - networkSumFrameTime += m_networkFrameTimeMilliseconds[i]; + sb[i] = new SimStatsPacket.StatBlock(); } - // Get the index that represents the current frame based on the next one known; go back - // to the last index if next one is stated to restart at 0 - if (m_nextLocation == 0) - currentFrame = m_numberFramesStored - 1; - else - currentFrame = m_nextLocation - 1; - - // Calculate the frame dilation; which is currently based on the ratio between the sum of the - // physics and simulation rate, and the set minimum time to run a scene's frame - frameDilation = (float)(m_simulationFrameTimeMilliseconds[currentFrame] + - m_physicsFrameTimeMilliseconds[currentFrame]) / m_scene.MinFrameTicks; - - // ORIGINAL code commented out until we have time to add our own sb[0].StatID = (uint) Stats.TimeDilation; - sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor)); + sb[0].StatValue = (Single.IsNaN(timeDilation)) ? 0.0f : (float)Math.Round(timeDilation,3); sb[1].StatID = (uint) Stats.SimFPS; - sb[1].StatValue = reportedFPS / m_statsUpdateFactor; + sb[1].StatValue = (float)Math.Round(reportedFPS,1);; sb[2].StatID = (uint) Stats.PhysicsFPS; - sb[2].StatValue = physfps / m_statsUpdateFactor; + sb[2].StatValue = (float)Math.Round(physfps,1); sb[3].StatID = (uint) Stats.AgentUpdates; - sb[3].StatValue = (m_agentUpdates / m_statsUpdateFactor); + sb[3].StatValue = m_agentUpdates * updateTimeFactor; sb[4].StatID = (uint) Stats.Agents; sb[4].StatValue = m_rootAgents; @@ -502,38 +492,32 @@ namespace OpenSim.Region.Framework.Scenes sb[7].StatID = (uint) Stats.ActivePrim; sb[7].StatValue = m_activePrim; - // ORIGINAL code commented out until we have time to add our own - // statistics to the statistics window sb[8].StatID = (uint)Stats.FrameMS; - //sb[8].StatValue = m_frameMS / framesUpdated; - sb[8].StatValue = (float) totalSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor; + sb[8].StatValue = totalFrameTime; sb[9].StatID = (uint)Stats.NetMS; - //sb[9].StatValue = m_netMS / framesUpdated; - sb[9].StatValue = (float) networkSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor; + sb[9].StatValue = m_netMS * perframefactor; sb[10].StatID = (uint)Stats.PhysicsMS; - //sb[10].StatValue = m_physicsMS / framesUpdated; - sb[10].StatValue = (float) physicsSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor; + sb[10].StatValue = physicsMS; sb[11].StatID = (uint)Stats.ImageMS ; - sb[11].StatValue = m_imageMS / framesUpdated; + sb[11].StatValue = m_imageMS * perframefactor; sb[12].StatID = (uint)Stats.OtherMS; - //sb[12].StatValue = m_otherMS / framesUpdated; - sb[12].StatValue = (float) simulationSumFrameTime / m_numberFramesStored / m_statisticsFPSfactor; + sb[12].StatValue = otherMS; sb[13].StatID = (uint)Stats.InPacketsPerSecond; - sb[13].StatValue = (m_inPacketsPerSecond / m_statsUpdateFactor); + sb[13].StatValue = (float)Math.Round(m_inPacketsPerSecond * updateTimeFactor); sb[14].StatID = (uint)Stats.OutPacketsPerSecond; - sb[14].StatValue = (m_outPacketsPerSecond / m_statsUpdateFactor); + sb[14].StatValue = (float)Math.Round(m_outPacketsPerSecond * updateTimeFactor); sb[15].StatID = (uint)Stats.UnAckedBytes; sb[15].StatValue = m_unAckedBytes; sb[16].StatID = (uint)Stats.AgentMS; - sb[16].StatValue = m_agentMS / framesUpdated; + sb[16].StatValue = agentMS; sb[17].StatID = (uint)Stats.PendingDownloads; sb[17].StatValue = m_pendingDownloads; @@ -544,120 +528,155 @@ namespace OpenSim.Region.Framework.Scenes sb[19].StatID = (uint)Stats.ActiveScripts; sb[19].StatValue = m_activeScripts; - sb[20].StatID = (uint)Stats.ScriptLinesPerSecond; - sb[20].StatValue = m_scriptLinesPerSecond / m_statsUpdateFactor; + sb[20].StatID = (uint)Stats.SimSleepMs; + sb[20].StatValue = sleeptime; sb[21].StatID = (uint)Stats.SimSpareMs; - sb[21].StatValue = m_spareMS / framesUpdated; + sb[21].StatValue = sparetime; + + // this should came from phys engine + sb[22].StatID = (uint)Stats.SimPhysicsStepMs; + sb[22].StatValue = 20; + + // send the ones we dont have as zeros, to clean viewers state + // specially arriving from regions with wrond IDs in use + + sb[23].StatID = (uint)Stats.VirtualSizeKb; + sb[23].StatValue = 0; + + sb[24].StatID = (uint)Stats.ResidentSizeKb; + sb[24].StatValue = 0; + + sb[25].StatID = (uint)Stats.PendingLocalUploads; + sb[25].StatValue = 0; - // Current ratio between the sum of physics and sim rate, and the - // minimum time to run a scene's frame - sb[22].StatID = (uint)Stats.FrameDilation; - sb[22].StatValue = frameDilation; + sb[26].StatID = (uint)Stats.PhysicsPinnedTasks; + sb[26].StatValue = 0; - // Current number of users currently attemptint to login to region - sb[23].StatID = (uint)Stats.UsersLoggingIn; - sb[23].StatValue = m_usersLoggingIn; + sb[27].StatID = (uint)Stats.PhysicsLodTasks; + sb[27].StatValue = 0; - // Total number of geometric primitives in the scene - sb[24].StatID = (uint)Stats.TotalGeoPrim; - sb[24].StatValue = m_numGeoPrim; + sb[28].StatID = (uint)Stats.ScriptEps; // we actuall have this, but not messing array order AGAIN + sb[28].StatValue = (float)Math.Round(m_scriptEventsPerSecond * updateTimeFactor); - // Total number of mesh objects in the scene - sb[25].StatID = (uint)Stats.TotalMesh; - sb[25].StatValue = m_numMesh; + sb[29].StatID = (uint)Stats.SimAIStepTimeMS; + sb[29].StatValue = 0; - // Current number of threads that XEngine is using - sb[26].StatID = (uint)Stats.ThreadCount; - sb[26].StatValue = m_inUseThreads; + sb[30].StatID = (uint)Stats.SimIoPumpTime; + sb[30].StatValue = 0; - sb[27].StatID = (uint)Stats.ScriptMS; - sb[27].StatValue = (numFrames <= 0) ? 0 : ((float)m_scriptMS / numFrames); + sb[31].StatID = (uint)Stats.SimPCTSscriptsRun; + sb[31].StatValue = 0; - for (int i = 0; i < m_statisticArraySize; i++) + sb[32].StatID = (uint)Stats.SimRegionIdle; + sb[32].StatValue = 0; + + sb[33].StatID = (uint)Stats.SimRegionIdlePossible; + sb[33].StatValue = 0; + + sb[34].StatID = (uint)Stats.SimSkippedSillouet_PS; + sb[34].StatValue = 0; + + sb[35].StatID = (uint)Stats.SimSkippedCharsPerC; + sb[35].StatValue = 0; + + sb[36].StatID = (uint)Stats.SimPhysicsMemory; + sb[36].StatValue = 0; + + sb[37].StatID = (uint)Stats.ScriptMS; + sb[37].StatValue = scriptTimeMS; + + for (int i = 0; i < m_statisticViewerArraySize; i++) { lastReportedSimStats[i] = sb[i].StatValue; } - - SimStats simStats + + + // add extra stats for internal use + + for (int i = 0; i < m_statisticExtraArraySize; i++) + { + sbex[i] = new SimStatsPacket.StatBlock(); + } + + sbex[0].StatID = (uint)Stats.LSLScriptLinesPerSecond; + sbex[0].StatValue = m_scriptLinesPerSecond * updateTimeFactor; + lastReportedSimStats[38] = m_scriptLinesPerSecond * updateTimeFactor; + + sbex[1].StatID = (uint)Stats.FrameDilation2; + sbex[1].StatValue = (Single.IsNaN(timeDilation)) ? 0.1f : timeDilation; + lastReportedSimStats[39] = (Single.IsNaN(timeDilation)) ? 0.1f : timeDilation; + + sbex[2].StatID = (uint)Stats.UsersLoggingIn; + sbex[2].StatValue = m_usersLoggingIn; + lastReportedSimStats[40] = m_usersLoggingIn; + + sbex[3].StatID = (uint)Stats.TotalGeoPrim; + sbex[3].StatValue = m_numGeoPrim; + lastReportedSimStats[41] = m_numGeoPrim; + + sbex[4].StatID = (uint)Stats.TotalMesh; + sbex[4].StatValue = m_numMesh; + lastReportedSimStats[42] = m_numMesh; + + sbex[5].StatID = (uint)Stats.ThreadCount; + sbex[5].StatValue = m_inUseThreads; + lastReportedSimStats[43] = m_inUseThreads; + + SimStats simStats = new SimStats( ReportingRegion.RegionLocX, ReportingRegion.RegionLocY, regionFlags, (uint)m_objectCapacity, - rb, sb, m_scene.RegionInfo.originRegionID); + rb, sb, sbex, m_scene.RegionInfo.originRegionID); - handlerSendStatResult = OnSendStatsResult; + handlerSendStatResult = OnSendStatsResult; if (handlerSendStatResult != null) { handlerSendStatResult(simStats); } // Extra statistics that aren't currently sent to clients - lock (m_lastReportedExtraSimStats) + if (m_scene.PhysicsScene != null) { - m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor; - m_lastReportedExtraSimStats[SlowFramesStat.ShortName] = (float)SlowFramesStat.Value; - - Dictionary physicsStats = m_scene.PhysicsScene.GetStats(); - - if (physicsStats != null) + lock (m_lastReportedExtraSimStats) { - foreach (KeyValuePair tuple in physicsStats) + m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates * updateTimeFactor; + m_lastReportedExtraSimStats[SlowFramesStat.ShortName] = (float)SlowFramesStat.Value; + + Dictionary physicsStats = m_scene.PhysicsScene.GetStats(); + + if (physicsStats != null) { - // FIXME: An extremely dirty hack to divide MS stats per frame rather than per second - // Need to change things so that stats source can indicate whether they are per second or - // per frame. - if (tuple.Key.EndsWith("MS")) - m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / framesUpdated; - else - m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / m_statsUpdateFactor; + foreach (KeyValuePair tuple in physicsStats) + { + // FIXME: An extremely dirty hack to divide MS stats per frame rather than per second + // Need to change things so that stats source can indicate whether they are per second or + // per frame. + if (tuple.Key.EndsWith("MS")) + m_lastReportedExtraSimStats[tuple.Key] = tuple.Value * perframefactor; + else + m_lastReportedExtraSimStats[tuple.Key] = tuple.Value * updateTimeFactor; + } } } } +// LastReportedObjectUpdates = m_objectUpdates / m_statsUpdateFactor; ResetValues(); + Monitor.Exit(m_statsLock); } } private void ResetValues() { - // Reset the number of frames that the physics library has - // processed since the last stats report - m_numberPhysicsFrames = 0; - - m_timeDilation = 0; - m_fps = 0; - m_pfps = 0; m_agentUpdates = 0; m_objectUpdates = 0; - //m_inPacketsPerSecond = 0; - //m_outPacketsPerSecond = 0; m_unAckedBytes = 0; - m_scriptLinesPerSecond = 0; + m_scriptEventsPerSecond = 0; - m_frameMS = 0; - m_agentMS = 0; m_netMS = 0; - m_physicsMS = 0; m_imageMS = 0; - m_otherMS = 0; - m_scriptMS = 0; - m_spareMS = 0; } - # region methods called from Scene - // The majority of these functions are additive - // so that you can easily change the amount of - // seconds in between sim stats updates - - public void AddTimeDilation(float td) - { - //float tdsetting = td; - //if (tdsetting > 1.0f) - //tdsetting = (tdsetting - (tdsetting - 0.91f)); - - //if (tdsetting < 0) - //tdsetting = 0.0f; - m_timeDilation = td; - } internal void CheckStatSanity() { @@ -675,14 +694,44 @@ namespace OpenSim.Region.Framework.Scenes } } - public void AddFPS(int frames) + # region methods called from Scene + + public void AddFrameStats(float _timeDilation, float _physicsFPS, float _agentMS, + float _physicsMS, float _otherMS , float _sleepMS, + float _frameMS, float _scriptTimeMS) { - m_fps += frames; + lock(m_statsFrameLock) + { + m_fps++; + m_timeDilation += _timeDilation; + m_pfps += _physicsFPS; + m_agentMS += _agentMS; + m_physicsMS += _physicsMS; + m_otherMS += _otherMS; + m_sleeptimeMS += _sleepMS; + m_frameMS += _frameMS; + m_scriptTimeMS += _scriptTimeMS; + + if (_frameMS > SlowFramesStatReportThreshold) + SlowFramesStat.Value++; + + m_FrameStatsTS = Util.GetTimeStampMS(); + } } - public void AddPhysicsFPS(float frames) + private void ResetFrameStats() { - m_pfps += frames; + m_fps = 0; + m_timeDilation = 0.0f; + m_pfps = 0.0f; + m_agentMS = 0.0f; + m_physicsMS = 0.0f; + m_otherMS = 0.0f; + m_sleeptimeMS = 0.0f; + m_frameMS = 0.0f; + m_scriptTimeMS = 0.0f; + + m_prevFrameStatsTS = m_FrameStatsTS; } public void AddObjectUpdates(int numUpdates) @@ -711,77 +760,17 @@ namespace OpenSim.Region.Framework.Scenes if (m_unAckedBytes < 0) m_unAckedBytes = 0; } - public void addFrameMS(int ms) - { - m_frameMS += ms; - - // At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit - // longer than ideal due to the inaccuracy of the Sleep in Scene.Update() (which in itself is a concern). - if (ms > SlowFramesStatReportThreshold) - SlowFramesStat.Value++; - } - - public void AddSpareMS(int ms) - { - m_spareMS += ms; - } - public void addNetMS(int ms) + public void addNetMS(float ms) { m_netMS += ms; } - public void addAgentMS(int ms) - { - m_agentMS += ms; - } - - public void addPhysicsMS(int ms) - { - m_physicsMS += ms; - } - - public void addImageMS(int ms) + public void addImageMS(float ms) { m_imageMS += ms; } - public void addOtherMS(int ms) - { - m_otherMS += ms; - } - - public void AddScriptMS(int ms) - { - m_scriptMS += ms; - } - - public void addPhysicsFrame(int frames) - { - // Add the number of physics frames to the correct total physics - // frames - m_numberPhysicsFrames += frames; - } - - public void addFrameTimeMilliseconds(double total, double simulation, - double physics, double network) - { - // Save the frame times from the current frame into the appropriate - // arrays - m_totalFrameTimeMilliseconds[m_nextLocation] = total; - m_simulationFrameTimeMilliseconds[m_nextLocation] = simulation; - m_physicsFrameTimeMilliseconds[m_nextLocation] = physics; - m_networkFrameTimeMilliseconds[m_nextLocation] = network; - - // Update to the next location in the list - m_nextLocation++; - - // Since the list will begin to overwrite the oldest frame values - // first, the next location needs to loop back to the beginning of the - // list whenever it reaches the end - m_nextLocation = m_nextLocation % m_numberFramesStored; - } - public void AddPendingDownloads(int count) { m_pendingDownloads += count; @@ -792,9 +781,9 @@ namespace OpenSim.Region.Framework.Scenes //m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads); } - public void addScriptLines(int count) + public void addScriptEvents(int count) { - m_scriptLinesPerSecond += count; + m_scriptEventsPerSecond += count; } public void AddPacketsStats(int inPackets, int outPackets, int unAckedBytes) diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs index 3d563a6..20bad94 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs @@ -57,6 +57,7 @@ namespace OpenSim.Region.Framework.Scenes public int Height { get { return m_terrainData.SizeY; } } // Y dimension public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension + // Default, not-often-used builder public TerrainChannel() { @@ -195,13 +196,15 @@ namespace OpenSim.Region.Framework.Scenes // ITerrainChannel.LoadFromXmlString() public void LoadFromXmlString(string data) { - StringReader sr = new StringReader(data); - XmlTextReader reader = new XmlTextReader(sr); - reader.Read(); + using(StringReader sr = new StringReader(data)) + { + using(XmlTextReader reader = new XmlTextReader(sr)) + { + reader.ProhibitDtd = true; - ReadXml(reader); - reader.Close(); - sr.Close(); + ReadXml(reader); + } + } } // ITerrainChannel.Merge @@ -278,6 +281,148 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// A new version of terrain merge that processes the terrain in a specific order and corrects the problems with rotated terrains + /// having 'holes' in that need to be smoothed. The correct way to rotate something is to iterate over the target, taking data from + /// the source, not the other way around. This ensures that the target has no holes in it. + /// The processing order of an incoming terrain is: + /// 1. Apply rotation + /// 2. Apply bounding rectangle + /// 3. Apply displacement + /// rotationCenter is no longer needed and has been discarded. + /// + /// + /// <x, y, z> + /// + /// <x, y> + /// <x, y> + public void MergeWithBounding(ITerrainChannel newTerrain, Vector3 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize) + { + m_log.DebugFormat("{0} MergeWithBounding: inSize=<{1},{2}>, rot={3}, boundingOrigin={4}, boundingSize={5}, disp={6}, outSize=<{7},{8}>", + LogHeader, newTerrain.Width, newTerrain.Height, rotationDegrees, boundingOrigin.ToString(), + boundingSize.ToString(), displacement, m_terrainData.SizeX, m_terrainData.SizeY); + + // get the size of the incoming terrain + int baseX = newTerrain.Width; + int baseY = newTerrain.Height; + + // create an intermediate terrain map that is 25% bigger on each side that we can work with to handle rotation + int offsetX = baseX / 4; // the original origin will now be at these coordinates so now we can have imaginary negative coordinates ;) + int offsetY = baseY / 4; + int tmpX = baseX + baseX / 2; + int tmpY = baseY + baseY / 2; + int centreX = tmpX / 2; + int centreY = tmpY / 2; + TerrainData terrain_tmp = new HeightmapTerrainData(tmpX, tmpY, (int)Constants.RegionHeight); + for (int xx = 0; xx < tmpX; xx++) + for (int yy = 0; yy < tmpY; yy++) + terrain_tmp[xx, yy] = -65535f; //use this height like an 'alpha' mask channel + + double radianRotation = Math.PI * rotationDegrees / 180f; + double cosR = Math.Cos(radianRotation); + double sinR = Math.Sin(radianRotation); + if (rotationDegrees < 0f) rotationDegrees += 360f; //-90=270 -180=180 -270=90 + + // So first we apply the rotation to the incoming terrain, storing the result in terrain_tmp + // We special case orthogonal rotations for accuracy because even using double precision math, Math.Cos(90 degrees) is never fully 0 + // and we can never rotate around a centre 'pixel' because the 'bitmap' size is always even + + int x, y, sx, sy; + for (y = 0; y <= tmpY; y++) + { + for (x = 0; x <= tmpX; x++) + { + if (rotationDegrees == 0f) + { + sx = x - offsetX; + sy = y - offsetY; + } + else if (rotationDegrees == 90f) + { + sx = y - offsetX; + sy = tmpY - 1 - x - offsetY; + } + else if (rotationDegrees == 180f) + { + sx = tmpX - 1 - x - offsetX; + sy = tmpY - 1 - y - offsetY; + } + else if (rotationDegrees == 270f) + { + sx = tmpX - 1 - y - offsetX; + sy = x - offsetY; + } + else + { + // arbitary rotation: hmmm should I be using (centreX - 0.5) and (centreY - 0.5) and round cosR and sinR to say only 5 decimal places? + sx = centreX + (int)Math.Round((((double)x - centreX) * cosR) + (((double)y - centreY) * sinR)) - offsetX; + sy = centreY + (int)Math.Round((((double)y - centreY) * cosR) - (((double)x - centreX) * sinR)) - offsetY; + } + + if (sx >= 0 && sx < baseX && sy >= 0 && sy < baseY) + { + try + { + terrain_tmp[x, y] = (float)newTerrain[sx, sy]; + } + catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) + { + m_log.DebugFormat("{0} MergeWithBounding - Rotate: Out of Bounds sx={1} sy={2} dx={3} dy={4}", sx, sy, x, y); + } + } + } + } + + // We could also incorporate the next steps, bounding-rectangle and displacement in the loop above, but it's simpler to visualise if done separately + // and will also make it much easier when later I want the option for maybe a circular or oval bounding shape too ;). + + int newX = m_terrainData.SizeX; + int newY = m_terrainData.SizeY; + // displacement is relative to <0,0> in the destination region and defines where the origin of the data selected by the bounding-rectangle is placed + int dispX = (int)Math.Floor(displacement.X); + int dispY = (int)Math.Floor(displacement.Y); + + // startX/Y and endX/Y are coordinates in bitmap_tmp + int startX = (int)Math.Floor(boundingOrigin.X) + offsetX; + if (startX > tmpX) startX = tmpX; + if (startX < 0) startX = 0; + int startY = (int)Math.Floor(boundingOrigin.Y) + offsetY; + if (startY > tmpY) startY = tmpY; + if (startY < 0) startY = 0; + + int endX = (int)Math.Floor(boundingOrigin.X + boundingSize.X) + offsetX; + if (endX > tmpX) endX = tmpX; + if (endX < 0) endX = 0; + int endY = (int)Math.Floor(boundingOrigin.Y + boundingSize.Y) + offsetY; + if (endY > tmpY) endY = tmpY; + if (endY < 0) endY = 0; + + //m_log.DebugFormat("{0} MergeWithBounding: inSize=<{1},{2}>, disp=<{3},{4}> rot={5}, offset=<{6},{7}>, boundingStart=<{8},{9}>, boundingEnd=<{10},{11}>, cosR={12}, sinR={13}, outSize=<{14},{15}>", LogHeader, + // baseX, baseY, dispX, dispY, radianRotation, offsetX, offsetY, startX, startY, endX, endY, cosR, sinR, newX, newY); + + int dx, dy; + for (y = startY; y < endY; y++) + { + for (x = startX; x < endX; x++) + { + dx = x - startX + dispX; + dy = y - startY + dispY; + if (dx >= 0 && dx < newX && dy >= 0 && dy < newY) + { + try + { + float newHeight = (float)terrain_tmp[x, y]; //use 'alpha' mask + if (newHeight != -65535f) m_terrainData[dx, dy] = newHeight + displacement.Z; + } + catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;) + { + m_log.DebugFormat("{0} MergeWithBounding - Bound & Displace: Out of Bounds sx={1} sy={2} dx={3} dy={4}", x, y, dx, dy); + } + } + } + } + } + #endregion public TerrainChannel Copy() @@ -343,7 +488,7 @@ namespace OpenSim.Region.Framework.Scenes int index = 0; m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight); - + for (int y = 0; y < Height; y++) { for (int x = 0; x < Width; x++) @@ -363,8 +508,8 @@ namespace OpenSim.Region.Framework.Scenes public int SizeY; public int SizeZ; public float CompressionFactor; - public int[] Map; - public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap) + public float[] Map; + public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, float[] pMap) { Version = 1; SizeX = pX; @@ -395,17 +540,22 @@ namespace OpenSim.Region.Framework.Scenes // Fill the heightmap with the center bump terrain private void PinHeadIsland() { + float cx = m_terrainData.SizeX * 0.5f; + float cy = m_terrainData.SizeY * 0.5f; + float h; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { - m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; - float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d); - float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d); - if (m_terrainData[x, y]< spherFacA) - m_terrainData[x, y]= spherFacA; - if (m_terrainData[x, y]< spherFacB) - m_terrainData[x, y] = spherFacB; + // h = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; + h = 1.0f; + float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, cx, cy, 50) * 0.01d); + float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, cx, cy, 100) * 0.001d); + if (h < spherFacA) + h = spherFacA; + if (h < spherFacB) + h = spherFacB; + m_terrainData[x, y] = h; } } } diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs index fc8f8cd..9d1f815 100644 --- a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs +++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs @@ -27,10 +27,13 @@ /* Freely adapted from the Aurora version of the terrain compressor. * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/ + * Aurora version created from libOpenMetaverse Library terrain compressor */ using System; +using System.Collections.Generic; using System.Reflection; +using System.Diagnostics; using log4net; @@ -45,7 +48,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { public static class OpenSimTerrainCompressor { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); #pragma warning disable 414 private static string LogHeader = "[TERRAIN COMPRESSOR]"; @@ -61,47 +64,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP private const int POSITIVE_VALUE = 0x6; private const int NEGATIVE_VALUE = 0x7; - private static readonly float[] DequantizeTable16 = - new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - - private static readonly float[] DequantizeTable32 = - new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; - private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; +// private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; private static readonly float[] QuantizeTable16 = - new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + private static readonly float[] DequantizeTable16 = + new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; static OpenSimTerrainCompressor() { // Initialize the decompression tables BuildDequantizeTable16(); - SetupCosines16(); +// SetupCosines16(); BuildCopyMatrix16(); BuildQuantizeTable16(); } // Used to send cloud and wind patches - public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX, - int pRegionSizeY) + public static LayerDataPacket CreateLayerDataPacketStandardSize(TerrainPatch[] patches, byte type) { - LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; + LayerDataPacket layer = new LayerDataPacket { LayerID = { Type = type } }; TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader - {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize}; + { Stride = STRIDE, PatchSize = Constants.TerrainPatchSize }; // Should be enough to fit even the most poorly packed data - byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2]; + byte[] data = new byte[patches.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; BitPack bitpack = new BitPack(data, 0); bitpack.PackBits(header.Stride, 16); bitpack.PackBits(header.PatchSize, 8); bitpack.PackBits(type, 8); foreach (TerrainPatch t in patches) - CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY); + CreatePatchtStandardSize(bitpack, t.Data, t.X, t.Y); bitpack.PackBits(END_OF_PATCHES, 8); @@ -111,122 +108,131 @@ namespace OpenSim.Region.ClientStack.LindenUDP return layer; } - // Create a land packet for a single patch. - public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY) + public static void CreatePatchtStandardSize(BitPack output, float[] patchData, int x, int y) { - int[] xPieces = new int[1]; - int[] yPieces = new int[1]; - xPieces[0] = patchX; // patch X dimension - yPieces[0] = patchY; + TerrainPatch.Header header = PrescanPatch(patchData); + header.QuantWBits = 136; + + header.PatchIDs = (y & 0x1F); + header.PatchIDs += (x << 5); - return CreateLandPacket(terrData, xPieces, yPieces); + int wbits; + int[] patch = CompressPatch(patchData, header, 10, out wbits); + EncodePatchHeader(output, header, patch, false, ref wbits); + EncodePatch(output, patch, 0, wbits); } - public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces) + private static TerrainPatch.Header PrescanPatch(float[] patch) { - byte landPacketType = (byte)TerrainPatch.LayerType.Land; - if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) + TerrainPatch.Header header = new TerrainPatch.Header(); + float zmax = -99999999.0f; + float zmin = 99999999.0f; + + for (int i = 0; i < Constants.TerrainPatchSize * Constants.TerrainPatchSize; i++) { - landPacketType = (byte)TerrainPatch.LayerType.LandExtended; + float val = patch[i]; + if (val > zmax) zmax = val; + if (val < zmin) zmin = val; } - return CreateLandPacket(terrData, xPieces, yPieces, landPacketType); + header.DCOffset = zmin; + header.Range = (int)((zmax - zmin) + 1.0f); + + return header; } - /// - /// Creates a LayerData packet for compressed land data given a full - /// simulator heightmap and an array of indices of patches to compress - /// - /// - /// Terrain data that can result in a meter square heightmap. - /// - /// - /// Array of indexes in the grid of patches - /// for this simulator. - /// If creating a packet for multiple patches, there will be entries in - /// both the X and Y arrays for each of the patches. - /// For example if patches 1 and 17 are to be sent, - /// x[] = {1,1} and y[] = {0,1} which specifies the patches at - /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches). - /// - /// - /// Array of indexes in the grid of patches. - /// - /// - /// - public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type) + private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits) { - LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; + float[] block = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + float oozrange = 1.0f / header.Range; + float range = (1 << prequant); + float premult = oozrange * range; - TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader - {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize}; - byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; - BitPack bitpack = new BitPack(data, 0); - bitpack.PackBits(header.Stride, 16); - bitpack.PackBits(header.PatchSize, 8); - bitpack.PackBits(type, 8); + float sub = 0.5f * header.Range + header.DCOffset; - for (int i = 0; i < x.Length; i++) - CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]); + int wordsize = (prequant - 2) & 0x0f; + header.QuantWBits = wordsize; + header.QuantWBits |= wordsize << 4; - bitpack.PackBits(END_OF_PATCHES, 8); + int k = 0; + for (int j = 0; j < Constants.TerrainPatchSize; j++) + { + for (int i = 0; i < Constants.TerrainPatchSize; i++) + block[k++] = (patchData[j * Constants.TerrainPatchSize + i] - sub) * premult; + } - layer.LayerData.Data = new byte[bitpack.BytePos + 1]; - Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + float[] ftemp = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + int[] iout = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; - return layer; + wbits = (prequant >> 1); + + dct16x16(block, iout, ref wbits); + + return iout; } - // Unused: left for historical reference. - public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY) + // new using terrain data and patchs indexes + public static List CreateLayerDataPackets(TerrainData terrData, int[] x, int[] y, byte landPacketType) { - TerrainPatch.Header header = PrescanPatch(patchData); - header.QuantWBits = 136; - if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) - { - header.PatchIDs = (y & 0xFFFF); - header.PatchIDs += (x << 16); - } - else + List ret = new List(); + + //create packet and global header + LayerDataPacket layer = new LayerDataPacket(); + + layer.LayerID.Type = landPacketType; + + byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2]; + BitPack bitpack = new BitPack(data, 0); + bitpack.PackBits(STRIDE, 16); + bitpack.PackBits(Constants.TerrainPatchSize, 8); + bitpack.PackBits(landPacketType, 8); + + for (int i = 0; i < x.Length; i++) { - header.PatchIDs = (y & 0x1F); - header.PatchIDs += (x << 5); + CreatePatchFromTerrainData(bitpack, terrData, x[i], y[i]); + if (bitpack.BytePos > 980 && i != x.Length - 1) + { + //finish this packet + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + ret.Add(layer); + + // start another + layer = new LayerDataPacket(); + layer.LayerID.Type = landPacketType; + + bitpack = new BitPack(data, 0); + bitpack.PackBits(STRIDE, 16); + bitpack.PackBits(Constants.TerrainPatchSize, 8); + bitpack.PackBits(landPacketType, 8); + } } - // NOTE: No idea what prequant and postquant should be or what they do + bitpack.PackBits(END_OF_PATCHES, 8); + + layer.LayerData.Data = new byte[bitpack.BytePos + 1]; + Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1); + ret.Add(layer); - int wbits; - int[] patch = CompressPatch(patchData, header, 10, out wbits); - wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits); - EncodePatch(output, patch, 0, wbits); + return ret; } - /// - /// Add a patch of terrain to a BitPacker - /// - /// BitPacker to write the patch to - /// - /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array. - /// - /// - /// X offset of the patch to create. - /// - /// - /// Y offset of the patch to create. - /// - /// - /// - public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY) + public static void CreatePatchFromTerrainData(BitPack output, TerrainData terrData, int patchX, int patchY) { - TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY); - header.QuantWBits = 136; + float frange; + TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY, out frange); + header.QuantWBits = 130; + bool largeRegion = false; // If larger than legacy region size, pack patch X and Y info differently. if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize) { header.PatchIDs = (patchY & 0xFFFF); header.PatchIDs += (patchX << 16); + largeRegion = true; } else { @@ -234,45 +240,45 @@ namespace OpenSim.Region.ClientStack.LindenUDP header.PatchIDs += (patchX << 5); } - // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}", - // LogHeader, patchX, patchY, header.DCOffset, header.Range); + if (Math.Round((double)frange, 2) == 1.0) + { + // flat terrain speed up things - // NOTE: No idea what prequant and postquant should be or what they do - int wbits; - int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits); - wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits); - EncodePatch(output, patch, 0, wbits); - } + header.DCOffset -= 0.5f; - private static TerrainPatch.Header PrescanPatch(float[] patch) - { - TerrainPatch.Header header = new TerrainPatch.Header(); - float zmax = -99999999.0f; - float zmin = 99999999.0f; + header.QuantWBits = 0x00; + output.PackBits(header.QuantWBits, 8); + output.PackFloat(header.DCOffset); + output.PackBits(1, 16); + if (largeRegion) + output.PackBits(header.PatchIDs, 32); + else + output.PackBits(header.PatchIDs, 10); - for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) - { - float val = patch[i]; - if (val > zmax) zmax = val; - if (val < zmin) zmin = val; + // and thats all + output.PackBits(ZERO_EOB, 2); + return; } - header.DCOffset = zmin; - header.Range = (int) ((zmax - zmin) + 1.0f); - - return header; + int wbits; + int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits); + EncodePatchHeader(output, header, patch, largeRegion, ref wbits); + EncodePatch(output, patch, 0, wbits); } // Scan the height info we're returning and return a patch packet header for this patch. - private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY) + private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY, out float frange) { TerrainPatch.Header header = new TerrainPatch.Header(); - float zmax = -99999999.0f; - float zmin = 99999999.0f; + float zmax = float.MinValue; + float zmin = float.MaxValue; + + int startx = patchX * Constants.TerrainPatchSize; + int starty = patchY * Constants.TerrainPatchSize; - for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++) + for (int j = starty; j < starty + Constants.TerrainPatchSize; j++) { - for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++) + for (int i = startx; i < startx + Constants.TerrainPatchSize; i++) { float val = terrData[i, j]; if (val > zmax) zmax = val; @@ -281,309 +287,385 @@ namespace OpenSim.Region.ClientStack.LindenUDP } header.DCOffset = zmin; - header.Range = (int)((zmax - zmin) + 1.0f); - - return header; - } - - public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) - { - TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)}; - - // Quantized word bits - if (header.QuantWBits == END_OF_PATCHES) - return header; - - // DC offset - header.DCOffset = bitpack.UnpackFloat(); - - // Range - header.Range = bitpack.UnpackBits(16); - - // Patch IDs (10 bits) - header.PatchIDs = bitpack.UnpackBits(10); - - // Word bits - header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2); + frange = ((zmax - zmin) + 1.0f); + header.Range = (int)frange; return header; } - private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX, - uint pRegionSizeY, int wbits) + private static void EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, bool largeRegion, ref int wbits) { - /* - int temp; - int wbits = (header.QuantWBits & 0x0f) + 2; - uint maxWbits = (uint)wbits + 5; - uint minWbits = ((uint)wbits >> 1); - int wbitsMaxValue; - */ - // goal is to determ minimum number of bits to use so all data fits - /* - wbits = (int)minWbits; - wbitsMaxValue = (1 << wbits); - - for (int i = 0; i < patch.Length; i++) - { - temp = patch[i]; - if (temp != 0) - { - // Get the absolute value - if (temp < 0) temp *= -1; - - no coments.. - - for (int j = (int)maxWbits; j > (int)minWbits; j--) - { - if ((temp & (1 << j)) != 0) - { - if (j > wbits) wbits = j; - break; - } - } - - while (temp > wbitsMaxValue) - { - wbits++; - if (wbits == maxWbits) - goto Done; - wbitsMaxValue = 1 << wbits; - } - } - } - - Done: - - // wbits += 1; - */ - // better check if (wbits > 17) - wbits = 16; - else if (wbits < 3) - wbits = 3; + wbits = 17; + else if (wbits < 2) + wbits = 2; header.QuantWBits &= 0xf0; - header.QuantWBits |= (wbits - 2); output.PackBits(header.QuantWBits, 8); output.PackFloat(header.DCOffset); output.PackBits(header.Range, 16); - if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) + if (largeRegion) output.PackBits(header.PatchIDs, 32); else output.PackBits(header.PatchIDs, 10); - - return wbits; } - private static void IDCTColumn16(float[] linein, float[] lineout, int column) + private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) { - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - float total = OO_SQRT2*linein[column]; - - for (int u = 1; u < Constants.TerrainPatchSize; u++) - { - int usize = u*Constants.TerrainPatchSize; - total += linein[usize + column]*CosineTable16[usize + n]; - } + int maxwbitssize = (1 << wbits) - 1; + int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; - lineout[Constants.TerrainPatchSize*n + column] = total; + if (postquant > fullSize || postquant < 0) + { + Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); + return; } - } - private static void IDCTLine16(float[] linein, float[] lineout, int line) - { - const float oosob = 2.0f/Constants.TerrainPatchSize; - int lineSize = line*Constants.TerrainPatchSize; + if (postquant != 0) + patch[fullSize - postquant] = 0; - for (int n = 0; n < Constants.TerrainPatchSize; n++) + int lastZeroindx = fullSize - postquant; + + for (int i = 0; i < fullSize; i++) { - float total = OO_SQRT2*linein[lineSize]; + int temp = patch[i]; - for (int u = 1; u < Constants.TerrainPatchSize; u++) + if (temp == 0) { - total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n]; - } - - lineout[lineSize + n] = total*oosob; - } - } + bool eob = true; -/* - private static void DCTLine16(float[] linein, float[] lineout, int line) - { - float total = 0.0f; - int lineSize = line * Constants.TerrainPatchSize; + for (int j = i; j < lastZeroindx; j++) + { + if (patch[j] != 0) + { + eob = false; + break; + } + } - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[lineSize + n]; - } + if (eob) + { + output.PackBits(ZERO_EOB, 2); + return; + } + output.PackBits(ZERO_CODE, 1); + } + else + { + if (temp < 0) + { + temp *= -1; - lineout[lineSize] = OO_SQRT2 * total; + if (temp > maxwbitssize) temp = maxwbitssize; - int uptr = 0; - for (int u = 1; u < Constants.TerrainPatchSize; u++) - { - total = 0.0f; - uptr += Constants.TerrainPatchSize; + output.PackBits(NEGATIVE_VALUE, 3); + output.PackBits(temp, wbits); + } + else + { + if (temp > maxwbitssize) temp = maxwbitssize; - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[lineSize + n] * CosineTable16[uptr + n]; + output.PackBits(POSITIVE_VALUE, 3); + output.PackBits(temp, wbits); + } } - - lineout[lineSize + u] = total; } } -*/ - private static void DCTLine16(float[] linein, float[] lineout, int line) + private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header, + int prequant, out int wbits) { - // outputs transpose data (lines exchanged with coluns ) - // so to save a bit of cpu when doing coluns - float total = 0.0f; - int lineSize = line*Constants.TerrainPatchSize; + float[] block = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + int[] iout = new int[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[lineSize + n]; - } + float oozrange = 1.0f / header.Range; + float invprequat = (1 << prequant); + float premult = oozrange * invprequat; - lineout[line] = OO_SQRT2*total; + float sub = 0.5f * header.Range + header.DCOffset; + + int wordsize = (prequant - 2) & 0x0f; + header.QuantWBits = wordsize; + header.QuantWBits |= wordsize << 4; - for (int u = Constants.TerrainPatchSize; - u < Constants.TerrainPatchSize*Constants.TerrainPatchSize; - u += Constants.TerrainPatchSize) + int k = 0; + int startX = patchX * Constants.TerrainPatchSize; + int startY = patchY * Constants.TerrainPatchSize; + for (int y = startY; y < startY + Constants.TerrainPatchSize; y++) { - total = 0.0f; - for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++) + for (int x = startX; x < startX + Constants.TerrainPatchSize; x++) { - total += linein[ptrn]*CosineTable16[ptru]; + block[k++] = (terrData[x, y] - sub) * premult; } - - lineout[line + u] = total; } - } - - - /* - private static void DCTColumn16(float[] linein, int[] lineout, int column) - { - float total = 0.0f; - // const float oosob = 2.0f / Constants.TerrainPatchSize; - - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[Constants.TerrainPatchSize * n + column]; - } - // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); - lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]); + wbits = (prequant >> 1); - for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize) - { - total = 0.0f; + dct16x16(block, iout, ref wbits); - for (int n = 0; n < Constants.TerrainPatchSize; n++) - { - total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n]; - } + return iout; + } - // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]); - lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]); - } - } + #region Initialization - private static void DCTColumn16(float[] linein, int[] lineout, int column) + private static void BuildDequantizeTable16() { - // input columns are in fact stored in lines now - - float total = 0.0f; -// const float oosob = 2.0f / Constants.TerrainPatchSize; - int inlinesptr = Constants.TerrainPatchSize*column; - - for (int n = 0; n < Constants.TerrainPatchSize; n++) + for (int j = 0; j < Constants.TerrainPatchSize; j++) { - total += linein[inlinesptr + n]; + for (int i = 0; i < Constants.TerrainPatchSize; i++) + { + DequantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f + 2.0f * (i + j); + } } + } - // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); - lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]); - - for (int uptr = Constants.TerrainPatchSize; - uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize; - uptr += Constants.TerrainPatchSize) + private static void BuildQuantizeTable16() + { + const float oosob = 2.0f / Constants.TerrainPatchSize; + for (int j = 0; j < Constants.TerrainPatchSize; j++) { - total = 0.0f; - - for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++) + for (int i = 0; i < Constants.TerrainPatchSize; i++) { - total += linein[n]*CosineTable16[ptru]; + QuantizeTable16[j * Constants.TerrainPatchSize + i] = oosob / (1.0f + 2.0f * (i + (float)j)); } - -// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]); - lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]); } } - */ - private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits) + private static void BuildCopyMatrix16() { - // input columns are in fact stored in lines now - - bool dowbits = wbits != maxwbits; - int wbitsMaxValue = 1 << wbits; - - float total = 0.0f; - // const float oosob = 2.0f / Constants.TerrainPatchSize; - int inlinesptr = Constants.TerrainPatchSize*column; + bool diag = false; + bool right = true; + int i = 0; + int j = 0; + int count = 0; - for (int n = 0; n < Constants.TerrainPatchSize; n++) + while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize) { - total += linein[inlinesptr + n]; - } - - // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]); - int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]); - lineout[CopyMatrix16[column]] = tmp; + CopyMatrix16[j * Constants.TerrainPatchSize + i] = count++; - if (dowbits) - { - if (tmp < 0) tmp *= -1; - while (tmp > wbitsMaxValue) + if (!diag) { - wbits++; - wbitsMaxValue = 1 << wbits; - if (wbits == maxwbits) + if (right) { - dowbits = false; - break; - } - } - } + if (i < Constants.TerrainPatchSize - 1) i++; + else j++; - for (int uptr = Constants.TerrainPatchSize; - uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize; - uptr += Constants.TerrainPatchSize) - { - total = 0.0f; + right = false; + diag = true; + } + else + { + if (j < Constants.TerrainPatchSize - 1) j++; + else i++; - for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++) + right = true; + diag = true; + } + } + else { - total += linein[n]*CosineTable16[ptru]; + if (right) + { + i++; + j--; + if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false; + } + else + { + i--; + j++; + if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false; + } } + } + } + + #endregion Initialization + + + + + #region DCT + + /* DCT (Discrete Cosine Transform) + adaptation from + General Purpose 2D,3D FFT (Fast Fourier Transform) Package + by Takuya OOURA (email: ooura@kurims.kyoto-u.ac.jp) + + -------- 16x16 DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + Normalized 16x16 IDCT + C[k1 + k2] = (1/8) * sum_j1=0^15 sum_j2=0^15 + tmp[j1 + j2] * s[j1] * s[j2] * + cos(pi*j1*(k1+1/2)/16) * + cos(pi*j2*(k2+1/2)/16), 0<=k1<16, 0<=k2<16 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + Normalized 16x16 DCT + C[k1 + k2] = (1/8) * s[k1] * s[k2] * sum_j1=0^15 sum_j2=0^15 + tmp[j1 + j2] * + cos(pi*(j1+1/2)*k1/16) * + cos(pi*(j2+1/2)*k2/16), 0<=k1<16, 0<=k2<16 + (s[0] = 1/sqrt(2), s[j] = 1, j > 0) + */ + + /* Cn_kR = sqrt(2.0/n) * cos(pi/2*k/n) */ + /* Cn_kI = sqrt(2.0/n) * sin(pi/2*k/n) */ + /* Wn_kR = cos(pi/2*k/n) */ + /* Wn_kI = sin(pi/2*k/n) */ + + const float C16_1R = 0.35185093438159561476f * 2.82842712474619f; + const float C16_1I = 0.03465429229977286565f * 2.82842712474619f; + const float C16_2R = 0.34675996133053686546f * 2.82842712474619f; + const float C16_2I = 0.06897484482073575308f * 2.82842712474619f; + const float C16_3R = 0.33832950029358816957f * 2.82842712474619f; + const float C16_3I = 0.10263113188058934529f * 2.82842712474619f; + const float C16_4R = 0.32664074121909413196f * 2.82842712474619f; + const float C16_4I = 0.13529902503654924610f * 2.82842712474619f; + const float C16_5R = 0.31180625324666780814f * 2.82842712474619f; + const float C16_5I = 0.16666391461943662432f * 2.82842712474619f; + const float C16_6R = 0.29396890060483967924f * 2.82842712474619f; + const float C16_6I = 0.19642373959677554532f * 2.82842712474619f; + const float C16_7R = 0.27330046675043937206f * 2.82842712474619f; + const float C16_7I = 0.22429189658565907106f * 2.82842712474619f; + const float C16_8R = 0.25f * 2.82842712474619f; + const float W16_4R = 0.92387953251128675613f; + const float W16_4I = 0.38268343236508977173f; + const float W16_8R = 0.70710678118654752440f; + + static void dct16x16(float[] a, int[] iout, ref int wbits) + { + float[] tmp = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize]; + + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + float x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i; + float xr, xi; + float ftmp; - tmp = (int) (total*QuantizeTable16[uptr + column]); - lineout[CopyMatrix16[uptr + column]] = tmp; + int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; + int itmp; + int j, k; + int indx; + + const int maxwbits = 17; // per header encoding + int wbitsMaxValue = 1 << wbits; + bool dowbits = wbits < 17; + + for (j = 0, k = 0; j < fullSize; j += Constants.TerrainPatchSize, k++) + { + x4r = a[0 + j] - a[15 + j]; + xr = a[0 + j] + a[15 + j]; + x4i = a[8 + j] - a[7 + j]; + xi = a[8 + j] + a[7 + j]; + x0r = xr + xi; + x0i = xr - xi; + x5r = a[2 + j] - a[13 + j]; + xr = a[2 + j] + a[13 + j]; + x5i = a[10 + j] - a[5 + j]; + xi = a[10 + j] + a[5 + j]; + x1r = xr + xi; + x1i = xr - xi; + x6r = a[4 + j] - a[11 + j]; + xr = a[4 + j] + a[11 + j]; + x6i = a[12 + j] - a[3 + j]; + xi = a[12 + j] + a[3 + j]; + x2r = xr + xi; + x2i = xr - xi; + x7r = a[6 + j] - a[9 + j]; + xr = a[6 + j] + a[9 + j]; + x7i = a[14 + j] - a[1 + j]; + xi = a[14 + j] + a[1 + j]; + x3r = xr + xi; + x3i = xr - xi; + xr = x0r + x2r; + xi = x1r + x3r; + tmp[k] = C16_8R * (xr + xi); // + tmp[8 * Constants.TerrainPatchSize + k] = C16_8R * (xr - xi); // + xr = x0r - x2r; + xi = x1r - x3r; + tmp[4 * Constants.TerrainPatchSize + k] = C16_4R * xr - C16_4I * xi; // + tmp[12 * Constants.TerrainPatchSize + k] = C16_4R * xi + C16_4I * xr; // + x0r = W16_8R * (x1i - x3i); + x2r = W16_8R * (x1i + x3i); + xr = x0i + x0r; + xi = x2r + x2i; + tmp[2 * Constants.TerrainPatchSize + k] = C16_2R * xr - C16_2I * xi; // + tmp[14 * Constants.TerrainPatchSize + k] = C16_2R * xi + C16_2I * xr; // + xr = x0i - x0r; + xi = x2r - x2i; + tmp[6 * Constants.TerrainPatchSize + k] = C16_6R * xr - C16_6I * xi; // + tmp[10 * Constants.TerrainPatchSize + k] = C16_6R * xi + C16_6I * xr; // + xr = W16_8R * (x6r - x6i); + xi = W16_8R * (x6i + x6r); + x6r = x4r - xr; + x6i = x4i - xi; + x4r += xr; + x4i += xi; + xr = W16_4I * x7r - W16_4R * x7i; + xi = W16_4I * x7i + W16_4R * x7r; + x7r = W16_4R * x5r - W16_4I * x5i; + x7i = W16_4R * x5i + W16_4I * x5r; + x5r = x7r + xr; + x5i = x7i + xi; + x7r -= xr; + x7i -= xi; + xr = x4r + x5r; + xi = x5i + x4i; + tmp[Constants.TerrainPatchSize + k] = C16_1R * xr - C16_1I * xi; // + tmp[15 * Constants.TerrainPatchSize + k] = C16_1R * xi + C16_1I * xr; // + xr = x4r - x5r; + xi = x5i - x4i; + tmp[7 * Constants.TerrainPatchSize + k] = C16_7R * xr - C16_7I * xi; // + tmp[9 * Constants.TerrainPatchSize + k] = C16_7R * xi + C16_7I * xr; // + xr = x6r - x7i; + xi = x7r + x6i; + tmp[5 * Constants.TerrainPatchSize + k] = C16_5R * xr - C16_5I * xi; // + tmp[11 * Constants.TerrainPatchSize + k] = C16_5R * xi + C16_5I * xr; // + xr = x6r + x7i; + xi = x7r - x6i; + tmp[3 * Constants.TerrainPatchSize + k] = C16_3R * xr - C16_3I * xi; // + tmp[13 * Constants.TerrainPatchSize + k] = C16_3R * xi + C16_3I * xr; // + } + + for (j = 0, k = 0; j < fullSize; j += Constants.TerrainPatchSize, k++) + { + x4r = tmp[0 + j] - tmp[15 + j]; + xr = tmp[0 + j] + tmp[15 + j]; + x4i = tmp[8 + j] - tmp[7 + j]; + xi = tmp[8 + j] + tmp[7 + j]; + x0r = xr + xi; + x0i = xr - xi; + x5r = tmp[2 + j] - tmp[13 + j]; + xr = tmp[2 + j] + tmp[13 + j]; + x5i = tmp[10 + j] - tmp[5 + j]; + xi = tmp[10 + j] + tmp[5 + j]; + x1r = xr + xi; + x1i = xr - xi; + x6r = tmp[4 + j] - tmp[11 + j]; + xr = tmp[4 + j] + tmp[11 + j]; + x6i = tmp[12 + j] - tmp[3 + j]; + xi = tmp[12 + j] + tmp[3 + j]; + x2r = xr + xi; + x2i = xr - xi; + x7r = tmp[6 + j] - tmp[9 + j]; + xr = tmp[6 + j] + tmp[9 + j]; + x7i = tmp[14 + j] - tmp[1 + j]; + xi = tmp[14 + j] + tmp[1 + j]; + x3r = xr + xi; + x3i = xr - xi; + xr = x0r + x2r; + xi = x1r + x3r; + + //tmp[0 + k] = C16_8R * (xr + xi); // + ftmp = C16_8R * (xr + xi); + itmp = (int)(ftmp * QuantizeTable16[k]); + iout[CopyMatrix16[k]] = itmp; if (dowbits) { - if (tmp < 0) tmp *= -1; - while (tmp > wbitsMaxValue) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { wbits++; wbitsMaxValue = 1 << wbits; @@ -594,355 +676,650 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } } - } - return wbits; - } - public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) - { - for (int n = 0; n < size*size; n++) - { - // ? - int temp = bitpack.UnpackBits(1); - if (temp != 0) + //tmp[8 * Constants.TerrainPatchSize + k] = C16_8R * (xr - xi); // + ftmp = C16_8R * (xr - xi); + indx = 8 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) { - // Value or EOB - temp = bitpack.UnpackBits(1); - if (temp != 0) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - // Value - temp = bitpack.UnpackBits(1); - if (temp != 0) - { - // Negative - temp = bitpack.UnpackBits((int) header.WordBits); - patches[n] = temp*-1; - } - else + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) { - // Positive - temp = bitpack.UnpackBits((int) header.WordBits); - patches[n] = temp; + dowbits = false; + break; } } - else + } + + xr = x0r - x2r; + xi = x1r - x3r; + + //tmp[4 * Constants.TerrainPatchSize + k] = C16_4R * xr - C16_4I * xi; // + ftmp = C16_4R * xr - C16_4I * xi; + indx = 4 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - // Set the rest to zero - // TODO: This might not be necessary - for (int o = n; o < size*size; o++) + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) { - patches[o] = 0; + dowbits = false; + break; } - break; } } - else - { - patches[n] = 0; - } - } - } - private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits) - { - int maxwbitssize = (1 << wbits) - 1; + //tmp[12 * Constants.TerrainPatchSize + k] = C16_4R * xi + C16_4I * xr; // + ftmp = C16_4R * xi + C16_4I * xr; + indx = 12 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0) - { - Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error); - return; - } + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0; + x0r = W16_8R * (x1i - x3i); + x2r = W16_8R * (x1i + x3i); + xr = x0i + x0r; + xi = x2r + x2i; - for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++) - { - int temp = patch[i]; + //tmp[2 * Constants.TerrainPatchSize + k] = C16_2R * xr - C16_2I * xi; // + ftmp = C16_2R * xr - C16_2I * xi; + indx = 2 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - if (temp == 0) + if (dowbits) { - bool eob = true; - - for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - if (patch[j] != 0) + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) { - eob = false; + dowbits = false; break; } } + } - if (eob) + //tmp[14 * Constants.TerrainPatchSize + k] = C16_2R * xi + C16_2I * xr; // + ftmp = C16_2R * xi + C16_2I * xr; + indx = 14 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - output.PackBits(ZERO_EOB, 2); - return; + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } } - output.PackBits(ZERO_CODE, 1); } - else + + xr = x0i - x0r; + xi = x2r - x2i; + + //tmp[6 * Constants.TerrainPatchSize + k] = C16_6R * xr - C16_6I * xi; // + ftmp = C16_6R * xr - C16_6I * xi; + indx = 6 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) { - if (temp < 0) + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - temp *= -1; + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - if (temp > maxwbitssize) temp = maxwbitssize; + //tmp[10 * Constants.TerrainPatchSize + k] = C16_6R * xi + C16_6I * xr; // + ftmp = C16_6R * xi + C16_6I * xr; + indx = 10 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - output.PackBits(NEGATIVE_VALUE, 3); - output.PackBits(temp, wbits); - } - else + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) { - if (temp > maxwbitssize) temp = maxwbitssize; - - output.PackBits(POSITIVE_VALUE, 3); - output.PackBits(temp, wbits); + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } } } - } - } - public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group) - { - float[] block = new float[group.PatchSize*group.PatchSize]; - float[] output = new float[group.PatchSize*group.PatchSize]; - int prequant = (header.QuantWBits >> 4) + 2; - int quantize = 1 << prequant; - float ooq = 1.0f/quantize; - float mult = ooq*header.Range; - float addval = mult*(1 << (prequant - 1)) + header.DCOffset; - - if (group.PatchSize == Constants.TerrainPatchSize) - { - for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++) + xr = W16_8R * (x6r - x6i); + xi = W16_8R * (x6i + x6r); + x6r = x4r - xr; + x6i = x4i - xi; + x4r += xr; + x4i += xi; + xr = W16_4I * x7r - W16_4R * x7i; + xi = W16_4I * x7i + W16_4R * x7r; + x7r = W16_4R * x5r - W16_4I * x5i; + x7i = W16_4R * x5i + W16_4I * x5r; + x5r = x7r + xr; + x5i = x7i + xi; + x7r -= xr; + x7i -= xi; + xr = x4r + x5r; + xi = x5i + x4i; + + //tmp[1 * Constants.TerrainPatchSize + k] = C16_1R * xr - C16_1I * xi; // + ftmp = C16_1R * xr - C16_1I * xi; + indx = Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + + if (dowbits) { - block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n]; + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } } - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + //tmp[15 * Constants.TerrainPatchSize + k] = C16_1R * xi + C16_1I * xr; // + ftmp = C16_1R * xi + C16_1I * xr; + indx = 15 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - for (int o = 0; o < Constants.TerrainPatchSize; o++) - IDCTColumn16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - IDCTLine16(ftemp, block, o); - } - else - { - for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++) + if (dowbits) { - block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n]; + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } } - Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error); - } + xr = x4r - x5r; + xi = x5i - x4i; - for (int j = 0; j < block.Length; j++) - { - output[j] = block[j]*mult + addval; - } + //tmp[7 * Constants.TerrainPatchSize + k] = C16_7R * xr - C16_7I * xi; // + ftmp = C16_7R * xr - C16_7I * xi; + indx = 7 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - return output; - } + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits) - { - float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int wordsize = (prequant - 2) & 0x0f; - float oozrange = 1.0f/header.Range; - float range = (1 << prequant); - float premult = oozrange*range; - float sub = (1 << (prequant - 1)) + header.DCOffset*premult; + //tmp[9 * Constants.TerrainPatchSize + k] = C16_7R * xi + C16_7I * xr; // + ftmp = C16_7R * xi + C16_7I * xr; + indx = 9 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - header.QuantWBits = wordsize; - header.QuantWBits |= wordsize << 4; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - int k = 0; - for (int j = 0; j < Constants.TerrainPatchSize; j++) - { - for (int i = 0; i < Constants.TerrainPatchSize; i++) - block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub; - } + xr = x6r - x7i; + xi = x7r + x6i; - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + //tmp[5 * Constants.TerrainPatchSize + k] = C16_5R * xr - C16_5I * xi; // + ftmp = C16_5R * xr - C16_5I * xi; + indx = 5 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - int maxWbits = prequant + 5; - wbits = (prequant >> 1); + //tmp[11 * Constants.TerrainPatchSize + k] = C16_5R * xi + C16_5I * xr; // + ftmp = C16_5R * xi + C16_5I * xr; + indx = 11 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - for (int o = 0; o < Constants.TerrainPatchSize; o++) - DCTLine16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - return itemp; - } + xr = x6r + x7i; + xi = x7r - x6i; - private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits) - { - float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - float oozrange = 1.0f/header.Range; - float range = (1 << prequant); - float premult = oozrange*range; - float sub = (1 << (prequant - 1)) + header.DCOffset*premult; - int wordsize = (prequant - 2) & 0x0f; + //tmp[3 * Constants.TerrainPatchSize + k] = C16_3R * xr - C16_3I * xi; // + ftmp = C16_3R * xr - C16_3I * xi; + indx = 3 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - header.QuantWBits = wordsize; - header.QuantWBits |= wordsize << 4; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } - int k = 0; - for (int j = 0; j < Constants.TerrainPatchSize; j++) - { - for (int i = 0; i < Constants.TerrainPatchSize; i++) - block[k++] = patchData[j, i]*premult - sub; - } + //tmp[13 * Constants.TerrainPatchSize + k] = C16_3R * xi + C16_3I * xr; // + ftmp = C16_3R * xi + C16_3I * xr; + indx = 13 * Constants.TerrainPatchSize + k; + itmp = (int)(ftmp * QuantizeTable16[indx]); + iout[CopyMatrix16[indx]] = itmp; - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; + if (dowbits) + { + if (itmp < 0) itmp *= -1; + while (itmp > wbitsMaxValue) + { + wbits++; + wbitsMaxValue = 1 << wbits; + if (wbits == maxwbits) + { + dowbits = false; + break; + } + } + } + } + } - int maxWbits = prequant + 5; - wbits = (prequant >> 1); + #endregion DCT - for (int o = 0; o < Constants.TerrainPatchSize; o++) - DCTLine16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); + #region Decode + /* + public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack) + { + TerrainPatch.Header header = new TerrainPatch.Header { QuantWBits = bitpack.UnpackBits(8) }; - return itemp; - } + // Quantized word bits + if (header.QuantWBits == END_OF_PATCHES) + return header; - private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header, - int prequant, out int wbits) - { - float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int wordsize = prequant; - float oozrange = 1.0f/header.Range; - float range = (1 << prequant); - float premult = oozrange*range; - float sub = (1 << (prequant - 1)) + header.DCOffset*premult; + // DC offset + header.DCOffset = bitpack.UnpackFloat(); - header.QuantWBits = wordsize - 2; - header.QuantWBits |= (prequant - 2) << 4; + // Range + header.Range = bitpack.UnpackBits(16); - int k = 0; + // Patch IDs (10 bits) + header.PatchIDs = bitpack.UnpackBits(10); - int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ? - (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY; - yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize; + // Word bits + header.WordBits = (uint)((header.QuantWBits & 0x0f) + 2); - int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ? - (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX; - xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize; + return header; + } + */ - for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++) - { - for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++) + /* + public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size) { - block[k++] = terrData[xx, yy] * premult - sub; + for (int n = 0; n < size * size; n++) + { + // ? + int temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Value or EOB + temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Value + temp = bitpack.UnpackBits(1); + if (temp != 0) + { + // Negative + temp = bitpack.UnpackBits((int)header.WordBits); + patches[n] = temp * -1; + } + else + { + // Positive + temp = bitpack.UnpackBits((int)header.WordBits); + patches[n] = temp; + } + } + else + { + // Set the rest to zero + // TODO: This might not be necessary + for (int o = n; o < size * size; o++) + { + patches[o] = 0; + } + break; + } + } + else + { + patches[n] = 0; + } + } } - } - - float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; - - int maxWbits = prequant + 5; - wbits = (prequant >> 1); - - for (int o = 0; o < Constants.TerrainPatchSize; o++) - DCTLine16(block, ftemp, o); - for (int o = 0; o < Constants.TerrainPatchSize; o++) - wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits); - - return itemp; - } - - #region Initialization - - private static void BuildDequantizeTable16() + */ + #region IDCT + /* not in use + private static void IDCTColumn16(float[] linein, float[] lineout, int column) { - for (int j = 0; j < Constants.TerrainPatchSize; j++) + for (int n = 0; n < Constants.TerrainPatchSize; n++) { - for (int i = 0; i < Constants.TerrainPatchSize; i++) + float total = OO_SQRT2 * linein[column]; + + for (int u = 1; u < Constants.TerrainPatchSize; u++) { - DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j); + int usize = u * Constants.TerrainPatchSize; + total += linein[usize + column] * CosineTable16[usize + n]; } + + lineout[Constants.TerrainPatchSize * n + column] = total; } } - private static void BuildQuantizeTable16() + private static void IDCTLine16(float[] linein, float[] lineout, int line) { - const float oosob = 2.0f/Constants.TerrainPatchSize; - for (int j = 0; j < Constants.TerrainPatchSize; j++) + const float oosob = 2.0f / Constants.TerrainPatchSize; + int lineSize = line * Constants.TerrainPatchSize; + + for (int n = 0; n < Constants.TerrainPatchSize; n++) { - for (int i = 0; i < Constants.TerrainPatchSize; i++) + float total = OO_SQRT2 * linein[lineSize]; + + for (int u = 1; u < Constants.TerrainPatchSize; u++) { -// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j)); - QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j)); + total += linein[lineSize + u] * CosineTable16[u * Constants.TerrainPatchSize + n]; } + + lineout[lineSize + n] = total * oosob; } } +/* private static void SetupCosines16() { - const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize; + const float hposz = (float)Math.PI * 0.5f / Constants.TerrainPatchSize; for (int u = 0; u < Constants.TerrainPatchSize; u++) { for (int n = 0; n < Constants.TerrainPatchSize; n++) { - CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz); + CosineTable16[u * Constants.TerrainPatchSize + n] = (float)Math.Cos((2.0f * n + 1.0f) * u * hposz); } } } +*/ + //not in use, and still not fixed + /* + static void idct16x16(float[] a) + { + int j; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + float x4r, x4i, x5r, x5i, x6r, x6i, x7r, x7i; + float xr, xi; - private static void BuildCopyMatrix16() - { - bool diag = false; - bool right = true; - int i = 0; - int j = 0; - int count = 0; - - while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize) - { - CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++; - - if (!diag) - { - if (right) - { - if (i < Constants.TerrainPatchSize - 1) i++; - else j++; - - right = false; - diag = true; - } - else - { - if (j < Constants.TerrainPatchSize - 1) j++; - else i++; - - right = true; - diag = true; - } - } - else - { - if (right) - { - i++; - j--; - if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false; - } - else - { - i--; - j++; - if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false; - } - } - } - } + int fullSize = Constants.TerrainPatchSize * Constants.TerrainPatchSize; - #endregion Initialization + for (j = 0; j < fullSize; j += Constants.TerrainPatchSize) + { + x5r = C16_1R * tmp[1 + j] + C16_1I * tmp[15 + j]; + x5i = C16_1R * tmp[15 + j] - C16_1I * tmp[1 + j]; + xr = C16_7R * tmp[7 + j] + C16_7I * tmp[9 + j]; + xi = C16_7R * tmp[9 + j] - C16_7I * tmp[7 + j]; + x4r = x5r + xr; + x4i = x5i - xi; + x5r -= xr; + x5i += xi; + x7r = C16_5R * tmp[5 + j] + C16_5I * tmp[11 + j]; + x7i = C16_5R * tmp[11 + j] - C16_5I * tmp[5 + j]; + xr = C16_3R * tmp[3 + j] + C16_3I * tmp[13 + j]; + xi = C16_3R * tmp[13 + j] - C16_3I * tmp[3 + j]; + x6r = x7r + xr; + x6i = x7i - xi; + x7r -= xr; + x7i += xi; + xr = x4r - x6r; + xi = x4i - x6i; + x4r += x6r; + x4i += x6i; + x6r = W16_8R * (xi + xr); + x6i = W16_8R * (xi - xr); + xr = x5r + x7i; + xi = x5i - x7r; + x5r -= x7i; + x5i += x7r; + x7r = W16_4I * x5r + W16_4R * x5i; + x7i = W16_4I * x5i - W16_4R * x5r; + x5r = W16_4R * xr + W16_4I * xi; + x5i = W16_4R * xi - W16_4I * xr; + xr = C16_4R * tmp[4 + j] + C16_4I * tmp[12 + j]; + xi = C16_4R * tmp[12 + j] - C16_4I * tmp[4 + j]; + x2r = C16_8R * (tmp[0 + j] + tmp[8 + j]); + x3r = C16_8R * (tmp[0 + j] - tmp[8 + j]); + x0r = x2r + xr; + x1r = x3r + xi; + x2r -= xr; + x3r -= xi; + x0i = C16_2R * tmp[2 + j] + C16_2I * tmp[14 + j]; + x2i = C16_2R * tmp[14 + j] - C16_2I * tmp[2 + j]; + x1i = C16_6R * tmp[6 + j] + C16_6I * tmp[10 + j]; + x3i = C16_6R * tmp[10 + j] - C16_6I * tmp[6 + j]; + xr = x0i - x1i; + xi = x2i + x3i; + x0i += x1i; + x2i -= x3i; + x1i = W16_8R * (xi + xr); + x3i = W16_8R * (xi - xr); + xr = x0r + x0i; + xi = x0r - x0i; + tmp[0 + j] = xr + x4r; + tmp[15 + j] = xr - x4r; + tmp[8 + j] = xi + x4i; + tmp[7 + j] = xi - x4i; + xr = x1r + x1i; + xi = x1r - x1i; + tmp[2 + j] = xr + x5r; + tmp[13 + j] = xr - x5r; + tmp[10 + j] = xi + x5i; + tmp[5 + j] = xi - x5i; + xr = x2r + x2i; + xi = x2r - x2i; + tmp[4 + j] = xr + x6r; + tmp[11 + j] = xr - x6r; + tmp[12 + j] = xi + x6i; + tmp[3 + j] = xi - x6i; + xr = x3r + x3i; + xi = x3r - x3i; + tmp[6 + j] = xr + x7r; + tmp[9 + j] = xr - x7r; + tmp[14 + j] = xi + x7i; + tmp[1 + j] = xi - x7i; + } + for (j = 0; j < fullSize; j += Constants.TerrainPatchSize) + { + x5r = C16_1R * tmp[j + 1] + C16_1I * tmp[j + 15]; + x5i = C16_1R * tmp[j + 15] - C16_1I * tmp[j + 1]; + xr = C16_7R * tmp[j + 7] + C16_7I * tmp[j + 9]; + xi = C16_7R * tmp[j + 9] - C16_7I * tmp[j + 7]; + x4r = x5r + xr; + x4i = x5i - xi; + x5r -= xr; + x5i += xi; + x7r = C16_5R * tmp[j + 5] + C16_5I * tmp[j + 11]; + x7i = C16_5R * tmp[j + 11] - C16_5I * tmp[j + 5]; + xr = C16_3R * tmp[j + 3] + C16_3I * tmp[j + 13]; + xi = C16_3R * tmp[j + 13] - C16_3I * tmp[j + 3]; + x6r = x7r + xr; + x6i = x7i - xi; + x7r -= xr; + x7i += xi; + xr = x4r - x6r; + xi = x4i - x6i; + x4r += x6r; + x4i += x6i; + x6r = W16_8R * (xi + xr); + x6i = W16_8R * (xi - xr); + xr = x5r + x7i; + xi = x5i - x7r; + x5r -= x7i; + x5i += x7r; + x7r = W16_4I * x5r + W16_4R * x5i; + x7i = W16_4I * x5i - W16_4R * x5r; + x5r = W16_4R * xr + W16_4I * xi; + x5i = W16_4R * xi - W16_4I * xr; + xr = C16_4R * tmp[j + 4] + C16_4I * tmp[j + 12]; + xi = C16_4R * tmp[j + 12] - C16_4I * tmp[j + 4]; + x2r = C16_8R * (tmp[j + 0] + tmp[j + 8]); + x3r = C16_8R * (tmp[j + 0] - tmp[j + 8]); + x0r = x2r + xr; + x1r = x3r + xi; + x2r -= xr; + x3r -= xi; + x0i = C16_2R * tmp[j + 2] + C16_2I * tmp[j + 14]; + x2i = C16_2R * tmp[j + 14] - C16_2I * tmp[j + 2]; + x1i = C16_6R * tmp[j + 6] + C16_6I * tmp[j + 10]; + x3i = C16_6R * tmp[j + 10] - C16_6I * tmp[j + 6]; + xr = x0i - x1i; + xi = x2i + x3i; + x0i += x1i; + x2i -= x3i; + x1i = W16_8R * (xi + xr); + x3i = W16_8R * (xi - xr); + xr = x0r + x0i; + xi = x0r - x0i; + tmp[j + 0] = xr + x4r; + tmp[j + 15] = xr - x4r; + tmp[j + 8] = xi + x4i; + tmp[j + 7] = xi - x4i; + xr = x1r + x1i; + xi = x1r - x1i; + tmp[j + 2] = xr + x5r; + tmp[j + 13] = xr - x5r; + tmp[j + 10] = xi + x5i; + tmp[j + 5] = xi - x5i; + xr = x2r + x2i; + xi = x2r - x2i; + tmp[j + 4] = xr + x6r; + tmp[j + 11] = xr - x6r; + tmp[j + 12] = xi + x6i; + tmp[j + 3] = xi - x6i; + xr = x3r + x3i; + xi = x3r - x3i; + tmp[j + 6] = xr + x7r; + tmp[j + 9] = xr - x7r; + tmp[j + 14] = xi + x7i; + tmp[j + 1] = xi - x7i; + } + } + */ + #endregion IDCT + #endregion Decode } + } diff --git a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs deleted file mode 100644 index e209221..0000000 --- a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using NUnit.Framework; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Tests.Common; - -namespace OpenSim.Region.Framework.Scenes.Tests -{ - [TestFixture] - public class BorderTests : OpenSimTestCase - { - [Test] - public void TestCross() - { - TestHelpers.InMethod(); - - List testborders = new List(); - - Border NorthBorder = new Border(); - NorthBorder.BorderLine = new Vector3(0, 256, 256); //<--- - NorthBorder.CrossDirection = Cardinals.N; - testborders.Add(NorthBorder); - - Border SouthBorder = new Border(); - SouthBorder.BorderLine = new Vector3(0, 256, 0); //---> - SouthBorder.CrossDirection = Cardinals.S; - testborders.Add(SouthBorder); - - Border EastBorder = new Border(); - EastBorder.BorderLine = new Vector3(0, 256, 256); //<--- - EastBorder.CrossDirection = Cardinals.E; - testborders.Add(EastBorder); - - Border WestBorder = new Border(); - WestBorder.BorderLine = new Vector3(0, 256, 0); //---> - WestBorder.CrossDirection = Cardinals.W; - testborders.Add(WestBorder); - - Vector3 position = new Vector3(200,200,21); - - foreach (Border b in testborders) - Assert.That(!b.TestCross(position)); - - position = new Vector3(200,280,21); - Assert.That(NorthBorder.TestCross(position)); - - // Test automatic border crossing - // by setting the border crossing aabb to be the whole region - position = new Vector3(25,25,21); // safely within one 256m region - - // The Z value of the BorderLine is reversed, making all positions within the region - // trigger bordercross - - SouthBorder.BorderLine = new Vector3(0,256,256); // automatic border cross in the region - Assert.That(SouthBorder.TestCross(position)); - - NorthBorder.BorderLine = new Vector3(0, 256, 0); // automatic border cross in the region - Assert.That(NorthBorder.TestCross(position)); - - EastBorder.BorderLine = new Vector3(0, 256, 0); // automatic border cross in the region - Assert.That(EastBorder.TestCross(position)); - - WestBorder.BorderLine = new Vector3(0, 256, 255); // automatic border cross in the region - Assert.That(WestBorder.TestCross(position)); - } - - [Test] - public void TestCrossSquare512() - { - TestHelpers.InMethod(); - - List testborders = new List(); - - Border NorthBorder = new Border(); - NorthBorder.BorderLine = new Vector3(0, 512, 512); - NorthBorder.CrossDirection = Cardinals.N; - testborders.Add(NorthBorder); - - Border SouthBorder = new Border(); - SouthBorder.BorderLine = new Vector3(0, 512, 0); - SouthBorder.CrossDirection = Cardinals.S; - testborders.Add(SouthBorder); - - Border EastBorder = new Border(); - EastBorder.BorderLine = new Vector3(0, 512, 512); - EastBorder.CrossDirection = Cardinals.E; - testborders.Add(EastBorder); - - Border WestBorder = new Border(); - WestBorder.BorderLine = new Vector3(0, 512, 0); - WestBorder.CrossDirection = Cardinals.W; - testborders.Add(WestBorder); - - Vector3 position = new Vector3(450,220,21); - - foreach (Border b in testborders) - { - Assert.That(!b.TestCross(position)); - - } - - //Trigger east border - position = new Vector3(513,220,21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.E) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - - //Trigger west border - position = new Vector3(-1, 220, 21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.W) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - - //Trigger north border - position = new Vector3(220, 513, 21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.N) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - - //Trigger south border - position = new Vector3(220, -1, 21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.S) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - } - - [Test] - public void TestCrossRectangle512x256() - { - TestHelpers.InMethod(); - - List testborders = new List(); - - Border NorthBorder = new Border(); - NorthBorder.BorderLine = new Vector3(0, 512, 256); - NorthBorder.CrossDirection = Cardinals.N; - testborders.Add(NorthBorder); - - Border SouthBorder = new Border(); - SouthBorder.BorderLine = new Vector3(0, 512, 0); - SouthBorder.CrossDirection = Cardinals.S; - testborders.Add(SouthBorder); - - Border EastBorder = new Border(); - EastBorder.BorderLine = new Vector3(0, 256, 512); - EastBorder.CrossDirection = Cardinals.E; - testborders.Add(EastBorder); - - Border WestBorder = new Border(); - WestBorder.BorderLine = new Vector3(0, 256, 0); - WestBorder.CrossDirection = Cardinals.W; - testborders.Add(WestBorder); - - Vector3 position = new Vector3(450, 220, 21); - - foreach (Border b in testborders) - { - Assert.That(!b.TestCross(position)); - - } - - //Trigger east border - position = new Vector3(513, 220, 21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.E) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - - //Trigger west border - position = new Vector3(-1, 220, 21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.W) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - - //Trigger north border - position = new Vector3(220, 257, 21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.N) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - - //Trigger south border - position = new Vector3(220, -1, 21); - foreach (Border b in testborders) - { - if (b.CrossDirection == Cardinals.S) - Assert.That(b.TestCross(position)); - else - Assert.That(!b.TestCross(position)); - - } - } - - [Test] - public void TestCrossOdd512x512w256hole() - { - TestHelpers.InMethod(); - - List testborders = new List(); - // 512____ - // | | - // 256__| |___ - // | | - // |______| - // 0 | 512 - // 256 - - // Compound North border since the hole is at the top - Border NorthBorder1 = new Border(); - NorthBorder1.BorderLine = new Vector3(0, 256, 512); - NorthBorder1.CrossDirection = Cardinals.N; - testborders.Add(NorthBorder1); - - Border NorthBorder2 = new Border(); - NorthBorder2.BorderLine = new Vector3(256, 512, 256); - NorthBorder2.CrossDirection = Cardinals.N; - testborders.Add(NorthBorder2); - - Border SouthBorder = new Border(); - SouthBorder.BorderLine = new Vector3(0, 512, 0); - SouthBorder.CrossDirection = Cardinals.S; - testborders.Add(SouthBorder); - - //Compound East border - Border EastBorder1 = new Border(); - EastBorder1.BorderLine = new Vector3(0, 256, 512); - EastBorder1.CrossDirection = Cardinals.E; - testborders.Add(EastBorder1); - - Border EastBorder2 = new Border(); - EastBorder2.BorderLine = new Vector3(257, 512, 256); - EastBorder2.CrossDirection = Cardinals.E; - testborders.Add(EastBorder2); - - - - Border WestBorder = new Border(); - WestBorder.BorderLine = new Vector3(0, 512, 0); - WestBorder.CrossDirection = Cardinals.W; - testborders.Add(WestBorder); - - Vector3 position = new Vector3(450, 220, 21); - - foreach (Border b in testborders) - { - Assert.That(!b.TestCross(position)); - - } - - position = new Vector3(220, 450, 21); - - foreach (Border b in testborders) - { - Assert.That(!b.TestCross(position)); - - } - - bool result = false; - int bordersTriggered = 0; - - position = new Vector3(450, 450, 21); - - foreach (Border b in testborders) - { - if (b.TestCross(position)) - { - bordersTriggered++; - result = true; - } - } - - Assert.That(result); - Assert.That(bordersTriggered == 2); - - } - } -} diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs index da18941..fa698a9 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void T010_AddObjects() { TestHelpers.InMethod(); - + random = new Random(); SceneObjectGroup found; EntityManager entman = new EntityManager(); @@ -62,7 +62,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID obj2 = sog.UUID; uint li2 = sog.LocalId; entman.Add(sog); - + found = (SceneObjectGroup)entman[obj1]; Assert.That(found.UUID ,Is.EqualTo(obj1)); found = (SceneObjectGroup)entman[li1]; @@ -85,15 +85,15 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void T011_ThreadAddRemoveTest() { TestHelpers.InMethod(); - - // This test adds and removes with mutiple threads, attempting to break the + + // This test adds and removes with mutiple threads, attempting to break the // uuid and localid dictionary coherence. EntityManager entman = new EntityManager(); SceneObjectGroup sog = NewSOG(); for (int j=0; j<20; j++) { List trdlist = new List(); - + for (int i=0; i<4; i++) { // Adds scene object @@ -101,14 +101,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests Thread start = new Thread(new ThreadStart(test.TestAddSceneObject)); start.Start(); trdlist.Add(start); - + // Removes it test = new NewTestThreads(entman,sog); start = new Thread(new ThreadStart(test.TestRemoveSceneObject)); start.Start(); trdlist.Add(start); } - foreach (Thread thread in trdlist) + foreach (Thread thread in trdlist) { thread.Join(); } @@ -133,14 +133,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneObjectGroup sog = new SceneObjectGroup(sop); scene.AddNewSceneObject(sog, false); - + return sog; } - + private static string RandomName() { StringBuilder name = new StringBuilder(); - int size = random.Next(40,80); + int size = random.Next(40,80); char ch ; for (int i=0; i /// Test deleting an object from a scene. /// @@ -194,18 +197,18 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); Assert.That(so.IsDeleted, Is.False); + uint retrievedPartID = so.LocalId; scene.DeleteSceneObject(so, false); - Assert.That(so.IsDeleted, Is.True); + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(retrievedPartID); - SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); Assert.That(retrievedPart, Is.Null); } - + /// /// Changing a scene object uuid changes the root part uuid. This is a valid operation if the object is not - /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by + /// in a scene and is useful if one wants to supply a UUID directly rather than use the one generated by /// OpenSim. /// [Test] @@ -215,24 +218,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); string childPartName = "childPart"; UUID childPartUuid = new UUID("00000000-0000-0000-0001-000000000000"); - + SceneObjectPart rootPart - = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) { Name = rootPartName, UUID = rootPartUuid }; SceneObjectPart linkPart - = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) { Name = childPartName, UUID = childPartUuid }; SceneObjectGroup sog = new SceneObjectGroup(rootPart); sog.AddPart(linkPart); - + Assert.That(sog.UUID, Is.EqualTo(rootPartUuid)); Assert.That(sog.RootPart.UUID, Is.EqualTo(rootPartUuid)); Assert.That(sog.Parts.Length, Is.EqualTo(2)); - + UUID newRootPartUuid = new UUID("00000000-0000-0000-0000-000000000002"); sog.UUID = newRootPartUuid; - + Assert.That(sog.UUID, Is.EqualTo(newRootPartUuid)); Assert.That(sog.RootPart.UUID, Is.EqualTo(newRootPartUuid)); Assert.That(sog.Parts.Length, Is.EqualTo(2)); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs index 0b196c1..c27bc1a 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCopyTests.cs @@ -42,6 +42,7 @@ using OpenSim.Tests.Common; namespace OpenSim.Region.Framework.Scenes.Tests { + /* /// /// Test copying of scene objects. /// @@ -86,7 +87,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; - sogd.Enabled = false; + sogd.Enabled = false; SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID); uint soLocalId = so.LocalId; @@ -118,11 +119,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Check that object is still there. SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(retrievedPart2, Is.Not.Null); Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); // Check that we have a copy in inventory - InventoryItemBase item + InventoryItemBase item = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1"); Assert.That(item, Is.Not.Null); } @@ -144,7 +145,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; - sogd.Enabled = false; + sogd.Enabled = false; SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", ua.PrincipalID); uint soLocalId = so.LocalId; @@ -167,11 +168,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Check that object is still there. SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(retrievedPart2, Is.Not.Null); Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); // Check that we do not have a copy in inventory - InventoryItemBase item + InventoryItemBase item = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Lost And Found/so1"); Assert.That(item, Is.Null); } @@ -193,7 +194,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; - sogd.Enabled = false; + sogd.Enabled = false; SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2)); uint soLocalId = so.LocalId; @@ -218,11 +219,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Check that object is still there. SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(retrievedPart2, Is.Not.Null); Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); // Check that we have a copy in inventory - InventoryItemBase item + InventoryItemBase item = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); Assert.That(item, Is.Not.Null); } @@ -244,7 +245,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; - sogd.Enabled = false; + sogd.Enabled = false; SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", TestHelpers.ParseTail(0x2)); uint soLocalId = so.LocalId; @@ -271,11 +272,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests sogd.InventoryDeQueueAndDelete(); // Check that object is still there. SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(retrievedPart2, Is.Not.Null); Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); // Check that we have a copy in inventory - InventoryItemBase item + InventoryItemBase item = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); Assert.That(item, Is.Null); } @@ -302,11 +303,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests sogd.InventoryDeQueueAndDelete(); // Check that object is still there. SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(retrievedPart2, Is.Not.Null); Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); // Check that we have a copy in inventory - InventoryItemBase item + InventoryItemBase item = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); Assert.That(item, Is.Null); } @@ -333,14 +334,15 @@ namespace OpenSim.Region.Framework.Scenes.Tests sogd.InventoryDeQueueAndDelete(); // Check that object is still there. SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart2, Is.Not.Null); + Assert.That(retrievedPart2, Is.Not.Null); Assert.That(client.ReceivedKills.Count, Is.EqualTo(0)); // Check that we have a copy in inventory - InventoryItemBase item + InventoryItemBase item = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, ua.PrincipalID, "Objects/so1"); Assert.That(item, Is.Null); } } } + */ } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs index 5635c20..abf8c48 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs @@ -37,6 +37,7 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Region.CoreModules.World.Land; using OpenSim.Region.OptionalModules; using OpenSim.Tests.Common; +using System.Threading; namespace OpenSim.Region.Framework.Scenes.Tests { @@ -64,6 +65,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests [Test] public void TestCrossOnSameSimulator() { + TestHelpers.InMethod(); // TestHelpers.EnableLogging(); @@ -94,6 +96,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Cross with a negative value so1.AbsolutePosition = new Vector3(128, -10, 20); + // crossing is async + Thread.Sleep(500); + Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id)); Assert.NotNull(sceneB.GetSceneObjectGroup(so1Id)); } @@ -152,26 +157,28 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Cross sceneA.SceneGraph.UpdatePrimGroupPosition( - so1.LocalId, new Vector3(so1StartPos.X, so1StartPos.Y - 20, so1StartPos.Z), userId); + so1.LocalId, new Vector3(so1StartPos.X, so1StartPos.Y - 20, so1StartPos.Z), sp1SceneA.ControllingClient); + + // crossing is async + Thread.Sleep(500); SceneObjectGroup so1PostCross; - { - ScenePresence sp1SceneAPostCross = sceneA.GetScenePresence(userId); - Assert.IsTrue(sp1SceneAPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly false"); + ScenePresence sp1SceneAPostCross = sceneA.GetScenePresence(userId); + Assert.IsTrue(sp1SceneAPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly false"); - ScenePresence sp1SceneBPostCross = sceneB.GetScenePresence(userId); - TestClient sceneBTc = ((TestClient)sp1SceneBPostCross.ControllingClient); - sceneBTc.CompleteMovement(); + ScenePresence sp1SceneBPostCross = sceneB.GetScenePresence(userId); + TestClient sceneBTc = ((TestClient)sp1SceneBPostCross.ControllingClient); + sceneBTc.CompleteMovement(); - Assert.IsFalse(sp1SceneBPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly true"); - Assert.IsTrue(sp1SceneBPostCross.IsSatOnObject); + Assert.IsFalse(sp1SceneBPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly true"); + Assert.IsTrue(sp1SceneBPostCross.IsSatOnObject); + + Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id), "uck"); + so1PostCross = sceneB.GetSceneObjectGroup(so1Id); + Assert.NotNull(so1PostCross); + Assert.AreEqual(1, so1PostCross.GetSittingAvatarsCount()); - Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id), "uck"); - so1PostCross = sceneB.GetSceneObjectGroup(so1Id); - Assert.NotNull(so1PostCross); - Assert.AreEqual(1, so1PostCross.GetSittingAvatarsCount()); - } Vector3 so1PostCrossPos = so1PostCross.AbsolutePosition; @@ -179,7 +186,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Recross sceneB.SceneGraph.UpdatePrimGroupPosition( - so1PostCross.LocalId, new Vector3(so1PostCrossPos.X, so1PostCrossPos.Y + 20, so1PostCrossPos.Z), userId); + so1PostCross.LocalId, new Vector3(so1PostCrossPos.X, so1PostCrossPos.Y + 20, so1PostCrossPos.Z), sp1SceneBPostCross.ControllingClient); + + // crossing is async + Thread.Sleep(500); { ScenePresence sp1SceneBPostReCross = sceneB.GetScenePresence(userId); @@ -244,13 +254,22 @@ namespace OpenSim.Region.Framework.Scenes.Tests lmmA.EventManagerOnNoLandDataFromStorage(); lmmB.EventManagerOnNoLandDataFromStorage(); + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + ScenePresence sp1SceneA = SceneHelpers.AddScenePresence(sceneA, tc, acd); + SceneObjectGroup so1 = SceneHelpers.AddSceneObject(sceneA, 1, userId, "", sceneObjectIdTail); UUID so1Id = so1.UUID; so1.AbsolutePosition = new Vector3(128, 10, 20); // Cross with a negative value. We must make this call rather than setting AbsolutePosition directly // because only this will execute permission checks in the source region. - sceneA.SceneGraph.UpdatePrimGroupPosition(so1.LocalId, new Vector3(128, -10, 20), userId); + sceneA.SceneGraph.UpdatePrimGroupPosition(so1.LocalId, new Vector3(128, -10, 20), sp1SceneA.ControllingClient); + + // crossing is async + Thread.Sleep(500); Assert.IsNull(sceneA.GetSceneObjectGroup(so1Id)); Assert.NotNull(sceneB.GetSceneObjectGroup(so1Id)); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 1c396ac..b84ecac 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs @@ -77,16 +77,19 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestDeRezSceneObject() { TestHelpers.InMethod(); - + UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); - + TestScene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, new PermissionsModule()); - TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, userId).ControllingClient; - + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Startup"); + config.Set("serverside_object_permissions", true); + SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new DefaultPermissionsModule() }); + IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; - sogd.Enabled = false; + sogd.Enabled = false; SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", userId); uint soLocalId = so.LocalId; @@ -97,16 +100,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Check that object isn't deleted until we crank the sogd handle. SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart, Is.Not.Null); - Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); +// Assert.That(retrievedPart, Is.Not.Null); +// Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); sogd.InventoryDeQueueAndDelete(); - - SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart2, Is.Null); - Assert.That(client.ReceivedKills.Count, Is.EqualTo(1)); - Assert.That(client.ReceivedKills[0], Is.EqualTo(soLocalId)); +// SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); + Assert.That(retrievedPart, Is.Null); } /// @@ -133,7 +133,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneHelpers.SetupSceneModules(sceneB, config, etmB); // We need this for derez - SceneHelpers.SetupSceneModules(sceneA, new PermissionsModule()); + //SceneHelpers.SetupSceneModules(sceneA, new PermissionsModule()); UserAccount uaA = UserAccountHelpers.CreateUserWithInventory(sceneA, "Andy", "AAA", 0x1, ""); UserAccount uaB = UserAccountHelpers.CreateUserWithInventory(sceneA, "Brian", "BBB", 0x2, ""); @@ -153,52 +153,49 @@ namespace OpenSim.Region.Framework.Scenes.Tests uint soLocalId = so.LocalId; sceneA.DeleteSceneObject(so, false); - - Assert.That(clientA.ReceivedKills.Count, Is.EqualTo(1)); - Assert.That(clientA.ReceivedKills[0], Is.EqualTo(soLocalId)); - - Assert.That(childClientsB[0].ReceivedKills.Count, Is.EqualTo(1)); - Assert.That(childClientsB[0].ReceivedKills[0], Is.EqualTo(soLocalId)); } - + /// /// Test deleting an object from a scene where the deleter is not the owner /// /// - /// This test assumes that the deleter is not a god. + /// This test assumes that the deleter is not a god. /// [Test] public void TestDeRezSceneObjectNotOwner() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); - + TestScene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, new PermissionsModule()); + IConfigSource configSource = new IniConfigSource(); + IConfig config = configSource.AddConfig("Startup"); + config.Set("serverside_object_permissions", true); + SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new DefaultPermissionsModule() }); IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; - + // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; - sogd.Enabled = false; - + sogd.Enabled = false; + SceneObjectPart part = new SceneObjectPart(objectOwnerId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); part.Name = "obj1"; scene.AddNewSceneObject(new SceneObjectGroup(part), false); List localIds = new List(); - localIds.Add(part.LocalId); + localIds.Add(part.LocalId); scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); sogd.InventoryDeQueueAndDelete(); - + // Object should still be in the scene. SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID)); - } - + } + /// /// Test deleting an object asynchronously to user inventory. /// @@ -214,7 +211,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestScene scene = new SceneHelpers().SetupScene(); IConfigSource configSource = new IniConfigSource(); - IConfig config = configSource.AddConfig("Modules"); + IConfig config = configSource.AddConfig("Modules"); config.Set("InventoryAccessModule", "BasicInventoryAccessModule"); SceneHelpers.SetupSceneModules( scene, configSource, new object[] { new BasicInventoryAccessModule() }); @@ -234,10 +231,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; scene.DeRezObjects(client, new List() { so.LocalId }, UUID.Zero, DeRezAction.Take, folder1.ID); - SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); +// SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); - Assert.That(retrievedPart, Is.Not.Null); - Assert.That(so.IsDeleted, Is.False); +// Assert.That(retrievedPart, Is.Not.Null); +// Assert.That(so.IsDeleted, Is.False); sogd.InventoryDeQueueAndDelete(); @@ -260,4 +257,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Assert.That(retrievedPart, Is.Null); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs index e6d5a2f..41f61ac 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs @@ -66,8 +66,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestLinkDelink2SceneObjects() { TestHelpers.InMethod(); - - bool debugtest = false; + + bool debugtest = false; Scene scene = new SceneHelpers().SetupScene(); SceneObjectGroup grp1 = SceneHelpers.AddSceneObject(scene); @@ -83,7 +83,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // <180,0,0> grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0)); - + // Required for linking grp1.RootPart.ClearUpdateSchedule(); grp2.RootPart.ClearUpdateSchedule(); @@ -111,7 +111,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests } // root part should have no offset position or rotation - Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity, + Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity, "root part should have no offset position or rotation"); // offset position should be root part position - part2.absolute position. @@ -125,13 +125,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests // There's a euler anomoly at 180, 0, 0 so expect 180 to turn into -180. part1.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw); Vector3 rotEuler1 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG); - + if (debugtest) m_log.Debug(rotEuler1); part2.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw); Vector3 rotEuler2 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG); - + if (debugtest) m_log.Debug(rotEuler2); @@ -153,7 +153,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestLinkDelink2groups4SceneObjects() { TestHelpers.InMethod(); - + bool debugtest = false; Scene scene = new SceneHelpers().SetupScene(); @@ -194,7 +194,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Link grp4 to grp3. grp3.LinkToGroup(grp4); - + // At this point we should have 4 parts total in two groups. Assert.That(grp1.Parts.Length == 2, "Group1 children count should be 2"); Assert.That(grp2.IsDeleted, "Group 2 was not registered as deleted after link."); @@ -202,7 +202,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(grp3.Parts.Length == 2, "Group3 children count should be 2"); Assert.That(grp4.IsDeleted, "Group 4 was not registered as deleted after link."); Assert.That(grp4.Parts.Length, Is.EqualTo(0), "Group 4 still contained parts after delink."); - + if (debugtest) { m_log.Debug("--------After Link-------"); @@ -273,13 +273,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(part2.AbsolutePosition == Vector3.Zero, "Badness 1"); Assert.That(part4.OffsetPosition == new Vector3(20, 20, 20), "Badness 2"); Quaternion compareQuaternion = new Quaternion(0, 0.7071068f, 0, 0.7071068f); - Assert.That((part4.RotationOffset.X - compareQuaternion.X < 0.00003) - && (part4.RotationOffset.Y - compareQuaternion.Y < 0.00003) - && (part4.RotationOffset.Z - compareQuaternion.Z < 0.00003) + Assert.That((part4.RotationOffset.X - compareQuaternion.X < 0.00003) + && (part4.RotationOffset.Y - compareQuaternion.Y < 0.00003) + && (part4.RotationOffset.Z - compareQuaternion.Z < 0.00003) && (part4.RotationOffset.W - compareQuaternion.W < 0.00003), "Badness 3"); } - + /// /// Test that a new scene object which is already linked is correctly persisted to the persistence layer. /// @@ -288,37 +288,37 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - + TestScene scene = new SceneHelpers().SetupScene(); - + string rootPartName = "rootpart"; UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); string linkPartName = "linkpart"; UUID linkPartUuid = new UUID("00000000-0000-0000-0001-000000000000"); SceneObjectPart rootPart - = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) { Name = rootPartName, UUID = rootPartUuid }; SceneObjectPart linkPart - = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) { Name = linkPartName, UUID = linkPartUuid }; SceneObjectGroup sog = new SceneObjectGroup(rootPart); sog.AddPart(linkPart); scene.AddNewSceneObject(sog, true); - + // In a test, we have to crank the backup handle manually. Normally this would be done by the timer invoked // scene backup thread. scene.Backup(true); - + List storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID); - + Assert.That(storedObjects.Count, Is.EqualTo(1)); Assert.That(storedObjects[0].Parts.Length, Is.EqualTo(2)); Assert.That(storedObjects[0].ContainsPart(rootPartUuid)); Assert.That(storedObjects[0].ContainsPart(linkPartUuid)); } - + /// /// Test that a delink of a previously linked object is correctly persisted to the database /// @@ -327,20 +327,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - + TestScene scene = new SceneHelpers().SetupScene(); - + string rootPartName = "rootpart"; UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); string linkPartName = "linkpart"; UUID linkPartUuid = new UUID("00000000-0000-0000-0001-000000000000"); SceneObjectPart rootPart - = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) { Name = rootPartName, UUID = rootPartUuid }; - + SceneObjectPart linkPart - = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) + = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) { Name = linkPartName, UUID = linkPartUuid }; SceneObjectGroup linkGroup = new SceneObjectGroup(linkPart); scene.AddNewSceneObject(linkGroup, true); @@ -359,13 +359,15 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false); Assert.IsFalse(groupToDelete.GroupContainsForeignPrims); +/* backup is async scene.DeleteSceneObject(groupToDelete, false); - + List storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID); Assert.AreEqual(1, storedObjects.Count); Assert.AreEqual(1, storedObjects[0].Parts.Length); Assert.IsTrue(storedObjects[0].ContainsPart(rootPartUuid)); +*/ } } } diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs index 975c4d9..8b3a7e9 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs @@ -60,6 +60,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(g1Post.RootPart.Scale.X, Is.EqualTo(2)); Assert.That(g1Post.RootPart.Scale.Y, Is.EqualTo(3)); Assert.That(g1Post.RootPart.Scale.Z, Is.EqualTo(4)); + +// Assert.That(g1Post.RootPart.UndoCount, Is.EqualTo(1)); } /// @@ -72,8 +74,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests //log4net.Config.XmlConfigurator.Configure(); Scene scene = new SceneHelpers().SetupScene(); - - SceneObjectGroup g1 = SceneHelpers.CreateSceneObject(2, UUID.Zero); + UUID owner = UUID.Random(); + SceneObjectGroup g1 = SceneHelpers.CreateSceneObject(2, owner); g1.RootPart.Scale = new Vector3(2, 3, 4); g1.Parts[1].Scale = new Vector3(5, 6, 7); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs index e00defd..c2c7822 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs @@ -138,8 +138,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneObjectPart childPart = so.Parts[1]; - // FIXME: Should be childPosition after rotation? - Assert.That(childPart.AbsolutePosition, Is.EqualTo(rootPartPosition + childOffsetPosition)); + Assert.That(childPart.AbsolutePosition, Is.EqualTo(childPosition)); Assert.That(childPart.GroupPosition, Is.EqualTo(rootPartPosition)); Assert.That(childPart.GetWorldPosition(), Is.EqualTo(childPosition)); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 1737e3c..8d88083 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -71,7 +71,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests m_so1.ScriptSetTemporaryStatus(false); Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); - Assert.That(m_so1.Backup, Is.True); + Assert.That(m_so1.Backup, Is.True); } [Test] @@ -91,7 +91,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests m_so1.ScriptSetPhantomStatus(false); - Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); } [Test] @@ -107,11 +107,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests m_so1.ScriptSetVolumeDetect(true); // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); - Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom)); + // PrimFlags.JointLP2P is incorrect it now means VolumeDetect (as defined by viewers) + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.JointLP2P)); m_so1.ScriptSetVolumeDetect(false); - Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); } [Test] @@ -146,13 +147,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests m_so1.ScriptSetPhysicsStatus(true); m_so1.ScriptSetVolumeDetect(true); - Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics)); + // PrimFlags.JointLP2P is incorrect it now means VolumeDetect (as defined by viewers) + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom | PrimFlags.Physics | PrimFlags.JointLP2P)); m_so1.ScriptSetVolumeDetect(false); - Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); } - + [Test] public void TestSetPhysicsLinkset() { diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs index af3ce8e..340da9c 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* undo has changed, this tests dont apply without large changes using System; using System.Reflection; using NUnit.Framework; @@ -179,4 +180,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(g1.GroupScale, Is.EqualTo(newSize)); } } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs index aadf7c6..4ec69cd 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs @@ -42,7 +42,7 @@ using OpenSim.Tests.Common; namespace OpenSim.Region.Framework.Scenes.Tests { [TestFixture] - public class SceneObjectUserGroupTests : OpenSimTestCase + public class SceneObjectUserGroupTests { /// /// Test share with group object functionality @@ -52,31 +52,32 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestShareWithGroup() { TestHelpers.InMethod(); - +// log4net.Config.XmlConfigurator.Configure(); + UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); - + TestScene scene = new SceneHelpers().SetupScene(); IConfigSource configSource = new IniConfigSource(); - + IConfig startupConfig = configSource.AddConfig("Startup"); startupConfig.Set("serverside_object_permissions", true); - - IConfig groupsConfig = configSource.AddConfig("Groups"); + + IConfig groupsConfig = configSource.AddConfig("Groups"); groupsConfig.Set("Enabled", true); - groupsConfig.Set("Module", "GroupsModule"); - groupsConfig.Set("DebugEnabled", true); - + groupsConfig.Set("Module", "GroupsModule"); + groupsConfig.Set("DebugEnabled", true); + SceneHelpers.SetupSceneModules( - scene, configSource, new object[] - { new PermissionsModule(), - new GroupsModule(), + scene, configSource, new object[] + { new DefaultPermissionsModule(), + new GroupsModule(), new MockGroupsServicesConnector() }); - - IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; - - IGroupsModule groupsModule = scene.RequestModuleInterface(); - + + IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; + + IGroupsModule groupsModule = scene.RequestModuleInterface(); + groupsModule.CreateGroup(client, "group1", "To boldly go", true, UUID.Zero, 5, true, true, true); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 96d112d..0f386bc 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -44,6 +44,7 @@ using OpenSim.Region.CoreModules.World.Serialiser; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Tests.Common; using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Services.Interfaces; namespace OpenSim.Region.Framework.Scenes.Tests { @@ -141,7 +142,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Check rest of exepcted parameters. Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null); Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); - + Assert.That(sp.IsChildAgent, Is.False); Assert.That(sp.UUID, Is.EqualTo(spUuid)); @@ -226,7 +227,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests // *** This is the first stage, when a neighbouring region is told that a viewer is about to try and // establish a child scene presence. We pass in the circuit code that the client has to connect with *** // XXX: ViaLogin may not be correct here. - scene.SimulationService.CreateAgent(null, region, acd, (uint)TeleportFlags.ViaLogin, out reason); + EntityTransferContext ctx = new EntityTransferContext(); + scene.SimulationService.CreateAgent(null, region, acd, (uint)TeleportFlags.ViaLogin, ctx, out reason); Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(agentId), Is.Not.Null); Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); @@ -260,16 +262,15 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + // UUID agent1Id = UUID.Parse("00000000-0000-0000-0000-000000000001"); - + TestScene myScene1 = new SceneHelpers().SetupScene("Neighbour y", UUID.Random(), 1000, 1000); TestScene myScene2 = new SceneHelpers().SetupScene("Neighbour y + 1", UUID.Random(), 1001, 1000); IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Startup"); config.Set("serverside_object_permissions", true); - config.Set("EventQueue", true); EntityTransferModule etm = new EntityTransferModule(); @@ -278,7 +279,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests EventQueueGetModule eqgm2 = new EventQueueGetModule(); SceneHelpers.SetupSceneModules(myScene2, configSource, etm, eqgm2); - + // SceneHelpers.AddScenePresence(myScene1, agent1Id); // ScenePresence childPresence = myScene2.GetScenePresence(agent1); // @@ -287,4 +288,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Assert.That(childPresence.IsChildAgent, Is.True); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs index 42d91b9..d650c43 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs @@ -60,7 +60,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestScene scene = new SceneHelpers().SetupScene(); ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); sp.Flying = true; - sp.PhysicsCollisionUpdate(new CollisionEventUpdate()); + sp.Animator.UpdateMovementAnimations(); Assert.That(sp.Animator.CurrentMovementAnimation, Is.EqualTo("HOVER")); } diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs index e5c847e..90c5197 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs @@ -97,7 +97,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(sp.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); Assert.That(sp.AbsolutePosition.Z, Is.LessThan(targetPos.X)); - m_scene.Update(10); + m_scene.Update(50); double distanceToTarget = Util.GetDistanceTo(sp.AbsolutePosition, targetPos); Assert.That(distanceToTarget, Is.LessThan(1), "Avatar not within 1 unit of target position on first move"); @@ -121,7 +121,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(sp.AbsolutePosition.Y, Is.EqualTo(startPos.Y)); Assert.That(sp.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); - m_scene.Update(10); + m_scene.Update(50); distanceToTarget = Util.GetDistanceTo(sp.AbsolutePosition, targetPos); Assert.That(distanceToTarget, Is.LessThan(1), "Avatar not within 1 unit of target position on second move"); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs index 2e6dc70..aa26767 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs @@ -73,14 +73,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneHelpers.SetupSceneModules(scene, capsMod); ScenePresence sp = SceneHelpers.AddChildScenePresence(scene, spUuid); - Assert.That(capsMod.GetCapsForUser(spUuid), Is.Not.Null); + //Assert.That(capsMod.GetCapsForUser(spUuid), Is.Not.Null); // TODO: Need to add tests for other ICapabiltiesModule methods. +// scene.IncomingCloseAgent(sp.UUID, false); +// //Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null); scene.CloseAgent(sp.UUID, false); - Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null); +// Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null); // TODO: Need to add tests for other ICapabiltiesModule methods. } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index 7127644..3d51a63 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -39,6 +39,8 @@ using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Region.CoreModules.World.Permissions; using OpenSim.Tests.Common; +using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; +using System.Threading; namespace OpenSim.Region.Framework.Scenes.Tests { @@ -190,7 +192,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // We need to set up the permisions module on scene B so that our later use of agent limit to deny // QueryAccess won't succeed anyway because administrators are always allowed in and the default // IsAdministrator if no permissions module is present is true. - SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), new PermissionsModule(), etmB); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), new DefaultPermissionsModule(), etmB); AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); TestClient tc = new TestClient(acd, sceneA); @@ -229,7 +231,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); - // sceneB agent should also still be root + // sceneB agent should still be child Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); // sceneB should ignore unauthorized attempt to upgrade agent to root @@ -244,4 +246,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs index b232a44..e3ebf36 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs @@ -166,6 +166,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests [Test] public void TestSitAndStandWithSitTarget() { +/* sit position math as changed, this needs to be fixed later TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); @@ -223,6 +224,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); Assert.That(part.GetSittingAvatars(), Is.Null); +*/ } [Test] @@ -246,4 +248,4 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(m_sp.PhysicsActor, Is.Not.Null); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 443ec51..86500c7 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -282,7 +282,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // We need to set up the permisions module on scene B so that our later use of agent limit to deny // QueryAccess won't succeed anyway because administrators are always allowed in and the default // IsAdministrator if no permissions module is present is true. - SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB }); + SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new DefaultPermissionsModule(), etmB }); // Shared scene modules SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); @@ -447,7 +447,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // We need to set up the permisions module on scene B so that our later use of agent limit to deny // QueryAccess won't succeed anyway because administrators are always allowed in and the default // IsAdministrator if no permissions module is present is true. - SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB }); + SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new DefaultPermissionsModule(), etmB }); // Shared scene modules SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); @@ -465,7 +465,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests teleportLookAt, (uint)TeleportFlags.ViaLocation); - // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate + // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate // communication with the destination region. But this is a very non-obvious way of doing it - really we // should be forced to expicitly set this up. @@ -627,8 +627,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Both these operations will occur on different threads and will wait for each other. // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 // test protocol, where we are trying to avoid unpredictable async operations in regression tests. - tc.OnTestClientSendRegionTeleport - += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) + tc.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); sceneA.RequestTeleportLocation( diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs index 045fd3c..4ce6a95 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneStatisticsTests.cs @@ -54,8 +54,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID ownerId = TestHelpers.ParseTail(0x1); SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(3, ownerId, "so1", 0x10); - so1.ScriptSetPhysicsStatus(true); m_scene.AddSceneObject(so1); + so1.ScriptSetPhysicsStatus(true); Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(3)); Assert.That(m_scene.SceneGraph.GetActiveObjectsCount(), Is.EqualTo(3)); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs index 584a03c..dbb6a37 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTelehubTests.cs @@ -70,7 +70,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Must still be possible to successfully log in UUID loggingInUserId = TestHelpers.ParseTail(0x2); - UserAccount ua + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password"); SceneHelpers.AddScenePresence(scene, ua); @@ -107,7 +107,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Must still be possible to successfully log in UUID loggingInUserId = TestHelpers.ParseTail(0x2); - UserAccount ua + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, "Test", "User", loggingInUserId, "password"); SceneHelpers.AddScenePresence(scene, ua); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs index 517faf1..6c0af8f 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs @@ -66,7 +66,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests uint sizeX = 512; uint sizeY = 512; - Scene scene + Scene scene = new SceneHelpers().SetupScene("scene", regionUuid, 1000, 1000, sizeX, sizeY, new IniConfigSource()); Assert.AreEqual(sizeX, scene.RegionInfo.RegionSizeX); @@ -83,7 +83,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Scene scene = new SceneHelpers().SetupScene(); scene.Update(1); - + Assert.That(scene.Frame, Is.EqualTo(1)); } diff --git a/OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs index eeda84f..c74c83f 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SharedRegionModuleTests.cs @@ -105,7 +105,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // rmcp.LoadModulesFromAddins = false; //// reg.RegisterInterface(rmcp); // rmcp.Initialise(sim); -// rmcp.PostInitialise(); +// rmcp.PostInitialise(); // TypeExtensionNode node = new TypeExtensionNode(); // node. // rmcp.AddNode(node, configSource.Configs["Modules"], new Dictionary>()); @@ -120,9 +120,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests int expectedEventCount = 6; Assert.AreEqual( - expectedEventCount, - co.Count, - "Expected {0} events but only got {1} ({2})", + expectedEventCount, + co.Count, + "Expected {0} events but only got {1} ({2})", expectedEventCount, co.Count, string.Join(",", co)); Assert.AreEqual("Initialise", co[0]); Assert.AreEqual("PostInitialise", co[1]); @@ -137,7 +137,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests { // FIXME: Should really use MethodInfo public List CallOrder = new List(); - + public string Name { get { return "TestSharedRegion"; } } public Type ReplaceableInterface { get { return null; } } @@ -186,13 +186,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void Initialise() {} - public void Initialise(OpenSimBase sim) + public void Initialise(OpenSimBase sim) { m_openSim = sim; } /// - /// Called when the application loading is completed + /// Called when the application loading is completed /// public void PostInitialise() { @@ -228,8 +228,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests } scene.RegionModules.Clear(); - } - + } + public void AddNode(ISharedRegionModule module) { m_sharedInstances.Add(module); diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs index b01088d..8273e32 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.Framework.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); @@ -78,7 +78,7 @@ namespace OpenSim.Region.Framework.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); @@ -95,7 +95,7 @@ namespace OpenSim.Region.Framework.Tests Quaternion rezRot = new Quaternion(0.5f, 0.5f, 0.5f, 0.5f); Vector3 rezVel = new Vector3(2, 2, 2); - scene.RezObject(sop1, taskSceneObjectItem, rezPos, rezRot, rezVel, 0); + scene.RezObject(sop1, taskSceneObjectItem, rezPos, rezRot, rezVel, 0,false); SceneObjectGroup rezzedObject = scene.GetSceneObjectGroup("tso"); @@ -121,7 +121,7 @@ namespace OpenSim.Region.Framework.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); @@ -130,18 +130,18 @@ namespace OpenSim.Region.Framework.Tests = TaskInventoryHelpers.AddNotecard( scene.AssetService, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); - InventoryFolderBase folder + InventoryFolderBase folder = InventoryArchiveUtils.FindFoldersByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0]; - + // Perform test string message; scene.MoveTaskInventoryItem(user1.PrincipalID, folder.ID, sop1, sopItem1.ItemID, out message); - + InventoryItemBase ncUserItem = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Objects/ncItem"); Assert.That(ncUserItem, Is.Not.Null, "Objects/ncItem was not found"); } - + /// /// Test MoveTaskInventoryItem from a part inventory to a user inventory where the item has no parent folder assigned. /// @@ -153,7 +153,7 @@ namespace OpenSim.Region.Framework.Tests { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); @@ -162,11 +162,11 @@ namespace OpenSim.Region.Framework.Tests TaskInventoryItem sopItem1 = TaskInventoryHelpers.AddNotecard( scene.AssetService, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900), "Hello World!"); - + // Perform test string message; scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID, out message); - + InventoryItemBase ncUserItem = InventoryArchiveUtils.FindItemByPath(scene.InventoryService, user1.PrincipalID, "Notecards/ncItem"); Assert.That(ncUserItem, Is.Not.Null, "Notecards/ncItem was not found"); diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs index 8250e6c..58e157c 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs @@ -38,10 +38,7 @@ using OpenMetaverse; using OpenMetaverse.Assets; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; -using OpenSim.Region.CoreModules.World.Serialiser; -using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; @@ -116,7 +113,7 @@ namespace OpenSim.Region.Framework.Tests { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); @@ -138,5 +135,66 @@ namespace OpenSim.Region.Framework.Tests Assert.That(reretrievedFolders.Count, Is.EqualTo(2)); } + + // Work in Progress test. All Assertions pertaining permissions are commented for now. + [Test] + public void TestGiveInventoryItemFullPerms() + { + TestHelpers.InMethod(); + + List modules = new List(); + IConfigSource config = DefaultConfig(modules); + Scene scene = new SceneHelpers().SetupScene("Inventory Permissions", UUID.Random(), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); + + UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); + UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); + ScenePresence sp1 = SceneHelpers.AddScenePresence(scene, user1.PrincipalID); + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, user2.PrincipalID); + + InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "SomeObject", user1.PrincipalID, InventoryType.Object); + // Set All perms in inventory + item1.NextPermissions = (uint)OpenMetaverse.PermissionMask.All; + scene.UpdateInventoryItemAsset(sp1.ControllingClient, UUID.Zero, item1.ID, item1); + //Assert.That((item1.NextPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + string message; + + InventoryItemBase retrievedItem1 = scene.GiveInventoryItem(user2.PrincipalID, user1.PrincipalID, item1.ID, out message); + Assert.That(retrievedItem1, Is.Not.Null); + //Assert.That((retrievedItem1.CurrentPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + retrievedItem1 + = UserInventoryHelpers.GetInventoryItem(scene.InventoryService, user2.PrincipalID, "Objects/SomeObject"); + Assert.That(retrievedItem1, Is.Not.Null); + //Assert.That((retrievedItem1.BasePermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + //Assert.That((retrievedItem1.CurrentPermissions & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + // Rez the object + scene.RezObject(sp2.ControllingClient, retrievedItem1.ID, UUID.Zero, Vector3.Zero, Vector3.Zero, UUID.Zero, 0, false, false, false, UUID.Zero); + SceneObjectGroup sog = scene.GetSceneObjectGroup("SomeObject"); + Assert.That(sog, Is.Not.Null); + + // This is failing for all sorts of reasons. We'll fix it after perms are fixed. + //Console.WriteLine("Item Perms " + retrievedItem1.CurrentPermissions + " Obj Owner Perms " + sog.RootPart.OwnerMask + " Base Perms " + sog.RootPart.BaseMask + "\n"); + //Assert.True((sog.RootPart.OwnerMask & (uint)OpenMetaverse.PermissionMask.All) == (uint)OpenMetaverse.PermissionMask.All); + + } + + public static IConfigSource DefaultConfig(List modules) + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + config.AddConfig("Permissions"); + config.Configs["Permissions"].Set("permissionmodules", "DefaultPermissionsModule"); + config.Configs["Permissions"].Set("serverside_object_permissions", true); + config.Configs["Permissions"].Set("propagate_permissions", true); + + modules.Add(new BasicInventoryAccessModule()); + return config; + } + } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index 937c414..4ceebc1 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs @@ -41,7 +41,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests { protected IAssetService m_assetService; protected UuidGatherer m_uuidGatherer; - + [SetUp] public void Init() { @@ -55,9 +55,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestCorruptAsset() { TestHelpers.InMethod(); - + UUID corruptAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); - AssetBase corruptAsset + AssetBase corruptAsset = AssetHelpers.CreateAsset(corruptAssetUuid, AssetType.Notecard, "CORRUPT ASSET", UUID.Zero); m_assetService.Store(corruptAsset); @@ -67,7 +67,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // We count the uuid as gathered even if the asset itself is corrupt. Assert.That(m_uuidGatherer.GatheredUuids.Count, Is.EqualTo(1)); } - + /// /// Test requests made for non-existent assets while we're gathering /// @@ -75,7 +75,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestMissingAsset() { TestHelpers.InMethod(); - + UUID missingAssetUuid = UUID.Parse("00000000-0000-0000-0000-000000000666"); m_uuidGatherer.AddForInspection(missingAssetUuid); @@ -89,23 +89,23 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - + UUID ownerId = TestHelpers.ParseTail(0x10); UUID embeddedId = TestHelpers.ParseTail(0x20); UUID secondLevelEmbeddedId = TestHelpers.ParseTail(0x21); UUID missingEmbeddedId = TestHelpers.ParseTail(0x22); UUID ncAssetId = TestHelpers.ParseTail(0x30); - AssetBase ncAsset + AssetBase ncAsset = AssetHelpers.CreateNotecardAsset( ncAssetId, string.Format("Hello{0}World{1}", embeddedId, missingEmbeddedId)); m_assetService.Store(ncAsset); - AssetBase embeddedAsset + AssetBase embeddedAsset = AssetHelpers.CreateNotecardAsset(embeddedId, string.Format("{0} We'll meet again.", secondLevelEmbeddedId)); m_assetService.Store(embeddedAsset); - AssetBase secondLevelEmbeddedAsset + AssetBase secondLevelEmbeddedAsset = AssetHelpers.CreateNotecardAsset(secondLevelEmbeddedId, "Don't know where, don't know when."); m_assetService.Store(secondLevelEmbeddedAsset); diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs index 860172c..8fff38f 100644 --- a/OpenSim/Region/Framework/Scenes/UndoState.cs +++ b/OpenSim/Region/Framework/Scenes/UndoState.cs @@ -27,202 +27,307 @@ using System; using System.Reflection; +using System.Collections.Generic; using log4net; using OpenMetaverse; +using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; namespace OpenSim.Region.Framework.Scenes { public class UndoState { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public Vector3 Position = Vector3.Zero; - public Vector3 Scale = Vector3.Zero; - public Quaternion Rotation = Quaternion.Identity; - - /// - /// Is this undo state for an entire group? - /// - public bool ForGroup; + const int UNDOEXPIRESECONDS = 300; // undo expire time (nice to have it came from a ini later) + public ObjectChangeData data; + public DateTime creationtime; /// /// Constructor. /// /// - /// True if the undo is for an entire group - public UndoState(SceneObjectPart part, bool forGroup) + /// bit field with what is changed + /// + public UndoState(SceneObjectPart part, ObjectChangeType change) { - if (part.ParentID == 0) - { - ForGroup = forGroup; - -// if (ForGroup) - Position = part.ParentGroup.AbsolutePosition; -// else -// Position = part.OffsetPosition; - -// m_log.DebugFormat( -// "[UNDO STATE]: Storing undo position {0} for root part", Position); + data = new ObjectChangeData(); + data.change = change; + creationtime = DateTime.UtcNow; - Rotation = part.RotationOffset; - -// m_log.DebugFormat( -// "[UNDO STATE]: Storing undo rotation {0} for root part", Rotation); - - Scale = part.Shape.Scale; - -// m_log.DebugFormat( -// "[UNDO STATE]: Storing undo scale {0} for root part", Scale); + if (part.ParentGroup.RootPart == part) + { + if ((change & ObjectChangeType.Position) != 0) + data.position = part.ParentGroup.AbsolutePosition; + if ((change & ObjectChangeType.Rotation) != 0) + data.rotation = part.RotationOffset; + if ((change & ObjectChangeType.Scale) != 0) + data.scale = part.Shape.Scale; } else { - Position = part.OffsetPosition; -// m_log.DebugFormat( -// "[UNDO STATE]: Storing undo position {0} for child part", Position); + if ((change & ObjectChangeType.Position) != 0) + data.position = part.OffsetPosition; + if ((change & ObjectChangeType.Rotation) != 0) + data.rotation = part.RotationOffset; + if ((change & ObjectChangeType.Scale) != 0) + data.scale = part.Shape.Scale; + } + } + /// + /// check if undo or redo is too old + /// - Rotation = part.RotationOffset; -// m_log.DebugFormat( -// "[UNDO STATE]: Storing undo rotation {0} for child part", Rotation); + public bool checkExpire() + { + TimeSpan t = DateTime.UtcNow - creationtime; + if (t.Seconds > UNDOEXPIRESECONDS) + return true; + return false; + } - Scale = part.Shape.Scale; -// m_log.DebugFormat( -// "[UNDO STATE]: Storing undo scale {0} for child part", Scale); - } + /// + /// updates undo or redo creation time to now + /// + public void updateExpire() + { + creationtime = DateTime.UtcNow; } /// /// Compare the relevant state in the given part to this state. /// /// - /// true if both the part's position, rotation and scale match those in this undo state. False otherwise. - public bool Compare(SceneObjectPart part) + /// true what fiels and related data are equal, False otherwise. + /// + public bool Compare(SceneObjectPart part, ObjectChangeType change) { + if (data.change != change) // if diferent targets, then they are diferent + return false; + if (part != null) { if (part.ParentID == 0) - return - Position == part.ParentGroup.AbsolutePosition - && Rotation == part.RotationOffset - && Scale == part.Shape.Scale; + { + if ((change & ObjectChangeType.Position) != 0 && data.position != part.ParentGroup.AbsolutePosition) + return false; + } else - return - Position == part.OffsetPosition - && Rotation == part.RotationOffset - && Scale == part.Shape.Scale; - } + { + if ((change & ObjectChangeType.Position) != 0 && data.position != part.OffsetPosition) + return false; + } + + if ((change & ObjectChangeType.Rotation) != 0 && data.rotation != part.RotationOffset) + return false; + if ((change & ObjectChangeType.Rotation) != 0 && data.scale == part.Shape.Scale) + return false; + return true; + } return false; } - public void PlaybackState(SceneObjectPart part) + /// + /// executes the undo or redo to a part or its group + /// + /// + /// + + public void PlayState(SceneObjectPart part) { part.Undoing = true; - if (part.ParentID == 0) - { -// m_log.DebugFormat( -// "[UNDO STATE]: Undoing position to {0} for root part {1} {2}", -// Position, part.Name, part.LocalId); + SceneObjectGroup grp = part.ParentGroup; - if (Position != Vector3.Zero) - { - if (ForGroup) - part.ParentGroup.AbsolutePosition = Position; - else - part.ParentGroup.UpdateRootPosition(Position); - } + if (grp != null) + { + grp.doChangeObject(part, data); + } + part.Undoing = false; + } + } -// m_log.DebugFormat( -// "[UNDO STATE]: Undoing rotation {0} to {1} for root part {2} {3}", -// part.RotationOffset, Rotation, part.Name, part.LocalId); + public class UndoRedoState + { + int size; + public LinkedList m_redo = new LinkedList(); + public LinkedList m_undo = new LinkedList(); - if (ForGroup) - part.UpdateRotation(Rotation); - else - part.ParentGroup.UpdateRootRotation(Rotation); + /// + /// creates a new UndoRedoState with default states memory size + /// - if (Scale != Vector3.Zero) - { -// m_log.DebugFormat( -// "[UNDO STATE]: Undoing scale {0} to {1} for root part {2} {3}", -// part.Shape.Scale, Scale, part.Name, part.LocalId); + public UndoRedoState() + { + size = 5; + } - if (ForGroup) - part.ParentGroup.GroupResize(Scale); - else - part.Resize(Scale); - } + /// + /// creates a new UndoRedoState with states memory having indicated size + /// + /// - part.ParentGroup.ScheduleGroupForTerseUpdate(); - } + public UndoRedoState(int _size) + { + if (_size < 3) + size = 3; else - { - // Note: Updating these properties on sop automatically schedules an update if needed - if (Position != Vector3.Zero) - { -// m_log.DebugFormat( -// "[UNDO STATE]: Undoing position {0} to {1} for child part {2} {3}", -// part.OffsetPosition, Position, part.Name, part.LocalId); + size = _size; + } - part.OffsetPosition = Position; - } + /// + /// returns number of undo entries in memory + /// -// m_log.DebugFormat( -// "[UNDO STATE]: Undoing rotation {0} to {1} for child part {2} {3}", -// part.RotationOffset, Rotation, part.Name, part.LocalId); + public int Count + { + get { return m_undo.Count; } + } - part.UpdateRotation(Rotation); + /// + /// clears all undo and redo entries + /// - if (Scale != Vector3.Zero) + public void Clear() + { + m_undo.Clear(); + m_redo.Clear(); + } + + /// + /// adds a new state undo to part or its group, with changes indicated by what bits + /// + /// + /// bit field with what is changed + + public void StoreUndo(SceneObjectPart part, ObjectChangeType change) + { + lock (m_undo) + { + UndoState last; + + if (m_redo.Count > 0) // last code seems to clear redo on every new undo { -// m_log.DebugFormat( -// "[UNDO STATE]: Undoing scale {0} to {1} for child part {2} {3}", -// part.Shape.Scale, Scale, part.Name, part.LocalId); + m_redo.Clear(); + } - part.Resize(Scale); + if (m_undo.Count > 0) + { + // check expired entry + last = m_undo.First.Value; + if (last != null && last.checkExpire()) + m_undo.Clear(); + else + { + // see if we actually have a change + if (last != null) + { + if (last.Compare(part, change)) + return; + } + } } - } - part.Undoing = false; + // limite size + while (m_undo.Count >= size) + m_undo.RemoveLast(); + + UndoState nUndo = new UndoState(part, change); + m_undo.AddFirst(nUndo); + } } - public void PlayfwdState(SceneObjectPart part) - { - part.Undoing = true; + /// + /// executes last state undo to part or its group + /// current state is pushed into redo + /// + /// - if (part.ParentID == 0) + public void Undo(SceneObjectPart part) + { + lock (m_undo) { - if (Position != Vector3.Zero) - part.ParentGroup.AbsolutePosition = Position; - - if (Rotation != Quaternion.Identity) - part.UpdateRotation(Rotation); + UndoState nUndo; - if (Scale != Vector3.Zero) + // expire redo + if (m_redo.Count > 0) { - if (ForGroup) - part.ParentGroup.GroupResize(Scale); - else - part.Resize(Scale); + nUndo = m_redo.First.Value; + if (nUndo != null && nUndo.checkExpire()) + m_redo.Clear(); } - part.ParentGroup.ScheduleGroupForTerseUpdate(); + if (m_undo.Count > 0) + { + UndoState goback = m_undo.First.Value; + // check expired + if (goback != null && goback.checkExpire()) + { + m_undo.Clear(); + return; + } + + if (goback != null) + { + m_undo.RemoveFirst(); + + // redo limite size + while (m_redo.Count >= size) + m_redo.RemoveLast(); + + nUndo = new UndoState(part, goback.data.change); // new value in part should it be full goback copy? + m_redo.AddFirst(nUndo); + + goback.PlayState(part); + } + } } - else + } + + /// + /// executes last state redo to part or its group + /// current state is pushed into undo + /// + /// + + public void Redo(SceneObjectPart part) + { + lock (m_undo) { - // Note: Updating these properties on sop automatically schedules an update if needed - if (Position != Vector3.Zero) - part.OffsetPosition = Position; + UndoState nUndo; - if (Rotation != Quaternion.Identity) - part.UpdateRotation(Rotation); + // expire undo + if (m_undo.Count > 0) + { + nUndo = m_undo.First.Value; + if (nUndo != null && nUndo.checkExpire()) + m_undo.Clear(); + } - if (Scale != Vector3.Zero) - part.Resize(Scale); + if (m_redo.Count > 0) + { + UndoState gofwd = m_redo.First.Value; + // check expired + if (gofwd != null && gofwd.checkExpire()) + { + m_redo.Clear(); + return; + } + + if (gofwd != null) + { + m_redo.RemoveFirst(); + + // limite undo size + while (m_undo.Count >= size) + m_undo.RemoveLast(); + + nUndo = new UndoState(part, gofwd.data.change); // new value in part should it be full gofwd copy? + m_undo.AddFirst(nUndo); + + gofwd.PlayState(part); + } + } } - - part.Undoing = false; } } @@ -247,4 +352,4 @@ namespace OpenSim.Region.Framework.Scenes m_terrainModule.UndoTerrain(m_terrainChannel); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 2070ce5..80d3f62 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -65,7 +65,10 @@ namespace OpenSim.Region.Framework.Scenes /// /// The gathered uuids. public IDictionary GatheredUuids { get; private set; } - + public HashSet FailedUUIDs { get; private set; } + public HashSet UncertainAssetsUUIDs { get; private set; } + public int possibleNotAssetCount { get; set; } + public int ErrorCount { get; private set; } /// /// Gets the next UUID to inspect. /// @@ -92,7 +95,10 @@ namespace OpenSim.Region.Framework.Scenes /// /// Asset service. /// - public UuidGatherer(IAssetService assetService) : this(assetService, new Dictionary()) {} + public UuidGatherer(IAssetService assetService) : this(assetService, new Dictionary(), + new HashSet (),new HashSet ()) {} + public UuidGatherer(IAssetService assetService, IDictionary collector) : this(assetService, collector, + new HashSet (), new HashSet ()) {} /// /// Initializes a new instance of the class. @@ -101,16 +107,20 @@ namespace OpenSim.Region.Framework.Scenes /// Asset service. /// /// - /// Gathered UUIDs will be collected in this dictinaory. + /// Gathered UUIDs will be collected in this dictionary. /// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected. /// - public UuidGatherer(IAssetService assetService, IDictionary collector) + public UuidGatherer(IAssetService assetService, IDictionary collector, HashSet failedIDs, HashSet uncertainAssetsUUIDs) { m_assetService = assetService; GatheredUuids = collector; // FIXME: Not efficient for searching, can improve. m_assetUuidsToInspect = new Queue(); + FailedUUIDs = failedIDs; + UncertainAssetsUUIDs = uncertainAssetsUUIDs; + ErrorCount = 0; + possibleNotAssetCount = 0; } /// @@ -120,16 +130,28 @@ namespace OpenSim.Region.Framework.Scenes /// UUID. public bool AddForInspection(UUID uuid) { + if(uuid == UUID.Zero) + return false; + + if(FailedUUIDs.Contains(uuid)) + { + if(UncertainAssetsUUIDs.Contains(uuid)) + possibleNotAssetCount++; + else + ErrorCount++; + return false; + } + if(GatheredUuids.ContainsKey(uuid)) + return false; if (m_assetUuidsToInspect.Contains(uuid)) return false; // m_log.DebugFormat("[UUID GATHERER]: Adding asset {0} for inspection", uuid); m_assetUuidsToInspect.Enqueue(uuid); - return true; } - + /// /// Gather all the asset uuids associated with a given object. /// @@ -142,7 +164,9 @@ namespace OpenSim.Region.Framework.Scenes public void AddForInspection(SceneObjectGroup sceneObject) { // m_log.DebugFormat( - // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); + // "[UUID GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); + if(sceneObject.IsDeleted) + return; SceneObjectPart[] parts = sceneObject.Parts; for (int i = 0; i < parts.Length; i++) @@ -150,7 +174,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = parts[i]; // m_log.DebugFormat( - // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); + // "[UUID GATHERER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); try { @@ -179,8 +203,10 @@ namespace OpenSim.Region.Framework.Scenes if (part.Shape.ProjectionTextureUUID != UUID.Zero) GatheredUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; - if (part.CollisionSound != UUID.Zero) - GatheredUuids[part.CollisionSound] = (sbyte)AssetType.Sound; + UUID collisionSound = part.CollisionSound; + if ( collisionSound != UUID.Zero && + collisionSound != part.invalidCollisionSoundUUID) + GatheredUuids[collisionSound] = (sbyte)AssetType.Sound; if (part.ParticleSystem.Length > 0) { @@ -193,7 +219,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception) { m_log.WarnFormat( - "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.", + "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.", part.Name, part.UUID, sceneObject.Name, sceneObject.UUID); } } @@ -204,29 +230,24 @@ namespace OpenSim.Region.Framework.Scenes foreach (TaskInventoryItem tii in taskDictionary.Values) { // m_log.DebugFormat( - // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", + // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", // tii.Name, tii.Type, part.Name, part.UUID); - - if (!GatheredUuids.ContainsKey(tii.AssetID)) - AddForInspection(tii.AssetID, (sbyte)tii.Type); + AddForInspection(tii.AssetID, (sbyte)tii.Type); } // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and - // inventory transfer. There needs to be a way for a module to register a method without assuming a + // inventory transfer. There needs to be a way for a module to register a method without assuming a // Scene.EventManager is present. // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs - RecordMaterialsUuids(part); + RecordMaterialsUuids(part); } catch (Exception e) { m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e); - m_log.DebugFormat( - "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)", - part.Shape.TextureEntry.Length); } } } @@ -277,58 +298,115 @@ namespace OpenSim.Region.Framework.Scenes /// The uuid of the asset for which to gather referenced assets private void GetAssetUuids(UUID assetUuid) { + if(assetUuid == UUID.Zero) + return; + + if(FailedUUIDs.Contains(assetUuid)) + { + if(UncertainAssetsUUIDs.Contains(assetUuid)) + possibleNotAssetCount++; + else + ErrorCount++; + return; + } + // avoid infinite loops if (GatheredUuids.ContainsKey(assetUuid)) return; + AssetBase assetBase; try - { - AssetBase assetBase = GetAsset(assetUuid); + { + assetBase = GetAsset(assetUuid); + } + catch (Exception e) + { + m_log.ErrorFormat("[UUID GATHERER]: Failed to get asset {0} : {1}", assetUuid, e.Message); + ErrorCount++; + FailedUUIDs.Add(assetUuid); + return; + } - if (null != assetBase) - { - sbyte assetType = assetBase.Type; - GatheredUuids[assetUuid] = assetType; + if(assetBase == null) + { +// m_log.ErrorFormat("[UUID GATHERER]: asset {0} not found", assetUuid); + FailedUUIDs.Add(assetUuid); + if(UncertainAssetsUUIDs.Contains(assetUuid)) + possibleNotAssetCount++; + else + ErrorCount++; + return; + } - if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) - { - RecordWearableAssetUuids(assetBase); - } - else if ((sbyte)AssetType.Gesture == assetType) - { - RecordGestureAssetUuids(assetBase); - } - else if ((sbyte)AssetType.Notecard == assetType) - { - RecordTextEmbeddedAssetUuids(assetBase); - } - else if ((sbyte)AssetType.LSLText == assetType) - { - RecordTextEmbeddedAssetUuids(assetBase); - } - else if ((sbyte)OpenSimAssetType.Material == assetType) - { - RecordMaterialAssetUuids(assetBase); - } - else if ((sbyte)AssetType.Object == assetType) - { - RecordSceneObjectAssetUuids(assetBase); - } + if(UncertainAssetsUUIDs.Contains(assetUuid)) + UncertainAssetsUUIDs.Remove(assetUuid); + + sbyte assetType = assetBase.Type; + + if(assetBase.Data == null || assetBase.Data.Length == 0) + { +// m_log.ErrorFormat("[UUID GATHERER]: asset {0}, type {1} has no data", assetUuid, assetType); + ErrorCount++; + FailedUUIDs.Add(assetUuid); + return; + } + + GatheredUuids[assetUuid] = assetType; + try + { + if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) + { + RecordWearableAssetUuids(assetBase); + } + else if ((sbyte)AssetType.Gesture == assetType) + { + RecordGestureAssetUuids(assetBase); + } + else if ((sbyte)AssetType.Notecard == assetType) + { + RecordTextEmbeddedAssetUuids(assetBase); + } + else if ((sbyte)AssetType.LSLText == assetType) + { + RecordTextEmbeddedAssetUuids(assetBase); + } + else if ((sbyte)OpenSimAssetType.Material == assetType) + { + RecordMaterialAssetUuids(assetBase); + } + else if ((sbyte)AssetType.Object == assetType) + { + RecordSceneObjectAssetUuids(assetBase); } } - catch (Exception) + catch (Exception e) { - m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset id {0}", assetUuid); - throw; + m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset with id {0} type {1}: {2}", assetUuid, assetType, e.Message); + GatheredUuids.Remove(assetUuid); + ErrorCount++; + FailedUUIDs.Add(assetUuid); } - } + } private void AddForInspection(UUID assetUuid, sbyte assetType) { + if(assetUuid == UUID.Zero) + return; + // Here, we want to collect uuids which require further asset fetches but mark the others as gathered + if(FailedUUIDs.Contains(assetUuid)) + { + if(UncertainAssetsUUIDs.Contains(assetUuid)) + possibleNotAssetCount++; + else + ErrorCount++; + return; + } + if(GatheredUuids.ContainsKey(assetUuid)) + return; try - { - if ((sbyte)AssetType.Bodypart == assetType + { + if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType || (sbyte)AssetType.Gesture == assetType || (sbyte)AssetType.Notecard == assetType @@ -346,7 +424,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception) { m_log.ErrorFormat( - "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}", + "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}", assetUuid, assetType); throw; } @@ -457,8 +535,11 @@ namespace OpenSim.Region.Framework.Scenes foreach (Match uuidMatch in uuidMatches) { UUID uuid = new UUID(uuidMatch.Value); + if(uuid == UUID.Zero) + continue; // m_log.DebugFormat("[UUID GATHERER]: Recording {0} in text", uuid); - + if(!UncertainAssetsUUIDs.Contains(uuid)) + UncertainAssetsUUIDs.Add(uuid); AddForInspection(uuid); } } @@ -490,23 +571,18 @@ namespace OpenSim.Region.Framework.Scenes { string xml = Utils.BytesToString(sceneObjectAsset.Data); - if (String.IsNullOrEmpty(xml)) - m_log.ErrorFormat("[UUIDGatherer]: Asset {0} - {1} has a zero length XML blob!", sceneObjectAsset.Name, sceneObjectAsset.ID); + CoalescedSceneObjects coa; + if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) + { + foreach (SceneObjectGroup sog in coa.Objects) + AddForInspection(sog); + } else { - CoalescedSceneObjects coa; - if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) - { - foreach (SceneObjectGroup sog in coa.Objects) - AddForInspection(sog); - } - else - { - SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); + SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); - if (null != sog) - AddForInspection(sog); - } + if (null != sog) + AddForInspection(sog); } } @@ -554,7 +630,16 @@ namespace OpenSim.Region.Framework.Scenes /// private void RecordMaterialAssetUuids(AssetBase materialAsset) { - OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data); + OSDMap mat; + try + { + mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data); + } + catch (Exception e) + { + m_log.WarnFormat("[Materials]: cannot decode material asset {0}: {1}", materialAsset.ID, e.Message); + return; + } UUID normMap = mat["NormMap"].AsUUID(); if (normMap != UUID.Zero) -- cgit v1.1