From 263db441292956a8210a00c037848165667ab90e Mon Sep 17 00:00:00 2001 From: Magnuz Binder Date: Mon, 20 Apr 2015 21:30:06 +0200 Subject: Implement llGetBoundingBox fully. Signed-off-by: Michael Cerquoni --- .../Shared/Api/Implementation/LSL_Api.cs | 489 +++++++++++++++++++-- 1 file changed, 447 insertions(+), 42 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 40b7c35..5436888 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -28,6 +28,8 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; using System.Runtime.Remoting.Lifetime; using System.Text; using System.Threading; @@ -35,7 +37,9 @@ using System.Text.RegularExpressions; using Nini.Config; using log4net; using OpenMetaverse; +using OpenMetaverse.Assets; using OpenMetaverse.Packets; +using OpenMetaverse.Rendering; using OpenSim; using OpenSim.Framework; @@ -182,6 +186,38 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected bool m_restrictEmail = false; protected ISoundModule m_SoundModule = null; + protected float m_avatarHeightCorrection = 0.2f; + protected bool m_useSimpleBoxesInGetBoundingBox = false; + protected bool m_addStatsInGetBoundingBox = false; + + //LSL Avatar Bounding Box (lABB), lower (1) and upper (2), + //standing (Std), Groundsitting (Grs), Sitting (Sit), + //along X, Y and Z axes, constants (0) and coefficients (1) + protected float m_lABB1StdX0 = -0.275f; + protected float m_lABB2StdX0 = 0.275f; + protected float m_lABB1StdY0 = -0.35f; + protected float m_lABB2StdY0 = 0.35f; + protected float m_lABB1StdZ0 = -0.1f; + protected float m_lABB1StdZ1 = -0.5f; + protected float m_lABB2StdZ0 = 0.1f; + protected float m_lABB2StdZ1 = 0.5f; + protected float m_lABB1GrsX0 = -0.3875f; + protected float m_lABB2GrsX0 = 0.3875f; + protected float m_lABB1GrsY0 = -0.5f; + protected float m_lABB2GrsY0 = 0.5f; + protected float m_lABB1GrsZ0 = -0.05f; + protected float m_lABB1GrsZ1 = -0.375f; + protected float m_lABB2GrsZ0 = 0.5f; + protected float m_lABB2GrsZ1 = 0.0f; + protected float m_lABB1SitX0 = -0.5875f; + protected float m_lABB2SitX0 = 0.1875f; + protected float m_lABB1SitY0 = -0.35f; + protected float m_lABB2SitY0 = 0.35f; + protected float m_lABB1SitZ0 = -0.35f; + protected float m_lABB1SitZ1 = -0.375f; + protected float m_lABB2SitZ0 = -0.25f; + protected float m_lABB2SitZ1 = 0.25f; + //An array of HTTP/1.1 headers that are not allowed to be used //as custom headers by llHTTPRequest. private string[] HttpStandardHeaders = @@ -257,6 +293,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (lslConfig != null) { m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail); + m_avatarHeightCorrection = lslConfig.GetFloat("AvatarHeightCorrection", m_avatarHeightCorrection); + m_useSimpleBoxesInGetBoundingBox = lslConfig.GetBoolean("UseSimpleBoxesInGetBoundingBox", m_useSimpleBoxesInGetBoundingBox); + m_addStatsInGetBoundingBox = lslConfig.GetBoolean("AddStatsInGetBoundingBox", m_addStatsInGetBoundingBox); + m_lABB1StdX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingXconst", m_lABB1StdX0); + m_lABB2StdX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingXconst", m_lABB2StdX0); + m_lABB1StdY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingYconst", m_lABB1StdY0); + m_lABB2StdY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingYconst", m_lABB2StdY0); + m_lABB1StdZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZconst", m_lABB1StdZ0); + m_lABB1StdZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZcoeff", m_lABB1StdZ1); + m_lABB2StdZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZconst", m_lABB2StdZ0); + m_lABB2StdZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZcoeff", m_lABB2StdZ1); + m_lABB1GrsX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingXconst", m_lABB1GrsX0); + m_lABB2GrsX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingXconst", m_lABB2GrsX0); + m_lABB1GrsY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingYconst", m_lABB1GrsY0); + m_lABB2GrsY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingYconst", m_lABB2GrsY0); + m_lABB1GrsZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZconst", m_lABB1GrsZ0); + m_lABB1GrsZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZcoeff", m_lABB1GrsZ1); + m_lABB2GrsZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZconst", m_lABB2GrsZ0); + m_lABB2GrsZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZcoeff", m_lABB2GrsZ1); + m_lABB1SitX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingXconst", m_lABB1SitX0); + m_lABB2SitX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingXconst", m_lABB2SitX0); + m_lABB1SitY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingYconst", m_lABB1SitY0); + m_lABB2SitY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingYconst", m_lABB2SitY0); + m_lABB1SitZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZconst", m_lABB1SitZ0); + m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); + m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); + m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); } IConfig smtpConfig = seConfigSource.Configs["SMTP"]; @@ -9584,75 +9647,417 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// A partial implementation. + /// Full implementation of llGetBoundingBox according to SL 2015-04-15. + /// http://wiki.secondlife.com/wiki/LlGetBoundingBox /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox - /// So far only valid for standing/flying/ground sitting avatars and single prim objects. - /// If the object has multiple prims and/or a sitting avatar then the bounding - /// box is for the root prim only. + /// Returns local bounding box of avatar without attachments + /// if target is non-seated avatar or prim/mesh in avatar attachment. + /// Returns local bounding box of object including seated avatars + /// if target is seated avatar or prim/mesh in object. + /// Uses meshing of prims for high accuracy + /// or less accurate box models for speed. /// public LSL_List llGetBoundingBox(string obj) { m_host.AddScriptLPS(1); + + // Get target avatar if non-seated avatar or attachment, or prim and object UUID objID = UUID.Zero; + UUID.TryParse(obj, out objID); + ScenePresence agent = World.GetScenePresence(objID); + if (agent != null) + { + if (agent.ParentPart != null) + { + objID = agent.ParentPart.UUID; + agent = null; + } + } + SceneObjectGroup group = null; + SceneObjectPart target = World.GetSceneObjectPart(objID); + if (target != null) + { + group = target.ParentGroup; + if (group.IsAttachment) { + objID = group.AttachedAvatar; + agent = World.GetScenePresence(objID); + group = null; + target = null; + } + } + + // Initialize but break if no target LSL_List result = new LSL_List(); - if (!UUID.TryParse(obj, out objID)) + int groupCount = 0; + int partCount = 0; + int vertexCount = 0; + if (target == null && agent == null) { result.Add(new LSL_Vector()); result.Add(new LSL_Vector()); + if (m_addStatsInGetBoundingBox) + result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); return result; } - ScenePresence presence = World.GetScenePresence(objID); - if (presence != null) + Vector3 minPosition = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + Vector3 maxPosition = new Vector3(float.MinValue, float.MinValue, float.MinValue); + + // Try to get a mesher + IRendering primMesher = null; + List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); + if (renderers.Count > 0) + primMesher = RenderingLoader.LoadRenderer(renderers[0]); + + // Get bounding box of just avatar, seated or not + if (agent != null) + { + bool hasParent = false; + Vector3 lower; + Vector3 upper; + BoundingBoxOfScenePresence(agent, out lower, out upper); + Vector3 offset = Vector3.Zero; + + // Since local bounding box unrotated and untilted, keep it simple + AddBoundingBoxOfSimpleBox(lower, upper, offset, agent.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + partCount++; + groupCount++; + + // Return lower and upper bounding box corners + result.Add(new LSL_Vector(minPosition)); + result.Add(new LSL_Vector(maxPosition)); + if (m_addStatsInGetBoundingBox) + result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); + return result; + } + // Get bounding box of object including seated avatars + else if (group != null) { - if (presence.ParentID == 0) // not sat on an object + // Merge bounding boxes of all parts (prims and mesh) + foreach (SceneObjectPart part in group.Parts) { - LSL_Vector lower; - LSL_Vector upper; - if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID - == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) + bool hasParent = (!part.IsRoot); + // When requested or if no mesher, keep it simple + if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) { - // This is for ground sitting avatars - float height = presence.Appearance.AvatarHeight / 2.66666667f; - lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f); - upper = new LSL_Vector(0.3375f, 0.45f, 0.0f); + AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); } + // Do the full mounty else { - // This is for standing/flying avatars - float height = presence.Appearance.AvatarHeight / 2.0f; - lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f); - upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f); + Primitive omvPrim = part.Shape.ToOmvPrimitive(part.OffsetPosition, part.RotationOffset); + byte[] sculptAsset = null; + if (omvPrim.Sculpt != null) + sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); + + // When part is mesh + // Quirk: Only imports as incompletely populated faceted mesh object, so needs an own handler. + if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) + { + AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); + FacetedMesh mesh = null; + FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); + meshAsset = null; + if (mesh != null) + { + AddBoundingBoxOfFacetedMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + } + + // When part is sculpt + // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. + else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) + { + IJ2KDecoder imgDecoder = World.RequestModuleInterface(); + if (imgDecoder != null) + { + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if (sculpt != null) + { + SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); + sculpt.Dispose(); + if (mesh != null) + { + AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + } + } + } + + // When part is prim + else if (omvPrim.Sculpt == null) + { + SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); + if (mesh != null) + { + AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + } + + // When all else fails, try fallback to simple box + else + { + AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + } } - result.Add(lower); - result.Add(upper); - return result; + partCount++; } + } + + // Merge bounding boxes of seated avatars + foreach (ScenePresence sp in group.GetSittingAvatars()) + { + Vector3 lower; + Vector3 upper; + BoundingBoxOfScenePresence(sp, out lower, out upper); + Vector3 offset = sp.OffsetPosition; + + bool hasParent = true; + // When requested or if no mesher, keep it simple + if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) + { + AddBoundingBoxOfSimpleBox(lower, upper, offset, sp.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + } + // Do the full mounty else { - // sitting on an object so we need the bounding box of that - // which should include the avatar so set the UUID to the - // UUID of the object the avatar is sat on and allow it to fall through - // to processing an object - SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID); - objID = p.UUID; + // Prim shapes don't do center offsets, so add it here. + offset = offset + (lower + upper) * 0.5f * sp.Rotation; + Primitive omvPrim = MakeOpenMetaversePrim(upper - lower, offset, sp.Rotation, ScriptBaseClass.PRIM_TYPE_SPHERE); + SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); + AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); + mesh = null; + } + partCount++; + } + + groupCount++; + + // Return lower and upper bounding box corners + result.Add(new LSL_Vector(minPosition)); + result.Add(new LSL_Vector(maxPosition)); + if (m_addStatsInGetBoundingBox) + result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); + + primMesher = null; + return result; + } + + /// + /// Helper to calculate bounding box of an avatar. + /// + private void BoundingBoxOfScenePresence(ScenePresence sp, out Vector3 lower, out Vector3 upper) + { + // Adjust from OS model + // avatar height = visual height - 0.2, bounding box height = visual height + // to SL model + // avatar height = visual height, bounding box height = visual height + 0.2 + float height = sp.Appearance.AvatarHeight + m_avatarHeightCorrection; + + // According to avatar bounding box in SL 2015-04-18: + // standing = <-0.275,-0.35,-0.1-0.5*h> : <0.275,0.35,0.1+0.5*h> + // groundsitting = <-0.3875,-0.5,-0.05-0.375*h> : <0.3875,0.5,0.5> + // sitting = <-0.5875,-0.35,-0.35-0.375*h> : <0.1875,0.35,-0.25+0.25*h> + + // When avatar is sitting + if (sp.ParentPart != null) + { + lower = new Vector3(m_lABB1SitX0, m_lABB1SitY0, m_lABB1SitZ0 + m_lABB1SitZ1 * height); + upper = new Vector3(m_lABB2SitX0, m_lABB2SitY0, m_lABB2SitZ0 + m_lABB2SitZ1 * height); + } + // When avatar is groundsitting + else if (sp.Animator.Animations.ImplicitDefaultAnimation.AnimID == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) + { + lower = new Vector3(m_lABB1GrsX0, m_lABB1GrsY0, m_lABB1GrsZ0 + m_lABB1GrsZ1 * height); + upper = new Vector3(m_lABB2GrsX0, m_lABB2GrsY0, m_lABB2GrsZ0 + m_lABB2GrsZ1 * height); + } + // When avatar is standing or flying + else + { + lower = new Vector3(m_lABB1StdX0, m_lABB1StdY0, m_lABB1StdZ0 + m_lABB1StdZ1 * height); + upper = new Vector3(m_lABB2StdX0, m_lABB2StdY0, m_lABB2StdZ0 + m_lABB2StdZ1 * height); + } + } + + /// + /// Helper to approximate a part with a simple box. + /// + private void AddBoundingBoxOfSimpleBox(Vector3 corner1, Vector3 corner2, Vector3 offset, Quaternion rotation, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) + { + // Parse the 8 box corners + for (int i = 0; i < 8; i++) + { + // Calculate each box corner + Vector3 position = corner1; + if ((i & 1) != 0) + position.X = corner2.X; + if ((i & 2) != 0) + position.Y = corner2.Y; + if ((i & 4) != 0) + position.Z = corner2.Z; + // Rotate part unless part is root + if (hasParent) + position = position * rotation; + position = position + offset; + // Adjust lower and upper bounding box corners if needed + lower = Vector3.Min(lower, position); + upper = Vector3.Max(upper, position); + count++; + } + } + + /// + /// Helper to parse a meshed prim and needed especially + /// for accuracy with tortured prims and sculpts. + /// + private void AddBoundingBoxOfSimpleMesh(SimpleMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) + { + // Quirk: A meshed box contains 10 instead of the 8 necessary vertices. + if (mesh != null) + { + // Parse each vertex in mesh + foreach (Vertex vertex in mesh.Vertices) + { + Vector3 position = vertex.Position; + position = position * prim.Scale; + // Rotate part unless part is root + if (hasParent) + position = position * prim.Rotation; + position = position + prim.Position; + // Adjust lower and upper bounding box corners if needed + lower = Vector3.Min(lower, position); + upper = Vector3.Max(upper, position); + count++; } } - SceneObjectPart part = World.GetSceneObjectPart(objID); - // Currently only works for single prims without a sitting avatar - if (part != null) + } + + /// + /// Helper to parse mesh because no method exists + /// to parse mesh assets to SimpleMesh. + /// + private void AddBoundingBoxOfFacetedMesh(FacetedMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) + { + if (mesh != null) { - Vector3 halfSize = part.Scale / 2.0f; - LSL_Vector lower = (new LSL_Vector(halfSize)) * -1.0f; - LSL_Vector upper = new LSL_Vector(halfSize); - result.Add(lower); - result.Add(upper); - return result; + // Parse each face in mesh + // since vertex array isn't populated. + // This parses each unique vertex 3-6 times. + foreach (Face face in mesh.Faces) + { + // Parse each vertex in face + foreach (Vertex vertex in face.Vertices) + { + Vector3 position = vertex.Position; + position = position * prim.Scale; + // Rotate part unless part is root + if (hasParent) + position = position * prim.Rotation; + position = position + prim.Position; + // Adjust lower and upper bounding box corners if needed + lower = Vector3.Min(lower, position); + upper = Vector3.Max(upper, position); + count++; + } + } } + } - // Not found so return empty values - result.Add(new LSL_Vector()); - result.Add(new LSL_Vector()); - return result; + /// + /// Helper to make up an OpenMetaverse prim + /// needed to create mesh from parts. + /// + private Primitive MakeOpenMetaversePrim(Vector3 scale, Vector3 position, Quaternion rotation, int primType) + { + // Initialize and set common parameters + Primitive prim = new OpenMetaverse.Primitive(); + prim.Scale = scale; + prim.Position = position; + prim.Rotation = rotation; + prim.PrimData.PathShearX = 0.0f; + prim.PrimData.PathShearY = 0.0f; + prim.PrimData.PathBegin = 0.0f; + prim.PrimData.PathEnd = 1.0f; + prim.PrimData.PathScaleX = 1.0f; + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.PathTaperX = 0.0f; + prim.PrimData.PathTaperY = 0.0f; + prim.PrimData.PathTwistBegin = 0.0f; + prim.PrimData.PathTwist = 0.0f; + prim.PrimData.ProfileBegin = 0.0f; + prim.PrimData.ProfileEnd = 1.0f; + prim.PrimData.ProfileHollow = 0.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.ProfileHole = (HoleType)0; + prim.PrimData.PathCurve = (PathCurve)16; + prim.PrimData.PathRadiusOffset = 0.0f; + prim.PrimData.PathRevolutions = 1.0f; + prim.PrimData.PathSkew = 0.0f; + prim.PrimData.PCode = OpenMetaverse.PCode.Prim; + prim.PrimData.State = (byte)0; + + // Set type specific parameters + switch (primType) + { + // Set specific parameters for box + case ScriptBaseClass.PRIM_TYPE_BOX: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.PathCurve = (PathCurve)16; + break; + // Set specific parameters for cylinder + case ScriptBaseClass.PRIM_TYPE_CYLINDER: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)0; + prim.PrimData.PathCurve = (PathCurve)16; + break; + // Set specific parameters for prism + case ScriptBaseClass.PRIM_TYPE_PRISM: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)3; + prim.PrimData.PathCurve = (PathCurve)16; + break; + // Set specific parameters for sphere + case ScriptBaseClass.PRIM_TYPE_SPHERE: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)5; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for torus + case ScriptBaseClass.PRIM_TYPE_TORUS: + prim.PrimData.PathScaleY = 0.5f; + prim.PrimData.ProfileCurve = (ProfileCurve)0; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for tube + case ScriptBaseClass.PRIM_TYPE_TUBE: + prim.PrimData.PathScaleY = 0.5f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for ring + case ScriptBaseClass.PRIM_TYPE_RING: + prim.PrimData.PathScaleY = 0.5f; + prim.PrimData.ProfileCurve = (ProfileCurve)3; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Set specific parameters for sculpt + case ScriptBaseClass.PRIM_TYPE_SCULPT: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)5; + prim.PrimData.PathCurve = (PathCurve)32; + break; + // Default to specific parameters for box + default: + prim.PrimData.PathScaleY = 1.0f; + prim.PrimData.ProfileCurve = (ProfileCurve)1; + prim.PrimData.PathCurve = (PathCurve)16; + break; + } + + return prim; } public LSL_Vector llGetGeometricCenter() -- cgit v1.1 From f11720d71fee66b7dc902c3a6632e571824e2288 Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Mon, 20 Apr 2015 05:36:39 +0100 Subject: Enable grab feature (Ctrl+Drag) for non-physical link-sets and add code to handle spin (Ctrl+Shift+Drag) This patch fixes permission issues with dragging scripted objects. As on LL grid, scripted prims can not be dragged now. Also after dragging, the group was not marked as updated. This meant that after the region was restarted the group would revert to its original position. Signed-off-by: Michael Cerquoni --- .../Region/Framework/Scenes/SceneObjectGroup.cs | 30 +++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 0a1a226..75da299 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2672,20 +2672,26 @@ namespace OpenSim.Region.Framework.Scenes } else { - //NonPhysicalGrabMovement(pos); + NonPhysicalGrabMovement(pos); } } else { - //NonPhysicalGrabMovement(pos); + NonPhysicalGrabMovement(pos); } } } + /// + /// Apply possition for grabbing non-physical linksets (ctrl+drag) + /// + /// New Position public void NonPhysicalGrabMovement(Vector3 pos) { - AbsolutePosition = pos; - m_rootPart.SendTerseUpdateToAllClients(); + if((m_rootPart.Flags & PrimFlags.Scripted) == 0) + { + UpdateGroupPosition(pos); + } } /// @@ -2781,17 +2787,29 @@ namespace OpenSim.Region.Framework.Scenes } else { - //NonPhysicalSpinMovement(pos); + NonPhysicalSpinMovement(newOrientation); } } else { - //NonPhysicalSpinMovement(pos); + NonPhysicalSpinMovement(newOrientation); } } } /// + /// Apply rotation for spinning non-physical linksets (ctrl+shift+drag) + /// + /// New Rotation + private void NonPhysicalSpinMovement(Quaternion newOrientation) + { + if ((m_rootPart.Flags & PrimFlags.Scripted) == 0) + { + UpdateGroupRotationR(newOrientation); + } + } + + /// /// Set the name of a prim /// /// -- cgit v1.1 From e855c8e7118823808f6af89f878f81858fbf35c6 Mon Sep 17 00:00:00 2001 From: Magnuz Binder Date: Fri, 20 Mar 2015 19:12:43 +0100 Subject: Allow setting profilecut diff to 0.02 from scripts just like from viewer. Signed-off-by: Michael Cerquoni --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 5436888..e20e4c4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7788,13 +7788,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { profilecut.y = 1f; } - if (profilecut.y - profilecut.x < 0.05f) + if (profilecut.y - profilecut.x < 0.02f) { - profilecut.x = profilecut.y - 0.05f; + profilecut.x = profilecut.y - 0.02f; if (profilecut.x < 0.0f) { profilecut.x = 0.0f; - profilecut.y = 0.05f; + profilecut.y = 0.02f; } } shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x); -- cgit v1.1 From cde4e7ec865b1e6c933fad0f6b14e6df55123f0c Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Sat, 25 Apr 2015 05:39:20 +0100 Subject: Fix the click to buy prim dialog not being displayed with alpha viewers after recent changes to viewer code by LL. Recent viewer changes by linden lab now require more information when requesting prim tooltip data. The object properties must now be sent when the viewer requests the object family properties used to display the tool tip. Thanks to Liru for finding the viewer commit that broke this feature in OS. Signed-off-by: BlueWall --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 311dd31..855342f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4465,7 +4465,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,true)); } private void ResendPropertyUpdate(ObjectPropertyUpdate update) -- cgit v1.1 From d80230adcdd26a7f512355df256cc5c9c5e3d0e6 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Mon, 27 Apr 2015 15:46:09 -0500 Subject: Revert "Fix the click to buy prim dialog not being displayed with alpha viewers after recent changes to viewer code by LL." See: http://opensimulator.org/mantis/view.php?id=7426#c28089 Reverting this commit due to unwanted effects. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 855342f..311dd31 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4465,7 +4465,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,true)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); } private void ResendPropertyUpdate(ObjectPropertyUpdate update) -- cgit v1.1 From 38459104eb7d3484d17bc764c500fb9f4026c49a Mon Sep 17 00:00:00 2001 From: BlueWall Date: Tue, 28 Apr 2015 09:36:56 -0500 Subject: Revert "Revert "Fix the click to buy prim dialog not being displayed with alpha viewers after recent changes to viewer code by LL."" This brings back the fix for recent viewer click to buy prim dialog which was reverted after some reports of objects being altered when touched. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 311dd31..855342f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4465,7 +4465,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,true)); } private void ResendPropertyUpdate(ObjectPropertyUpdate update) -- cgit v1.1 From e171ae899d3b78072f368de357dadeeae8808f8d Mon Sep 17 00:00:00 2001 From: BlueWall Date: Tue, 28 Apr 2015 17:24:54 -0500 Subject: Revert "Enable grab feature (Ctrl+Drag) for non-physical link-sets and add code to handle spin (Ctrl+Shift+Drag)" We found that linksets can move if the root prim is unscripted. Will revert this until a fix can be implemented. --- .../Region/Framework/Scenes/SceneObjectGroup.cs | 30 +++++----------------- 1 file changed, 6 insertions(+), 24 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 75da299..0a1a226 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2672,26 +2672,20 @@ namespace OpenSim.Region.Framework.Scenes } else { - NonPhysicalGrabMovement(pos); + //NonPhysicalGrabMovement(pos); } } else { - NonPhysicalGrabMovement(pos); + //NonPhysicalGrabMovement(pos); } } } - /// - /// Apply possition for grabbing non-physical linksets (ctrl+drag) - /// - /// New Position public void NonPhysicalGrabMovement(Vector3 pos) { - if((m_rootPart.Flags & PrimFlags.Scripted) == 0) - { - UpdateGroupPosition(pos); - } + AbsolutePosition = pos; + m_rootPart.SendTerseUpdateToAllClients(); } /// @@ -2787,29 +2781,17 @@ namespace OpenSim.Region.Framework.Scenes } else { - NonPhysicalSpinMovement(newOrientation); + //NonPhysicalSpinMovement(pos); } } else { - NonPhysicalSpinMovement(newOrientation); + //NonPhysicalSpinMovement(pos); } } } /// - /// Apply rotation for spinning non-physical linksets (ctrl+shift+drag) - /// - /// New Rotation - private void NonPhysicalSpinMovement(Quaternion newOrientation) - { - if ((m_rootPart.Flags & PrimFlags.Scripted) == 0) - { - UpdateGroupRotationR(newOrientation); - } - } - - /// /// Set the name of a prim /// /// -- cgit v1.1 From 59778cfc2abc807792b64e9392ad3009aaf07ecb Mon Sep 17 00:00:00 2001 From: Steven Zielinski Date: Tue, 21 Apr 2015 15:33:54 -0400 Subject: Added in all metrics for Phase 1 except for Time Dilation. Test Plan: Tested on local opensim and firestorm. Not tested with JSON stats reporter. Reviewers: rlouden Reviewed By: rlouden Differential Revision: http://cr.irl.ucf.edu/D269 Signed-off-by: Diva Canto --- OpenSim/Region/Framework/Scenes/Scene.cs | 104 ++++++++++++++++- .../Region/Framework/Scenes/SimStatsReporter.cs | 123 +++++++++++++++++++-- 2 files changed, 218 insertions(+), 9 deletions(-) mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/Scene.cs mode change 100644 => 100755 OpenSim/Region/Framework/Scenes/SimStatsReporter.cs (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs old mode 100644 new mode 100755 index 4715558..906c862 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1107,7 +1107,27 @@ namespace OpenSim.Region.Framework.Scenes #endregion Interest Management - StatsReporter = new SimStatsReporter(this); + // Acquire the statistics section of the OpenSim.ini file located + // in the bin directory + IConfig statisticsConfig = m_config.Configs["Statistics"]; + + // 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", 10)); + } + else + { + // Create a StatsReporter with the current scene and a default + // 10 frames stored for the frame time statistics + StatsReporter = new SimStatsReporter(this); + } + StatsReporter.OnSendStatsResult += SendSimStatsPackets; StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats; @@ -1607,6 +1627,21 @@ namespace OpenSim.Region.Framework.Scenes 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(); + while (!m_shuttingDown && ((endFrame == null && Active) || Frame < endFrame)) { ++Frame; @@ -1622,25 +1657,62 @@ namespace OpenSim.Region.Framework.Scenes // Apply taints in terrain module to terrain in physics scene 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); } 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); // 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(); + + // Get the simulation frame time that the avatar force input + // took + simFrameStopwatch.Stop(); + preciseSimFrameTime += + simFrameStopwatch.Elapsed.TotalMilliseconds; agentMS = Util.EnvironmentTickCountSubtract(tmpMS); // 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) @@ -1649,8 +1721,16 @@ namespace OpenSim.Region.Framework.Scenes 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(); // Check if any objects have reached their targets @@ -1738,6 +1818,11 @@ namespace OpenSim.Region.Framework.Scenes EventManager.TriggerRegionHeartbeatEnd(this); otherMS = eventMS + backupMS + terrainMS + landMS; + // Get the elapsed time for the simulation frame + simFrameStopwatch.Stop(); + preciseSimFrameTime += + simFrameStopwatch.Elapsed.TotalMilliseconds; + if (!UpdateOnTimer) { Watchdog.UpdateThread(); @@ -1754,6 +1839,14 @@ namespace OpenSim.Region.Framework.Scenes spareMS = Math.Max(0, MinFrameTicks - physicsMS2 - agentMS - physicsMS - otherMS); } + // Get the total frame time + totalFrameStopwatch.Stop(); + preciseTotalFrameTime = + totalFrameStopwatch.Elapsed.TotalMilliseconds; + + // 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(); @@ -1771,6 +1864,15 @@ namespace OpenSim.Region.Framework.Scenes StatsReporter.AddSpareMS(spareMS); StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); + // 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. if (DebugUpdates && Util.EnvironmentTickCountSubtract( diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs old mode 100644 new mode 100755 index 8f1e345..6182bcd --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs @@ -213,6 +213,27 @@ namespace OpenSim.Region.Framework.Scenes 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 = 10; + + // 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; + private Scene m_scene; private RegionInfo ReportingRegion; @@ -223,6 +244,13 @@ namespace OpenSim.Region.Framework.Scenes public SimStatsReporter(Scene scene) { + // 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]; + m_scene = scene; m_reportedFpsCorrectionFactor = scene.MinFrameSeconds * m_nominalReportedFps; m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); @@ -256,6 +284,13 @@ namespace OpenSim.Region.Framework.Scenes StatsManager.RegisterStat(SlowFramesStat); } + public SimStatsReporter(Scene scene, int numberOfFrames) : this (scene) + { + // Store the number of frames from the OpenSim.ini configuration + // file + m_numberFramesStored = numberOfFrames; + } + public void Close() { m_report.Elapsed -= TriggerStatsHeartbeat; @@ -289,6 +324,11 @@ namespace OpenSim.Region.Framework.Scenes private void statsHeartBeat(object sender, EventArgs e) { + double totalSumFrameTime; + double simulationSumFrameTime; + double physicsSumFrameTime; + double networkSumFrameTime; + if (!m_scene.Active) return; @@ -314,14 +354,21 @@ namespace OpenSim.Region.Framework.Scenes #region various statistic googly moogly + // ORIGINAL code commented out until we have time to add our own + // statistics to the statistics window, this will be done as a + // new section given the title of our current project // We're going to lie about the FPS because we've been lying since 2008. The actual FPS is currently // locked at a maximum of 11. Maybe at some point this can change so that we're not lying. - int reportedFPS = (int)(m_fps * m_reportedFpsCorrectionFactor); - + //int reportedFPS = (int)(m_fps * m_reportedFpsCorrectionFactor); + int reportedFPS = m_fps; + // save the reported value so there is something available for llGetRegionFPS lastReportedSimFPS = reportedFPS / m_statsUpdateFactor; - float physfps = ((m_pfps / 1000)); + // 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; //if (physfps > 600) //physfps = physfps - (physfps - 600); @@ -364,6 +411,26 @@ namespace OpenSim.Region.Framework.Scenes 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++) + { + // 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[0].StatID = (uint) Stats.TimeDilation; sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor)); @@ -388,21 +455,31 @@ 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 = m_frameMS / framesUpdated; + sb[8].StatValue = (float) totalSumFrameTime / + m_numberFramesStored; sb[9].StatID = (uint)Stats.NetMS; - sb[9].StatValue = m_netMS / framesUpdated; + //sb[9].StatValue = m_netMS / framesUpdated; + sb[9].StatValue = (float) networkSumFrameTime / + m_numberFramesStored; sb[10].StatID = (uint)Stats.PhysicsMS; - sb[10].StatValue = m_physicsMS / framesUpdated; + //sb[10].StatValue = m_physicsMS / framesUpdated; + sb[10].StatValue = (float) physicsSumFrameTime / + m_numberFramesStored; sb[11].StatID = (uint)Stats.ImageMS ; sb[11].StatValue = m_imageMS / framesUpdated; sb[12].StatID = (uint)Stats.OtherMS; - sb[12].StatValue = m_otherMS / framesUpdated; - + //sb[12].StatValue = m_otherMS / framesUpdated; + sb[12].StatValue = (float) simulationSumFrameTime / + m_numberFramesStored; + sb[13].StatID = (uint)Stats.InPacketsPerSecond; sb[13].StatValue = (m_inPacketsPerSecond / m_statsUpdateFactor); @@ -475,6 +552,10 @@ namespace OpenSim.Region.Framework.Scenes 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; @@ -605,6 +686,32 @@ namespace OpenSim.Region.Framework.Scenes m_otherMS += 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; -- cgit v1.1 From da32512ea449c2de2d4a6069f899fbd4a8bb03fa Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 29 Apr 2015 18:47:17 -0700 Subject: Updated all occurrences of AssemblyVersion("0.8.1.*") to AssemblyVersion("0.8.2.*") --- OpenSim/Region/Application/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/Framework/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs | 2 +- .../Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/Physics/Manager/AssemblyInfo.cs | 2 +- OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs | 2 +- OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs | 2 +- OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs | 2 +- .../ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs | 2 +- OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Application/Properties/AssemblyInfo.cs b/OpenSim/Region/Application/Properties/AssemblyInfo.cs index 650425b..8652312 100644 --- a/OpenSim/Region/Application/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Application/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using Mono.Addins; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] [assembly: AddinRoot("OpenSim", OpenSim.VersionInfo.VersionNumber)] [assembly: ImportAddinAssembly("OpenSim.Framework.dll")] diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs index 3bc0be8..264eaa3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs index 8ce1b85..8795c0c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs index 1b1b319..64532df 100644 --- a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using Mono.Addins; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] [assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs index 637387a..e60d3ae 100644 --- a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs index fd9ab3d..97dea1f 100644 --- a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs @@ -31,6 +31,6 @@ using Mono.Addins; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] [assembly: AddinRoot("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs index d028374..f8ad958 100644 --- a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using Mono.Addins; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] [assembly: Addin("OpenSim.Region.OptionalModules", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs index eba0675..7d054dd 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs @@ -55,4 +55,4 @@ using System.Runtime.InteropServices; // You can specify all values by your own or you can build default build and revision // numbers with the '*' character (the default): -[assembly : AssemblyVersion("0.8.1.*")] +[assembly : AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs index 4de5b47..4f90eee 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs index 1486ba8..c5867b2 100644 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs index 202ef20..33f60e4 100644 --- a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs @@ -55,4 +55,4 @@ using System.Runtime.InteropServices; // You can specify all values by your own or you can build default build and revision // numbers with the '*' character (the default): -[assembly : AssemblyVersion("0.8.1.*")] +[assembly : AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs index 2b083fe..ec968c0 100644 --- a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs index b95f7f4..076da78 100644 --- a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs @@ -55,4 +55,4 @@ using System.Runtime.InteropServices; // You can specify all values by your own or you can build default build and revision // numbers with the '*' character (the default): -[assembly : AssemblyVersion("0.8.1.*")] +[assembly : AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs index 125d38a..fc1ffba 100644 --- a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs @@ -55,4 +55,4 @@ using System.Runtime.InteropServices; // You can specify all values by your own or you can build default build and revision // numbers with the '*' character (the default): -[assembly : AssemblyVersion("0.8.1.*")] +[assembly : AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs index e8b29f9..11b89d2 100644 --- a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using Mono.Addins; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] [assembly: Addin("OpenSim.RegionModules.RegionCombinerModule", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs index d02c91c..4708473 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs index 31acd44..4df09ef 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs index af7ee26..3eaaed0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] diff --git a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs index 03612ef..0094af6 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs @@ -30,7 +30,7 @@ using Mono.Addins; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] [assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] diff --git a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs index 58fa66f..9fac53e 100644 --- a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("0.8.1.*")] +[assembly: AssemblyVersion("0.8.2.*")] -- cgit v1.1 From 877371411a9e997b0b11f45c410438ae2bb73f16 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 2 May 2015 22:18:58 -0700 Subject: Mantis #7514 I think this is it -- a bug introduced back in October, where the prefix and name space were being added twice on HG asset posts bu simulators. --- OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index 75f0774..c2010b1 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs @@ -205,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { case XmlNodeType.Attribute: // Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name); - writer.WriteAttributeString(reader.Prefix, reader.Name, reader.NamespaceURI, reader.Value); + writer.WriteAttributeString(reader.Name, reader.Value); break; case XmlNodeType.CDATA: @@ -228,7 +228,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) - writer.WriteAttributeString(reader.Prefix, reader.Name, reader.NamespaceURI, reader.Value); + writer.WriteAttributeString(reader.Name, reader.Value); reader.MoveToElement(); } -- cgit v1.1 From 60e719286bc82cf9353e508af14fe3252eeddc45 Mon Sep 17 00:00:00 2001 From: dahlia Date: Sun, 3 May 2015 17:05:48 -0700 Subject: Make Meshmerizer mesh cache static so it can be shared across class instances --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index d96de4a..24983ab 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -84,7 +84,8 @@ namespace OpenSim.Region.Physics.Meshing private List> mConvexHulls = null; private List mBoundingHull = null; - private Dictionary m_uniqueMeshes = new Dictionary(); + // Mesh cache. Static so it can be shared across instances of this class + private static Dictionary m_uniqueMeshes = new Dictionary(); public Meshmerizer(IConfigSource config) { -- cgit v1.1 From 73efb1633f61d9ad01ee58ae3e2704283a57ed52 Mon Sep 17 00:00:00 2001 From: dahlia Date: Sun, 3 May 2015 19:54:03 -0700 Subject: lock collision mesh cache when accessing --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 24983ab..42231b5 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -928,8 +928,11 @@ namespace OpenSim.Region.Physics.Meshing if (shouldCache) { key = primShape.GetMeshKey(size, lod); - if (m_uniqueMeshes.TryGetValue(key, out mesh)) - return mesh; + lock (m_uniqueMeshes) + { + if (m_uniqueMeshes.TryGetValue(key, out mesh)) + return mesh; + } } if (size.X < 0.01f) size.X = 0.01f; @@ -955,7 +958,10 @@ namespace OpenSim.Region.Physics.Meshing if (shouldCache) { - m_uniqueMeshes.Add(key, mesh); + lock (m_uniqueMeshes) + { + m_uniqueMeshes.Add(key, mesh); + } } } -- cgit v1.1 From 30f9e5372e7b999ace8334825237a3512c9e40fb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 3 May 2015 21:56:41 -0700 Subject: Only send parcel layer data around the point of interest. Can be disabled by setting [LandManagement]LimitParcelLayerUpdateDistance=false New parameters added to OpenSimDefaults for the distance and enablement. --- .../CoreModules/World/Land/LandManagementModule.cs | 84 ++++++++++++++++++++-- 1 file changed, 79 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 13485bf..25e1454 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -98,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land // caches ExtendedLandData private Cache parcelInfoCache; + /// /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. /// private Dictionary forcedPosition = new Dictionary(); + // Enables limiting parcel layer info transmission when doing simple updates + private bool shouldLimitParcelLayerInfoToViewDistance { get; set; } + // "View distance" for sending parcel layer info if asked for from a view point in the region + private int parcelLayerViewDistance { get; set; } + #region INonSharedRegionModule Members public Type ReplaceableInterface @@ -112,6 +118,14 @@ namespace OpenSim.Region.CoreModules.World.Land public void Initialise(IConfigSource source) { + shouldLimitParcelLayerInfoToViewDistance = true; + parcelLayerViewDistance = 128; + IConfig landManagementConfig = source.Configs["LandManagement"]; + if (landManagementConfig != null) + { + shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance); + parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance); + } } public void AddRegion(Scene scene) @@ -1129,11 +1143,26 @@ namespace OpenSim.Region.CoreModules.World.Land #region Parcel Updating + // Send parcel layer info for the whole region + public void SendParcelOverlay(IClientAPI remote_client) + { + SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize); + } + /// - /// Where we send the ParcelOverlay packet to the client + /// Send the parcel overlay blocks to the client. We send the overlay packets + /// around a location and limited by the 'parcelLayerViewDistance'. This number + /// is usually 128 and the code is arranged so it sends all the parcel overlay + /// information for a whole region if the region is legacy sized (256x256). If + /// the region is larger, only the parcel layer information is sent around + /// the point specified. This reduces the problem of parcel layer information + /// blocks increasing exponentially as region size increases. /// /// The object representing the client - public void SendParcelOverlay(IClientAPI remote_client) + /// X position in the region to send surrounding parcel layer info + /// y position in the region to send surrounding parcel layer info + /// Distance from x,y position to send parcel layer info + private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance) { const int LAND_BLOCKS_PER_PACKET = 1024; @@ -1141,15 +1170,58 @@ namespace OpenSim.Region.CoreModules.World.Land int byteArrayCount = 0; int sequenceID = 0; + int xLow = 0; + int xHigh = (int)m_scene.RegionInfo.RegionSizeX; + int yLow = 0; + int yHigh = (int)m_scene.RegionInfo.RegionSizeY; + + if (shouldLimitParcelLayerInfoToViewDistance) + { + // Compute view distance around the given point + int txLow = xPlace - layerViewDistance; + int txHigh = xPlace + layerViewDistance; + // If the distance is outside the region area, move the view distance to ba all in the region + if (txLow < xLow) + { + txLow = xLow; + txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh); + } + if (txHigh > xHigh) + { + txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2)); + txHigh = xHigh; + } + xLow = txLow; + xHigh = txHigh; + + int tyLow = yPlace - layerViewDistance; + int tyHigh = yPlace + layerViewDistance; + if (tyLow < yLow) + { + tyLow = yLow; + tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh); + } + if (tyHigh > yHigh) + { + tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2)); + tyHigh = yHigh; + } + yLow = tyLow; + yHigh = tyHigh; + } + // m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>", + // LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh); + // Layer data is in landUnit (4m) chunks - for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) + for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) { - for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) + for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) { byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client); byteArrayCount++; if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) { + // m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length); remote_client.SendLandParcelOverlay(byteArray, sequenceID); byteArrayCount = 0; sequenceID++; @@ -1162,6 +1234,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (byteArrayCount != 0) { remote_client.SendLandParcelOverlay(byteArray, sequenceID); + // m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length); } } @@ -1265,7 +1338,8 @@ namespace OpenSim.Region.CoreModules.World.Land temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); } - SendParcelOverlay(remote_client); + // Also send the layer data around the point of interest + SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance); } public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) -- cgit v1.1 From 43b8bd0c35c1d7ca0c97a4e64fe255943148d333 Mon Sep 17 00:00:00 2001 From: Magnuz Binder Date: Sun, 3 May 2015 07:50:13 +0200 Subject: Implement llCastRay fully, simplified. --- .../Shared/Api/Implementation/LSL_Api.cs | 760 ++++++++++++++++++++- 1 file changed, 759 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index e20e4c4..cf1bd2b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -218,6 +218,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected float m_lABB2SitZ0 = -0.25f; protected float m_lABB2SitZ1 = 0.25f; + protected float m_primSafetyCoeffX = 2.414214f; + protected float m_primSafetyCoeffY = 2.414214f; + protected float m_primSafetyCoeffZ = 1.618034f; + protected float m_floatToleranceInCastRay = 0.000001f; + protected float m_floatTolerance2InCastRay = 0.0001f; + protected int m_maxHitsInCastRay = 16; + protected int m_maxHitsPerPrimInCastRay = 16; + protected int m_maxHitsPerObjectInCastRay = 16; + protected bool m_detectExitsInCastRay = false; + protected bool m_filterPartsInCastRay = false; + protected bool m_doAttachmentsInCastRay = false; + protected bool m_useCastRayV1 = true; + //An array of HTTP/1.1 headers that are not allowed to be used //as custom headers by llHTTPRequest. private string[] HttpStandardHeaders = @@ -320,6 +333,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); + m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); + m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); + m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); + m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); + m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); + m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); + m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); + m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); + m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); + m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); + m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); + m_useCastRayV1 = lslConfig.GetBoolean("UseLlCastRayV1", m_useCastRayV1); } IConfig smtpConfig = seConfigSource.Configs["SMTP"]; @@ -13738,7 +13763,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return contacts[0]; } - public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + public LSL_List llCastRayV1(LSL_Vector start, LSL_Vector end, LSL_List options) { LSL_List list = new LSL_List(); @@ -13929,6 +13954,739 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return list; } + /// + /// Full implementation of llCastRay similar to SL 2015-04-21. + /// http://wiki.secondlife.com/wiki/LlCastRay + /// Uses pure geometry, bounding shapes, meshing and no physics + /// for prims, sculpts, meshes, avatars and terrain. + /// Implements all flags, reject types and data flags. + /// Can handle both objects/groups and prims/parts, by config. + /// May give poor results with multi-part meshes where "root" + /// part doesn't dominate, owing to "guessed" bounding boxes. + /// May sometimes be inaccurate owing to calculation precision + /// and a bug in libopenmetaverse PrimMesher. + /// + public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + { + // Use llCastRay v1 if configured + if (m_useCastRayV1) + return llCastRayV1(start, end, options); + + // Initialize + m_host.AddScriptLPS(1); + List rayHits = new List(); + LSL_List result = new LSL_List(); + float tol = m_floatToleranceInCastRay; + float tol2 = m_floatTolerance2InCastRay; + + // Get input options + int rejectTypes = 0; + int dataFlags = 0; + int maxHits = 1; + bool detectPhantom = false; + for (int i = 0; i < options.Length; i += 2) + { + if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) + rejectTypes = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) + dataFlags = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) + maxHits = options.GetLSLIntegerItem(i + 1); + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) + detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0); + } + if (maxHits > m_maxHitsInCastRay) + maxHits = m_maxHitsInCastRay; + bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0); + bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0); + bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0); + bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0); + bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0); + bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0); + bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); + + // Calculate some basic parameters + Vector3 ray = end - start; + float rayLength = ray.Length(); + + // Try to get a mesher and return failure if none or degenerate ray + IRendering primMesher = null; + List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); + if (renderers.Count < 1 || rayLength < tol) + { + result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); + return result; + } + primMesher = RenderingLoader.LoadRenderer(renderers[0]); + + // Used to translate and rotate world so ray is along negative Z axis from origo and + // calculations mostly simplified to a 2D projecttion on the X-Y plane + Vector3 posProj = new Vector3(-start); + Quaternion rotProj = Vector3.RotationBetween(ray, new Vector3(0.0f, 0.0f, -1.0f)); + Quaternion rotBack = Quaternion.Inverse(rotProj); + + // Iterate over all objects/groups and prims/parts in region + World.ForEachSOG( + delegate(SceneObjectGroup group) + { + // Check group filters unless part filters are configured + bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); + bool isNonphysical = !isPhysical; + bool isPhantom = group.IsPhantom || group.IsVolumeDetect; + bool isAttachment = group.IsAttachment; + bool doGroup = true; + if (isPhysical && rejectPhysical) + doGroup = false; + if (isNonphysical && rejectNonphysical) + doGroup = false; + if (isPhantom && detectPhantom) + doGroup = true; + if (m_filterPartsInCastRay) + doGroup = true; + if (isAttachment && !m_doAttachmentsInCastRay) + doGroup = false; + // Parse object/group if passed filters + if (doGroup) + { + // Iterate over all prims/parts in object/group + foreach(SceneObjectPart part in group.Parts) + { + // Check part filters if configured + if (m_filterPartsInCastRay) + { + isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); + isNonphysical = !isPhysical; + isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive); + bool doPart = true; + if (isPhysical && rejectPhysical) + doPart = false; + if (isNonphysical && rejectNonphysical) + doPart = false; + if (isPhantom && detectPhantom) + doPart = true; + if (!doPart) + continue; + } + // Parse prim/part if passed filters + + // Estimate bounding box from size box + Vector3 scaleSafe = part.Scale; + if (!part.Shape.SculptEntry) + scaleSafe = scaleSafe * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); + + // Filter parts by bounding shapes + Vector3 posPartRel = part.GetWorldPosition() + posProj; + Vector3 posPartProj = posPartRel * rotProj; + if (InBoundingShapes(ray, rayLength, scaleSafe, posPartRel, posPartProj, rotProj)) + { + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = part.UUID; + rayTrans.GroupId = part.ParentGroup.UUID; + rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; + rayTrans.Scale = part.Scale; + rayTrans.PositionPartProj = posPartProj; + rayTrans.PositionProj = posProj; + rayTrans.RotationPartProj = rotProj * part.GetWorldRotation(); + rayTrans.RotationBack = rotBack; + rayTrans.NeedsEnds = true; + rayTrans.RayLength = rayLength; + rayTrans.Tolerance = tol; + rayTrans.Tolerance2 = tol2; + + // Make an OMV prim to be able to mesh part + Primitive omvPrim = part.Shape.ToOmvPrimitive(posPartProj, rayTrans.RotationPartProj); + byte[] sculptAsset = null; + if (omvPrim.Sculpt != null) + sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); + + // When part is mesh, get and check mesh + if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) + { + AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); + FacetedMesh mesh = null; + FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); + meshAsset = null; + AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); + mesh = null; + } + + // When part is sculpt, create and check mesh + // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. + else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) + { + IJ2KDecoder imgDecoder = World.RequestModuleInterface(); + if (imgDecoder != null) + { + Image sculpt = imgDecoder.DecodeToImage(sculptAsset); + if (sculpt != null) + { + SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); + sculpt.Dispose(); + AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); + mesh = null; + } + } + } + + // When part is prim, create and check mesh + else if (omvPrim.Sculpt == null) + { + if ( + omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && + omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && + omvPrim.PrimData.PathSkew == 0.0 && + omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 + ) + rayTrans.NeedsEnds = false; + SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); + AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); + mesh = null; + } + + } + } + } + } + ); + + // Check avatar filter + if (!rejectAgents) + { + // Iterate over all avatars in region + World.ForEachRootScenePresence( + delegate (ScenePresence sp) + { + // Parse avatar + + // Get bounding box + Vector3 lower; + Vector3 upper; + BoundingBoxOfScenePresence(sp, out lower, out upper); + Vector3 scale = upper - lower; + + // Filter avatars by bounding shapes + Vector3 posPartRel = sp.AbsolutePosition + posProj + (lower + upper) * 0.5f * sp.Rotation; + Vector3 posPartProj = posPartRel * rotProj; + if (InBoundingShapes(ray, rayLength, scale, posPartRel, posPartProj, rotProj)) + { + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = sp.UUID; + rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; + rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; + rayTrans.Scale = scale; + rayTrans.PositionPartProj = posPartProj; + rayTrans.PositionProj = posProj; + rayTrans.RotationPartProj = rotProj * sp.Rotation; + rayTrans.RotationBack = rotBack; + rayTrans.NeedsEnds = false; + rayTrans.RayLength = rayLength; + rayTrans.Tolerance = tol; + rayTrans.Tolerance2 = tol2; + + // Make OMV prim, create and check mesh + Primitive omvPrim = MakeOpenMetaversePrim(scale, posPartProj, rayTrans.RotationPartProj, ScriptBaseClass.PRIM_TYPE_SPHERE); + SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); + AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); + mesh = null; + } + } + ); + } + + // Check terrain filter + if (!rejectLand) + { + // Parse terrain + + // Mesh terrain and check projected bounding box + Vector3 posPartProj = posProj * rotProj; + Quaternion rotPartProj = rotProj; + Vector3 lower; + Vector3 upper; + List triangles = TrisFromHeightmapUnderRay(start, end, out lower, out upper); + Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); + int dummy = 0; + AddBoundingBoxOfSimpleBox(lower, upper, posPartProj, rotPartProj, true, ref lowerBox, ref upperBox, ref dummy); + if (lowerBox.X <= tol && lowerBox.Y <= tol && lowerBox.Z <= tol && upperBox.X >= -tol && upperBox.Y >= -tol && upperBox.Z >= -rayLength - tol) + { + // Prepare data needed to check for ray hits + RayTrans rayTrans = new RayTrans(); + rayTrans.PartId = UUID.Zero; + rayTrans.GroupId = UUID.Zero; + rayTrans.Link = 0; + rayTrans.Scale = new Vector3 (1.0f, 1.0f, 1.0f); + rayTrans.PositionPartProj = posPartProj; + rayTrans.PositionProj = posProj; + rayTrans.RotationPartProj = rotPartProj; + rayTrans.RotationBack = rotBack; + rayTrans.NeedsEnds = true; + rayTrans.RayLength = rayLength; + rayTrans.Tolerance = tol; + rayTrans.Tolerance2 = tol2; + + // Check mesh + AddRayInTris(triangles, rayTrans, ref rayHits); + triangles = null; + } + } + + // Sort hits by ascending distance + rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance)); + + // Check excess hits per part and group + for (int t = 0; t < 2; t++) + { + int maxHitsPerType = 0; + UUID id = UUID.Zero; + if (t == 0) + maxHitsPerType = m_maxHitsPerPrimInCastRay; + else + maxHitsPerType = m_maxHitsPerObjectInCastRay; + + // Handle excess hits only when needed + if (maxHitsPerType < m_maxHitsInCastRay) + { + // Find excess hits + Hashtable hits = new Hashtable(); + for (int i = rayHits.Count - 1; i >= 0; i--) + { + if (t == 0) + id = rayHits[i].PartId; + else + id = rayHits[i].GroupId; + if (hits.ContainsKey(id)) + hits[id] = (int)hits[id] + 1; + else + hits[id] = 1; + } + + // Remove excess hits + for (int i = rayHits.Count - 1; i >= 0; i--) + { + if (t == 0) + id = rayHits[i].PartId; + else + id = rayHits[i].GroupId; + int hit = (int)hits[id]; + if (hit > m_maxHitsPerPrimInCastRay) + { + rayHits.RemoveAt(i); + hit--; + hits[id] = hit; + } + } + } + } + + // Parse hits into result list according to data flags + int hitCount = rayHits.Count; + if (hitCount > maxHits) + hitCount = maxHits; + for (int i = 0; i < hitCount; i++) + { + RayHit rayHit = rayHits[i]; + if (getRootKey) + result.Add(new LSL_Key(rayHit.GroupId.ToString())); + else + result.Add(new LSL_Key(rayHit.PartId.ToString())); + result.Add(new LSL_Vector(rayHit.Position)); + if (getLinkNum) + result.Add(new LSL_Integer(rayHit.Link)); + if (getNormal) + result.Add(new LSL_Vector(rayHit.Normal)); + } + result.Add(new LSL_Integer(hitCount)); + return result; + } + + /// + /// Struct for transmitting parameters required for finding llCastRay ray hits. + /// + public struct RayTrans + { + public UUID PartId; + public UUID GroupId; + public int Link; + public Vector3 Scale; + public Vector3 PositionPartProj; + public Vector3 PositionProj; + public Quaternion RotationPartProj; + public Quaternion RotationBack; + public bool NeedsEnds; + public float RayLength; + public float Tolerance; + public float Tolerance2; + } + + /// + /// Struct for llCastRay ray hits. + /// + public struct RayHit + { + public UUID PartId; + public UUID GroupId; + public int Link; + public Vector3 Position; + public Vector3 Normal; + public float Distance; + } + + /// + /// Helper to parse SimpleMesh for ray hits. + /// + private void AddRayInSimpleMesh(SimpleMesh mesh, RayTrans rayTrans, ref List rayHits) + { + if (mesh != null) + { + for (int i = 0; i < mesh.Indices.Count; i += 3) + { + Tri triangle = new Tri(); + triangle.p1 = mesh.Vertices[mesh.Indices[i]].Position; + triangle.p2 = mesh.Vertices[mesh.Indices[i + 1]].Position; + triangle.p3 = mesh.Vertices[mesh.Indices[i + 2]].Position; + AddRayInTri(triangle, rayTrans, ref rayHits); + } + } + } + + /// + /// Helper to parse FacetedMesh for ray hits. + /// + private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List rayHits) + { + if (mesh != null) + { + foreach (Face face in mesh.Faces) + { + for (int i = 0; i + /// Helper to parse Tri (triangle) List for ray hits. + /// + private void AddRayInTris(List triangles, RayTrans rayTrans, ref List rayHits) + { + foreach (Tri triangle in triangles) + { + AddRayInTri(triangle, rayTrans, ref rayHits); + } + } + + /// + /// Helper to add ray hit in a Tri (triangle). + /// + private void AddRayInTri(Tri triangle, RayTrans rayTrans, ref List rayHits) + { + // Check for hit in triangle + float distance; + Vector3 posHit; + Vector3 normal; + if (HitRayInTri(triangle, rayTrans, out distance, out posHit, out normal)) + { + // Project hit part back to normal coordinate system + Vector3 posPart = rayTrans.PositionPartProj * rayTrans.RotationBack - rayTrans.PositionProj; + // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) faces plane through shape center + if (Math.Abs(Vector3.Dot(posPart, normal) - Vector3.Dot(posHit, normal)) < rayTrans.Tolerance && !rayTrans.NeedsEnds) + return; + // Remove duplicate hits at triangle edges and intersections + for (int i = rayHits.Count - 1; i >= 0; i--) + { + if (rayHits[i].PartId == rayTrans.PartId && Math.Abs(rayHits[i].Distance - distance) < rayTrans.Tolerance2) + return; + } + + // Build result data set + RayHit rayHit = new RayHit(); + rayHit.PartId = rayTrans.PartId; + rayHit.GroupId = rayTrans.GroupId; + rayHit.Link = rayTrans.Link; + rayHit.Position = posHit; + rayHit.Normal = normal; + rayHit.Distance = distance; + rayHits.Add(rayHit); + } + } + + /// + /// Helper to find ray hit in a Tri (triangle). + /// + private bool HitRayInTri(Tri triangle, RayTrans rayTrans, out float distance, out Vector3 posHit, out Vector3 normal) + { + // Initialize + distance = 0.0f; + posHit = Vector3.Zero; + normal = Vector3.Zero; + float tol = rayTrans.Tolerance; + + // Project triangle on X-Y plane + Vector3 pos1 = triangle.p1 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; + Vector3 pos2 = triangle.p2 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; + Vector3 pos3 = triangle.p3 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; + + // Check if ray/origo inside triangle bounding rectangle + Vector3 lower = Vector3.Min(pos1, Vector3.Min(pos2, pos3)); + Vector3 upper = Vector3.Max(pos1, Vector3.Max(pos2, pos3)); + if (lower.X > tol || lower.Y > tol || lower.Z > tol || upper.X < -tol || upper.Y < -tol || upper.Z < -rayTrans.RayLength - tol) + return false; + + // Check if ray/origo inside every edge or reverse "outside" every edge on exit + float dist; + bool inside = true; + bool outside = true; + Vector3 vec1 = pos2 - pos1; + dist = pos1.X * vec1.Y - pos1.Y * vec1.X; + if (dist < -tol) + inside = false; + if (dist > tol) + outside = false; + Vector3 vec2 = pos3 - pos2; + dist = pos2.X * vec2.Y - pos2.Y * vec2.X; + if (dist < -tol) + inside = false; + if (dist > tol) + outside = false; + Vector3 vec3 = pos1 - pos3; + dist = pos3.X * vec3.Y - pos3.Y * vec3.X; + if (dist < -tol) + inside = false; + if (dist > tol) + outside = false; + + // Skip if ray/origo outside + if (!inside && !(outside && m_detectExitsInCastRay)) + return false; + + // Calculate normal + Vector3 normalProj = Vector3.Cross(vec1, vec2); + float normalLength = normalProj.Length(); + // Skip if degenerate triangle + if (normalLength < tol) + return false; + normalProj = normalProj / normalLength; + // Skip if ray parallell to triangle plane + if (Math.Abs(normalProj.Z) < tol) + return false; + + // Calculate distance + distance = Vector3.Dot(normalProj, pos2) / normalProj.Z * -1.0f; + // Skip if outside ray + if (distance < -tol || distance > rayTrans.RayLength + tol) + return false; + + // Calculate projected hit position + Vector3 posHitProj = new Vector3(0.0f, 0.0f, -distance); + // Project hit back to normal coordinate system + posHit = posHitProj * rayTrans.RotationBack - rayTrans.PositionProj; + normal = normalProj * rayTrans.RotationBack; + return true; + } + + /// + /// Helper to parse selected parts of HeightMap into a Tri (triangle) List and calculate bounding box. + /// + private List TrisFromHeightmapUnderRay(Vector3 posStart, Vector3 posEnd, out Vector3 lower, out Vector3 upper) + { + // Get bounding X-Y rectangle of terrain under ray + lower = Vector3.Min(posStart, posEnd); + upper = Vector3.Max(posStart, posEnd); + lower.X = (float)Math.Floor(lower.X); + lower.Y = (float)Math.Floor(lower.Y); + float zLower = float.MaxValue; + upper.X = (float)Math.Ceiling(upper.X); + upper.Y = (float)Math.Ceiling(upper.Y); + float zUpper = float.MinValue; + + // Initialize Tri (triangle) List + List triangles = new List(); + + // Set parsing lane direction to major ray X-Y axis + Vector3 vec = posEnd - posStart; + float xAbs = Math.Abs(vec.X); + float yAbs = Math.Abs(vec.Y); + bool bigX = true; + if (yAbs > xAbs) + { + bigX = false; + vec = vec / yAbs; + } + else if (xAbs > yAbs || xAbs > 0.0f) + vec = vec / xAbs; + else + vec = new Vector3(1.0f, 1.0f, 0.0f); + + // Simplify by start parsing in lower end of lane + if ((bigX && vec.X < 0.0f) || (!bigX && vec.Y < 0.0f)) + { + Vector3 posTemp = posStart; + posStart = posEnd; + posEnd = posTemp; + vec = vec * -1.0f; + } + + // First 1x1 rectangle under ray + float xFloorOld = 0.0f; + float yFloorOld = 0.0f; + Vector3 pos = posStart; + float xFloor = (float)Math.Floor(pos.X); + float yFloor = (float)Math.Floor(pos.Y); + AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); + + // Parse every remaining 1x1 rectangle under ray + while (pos != posEnd) + { + // Next 1x1 rectangle under ray + xFloorOld = xFloor; + yFloorOld = yFloor; + pos = pos + vec; + + // Clip position to 1x1 rectangle border + xFloor = (float)Math.Floor(pos.X); + yFloor = (float)Math.Floor(pos.Y); + if (bigX && pos.X > xFloor) + { + pos.Y -= vec.Y * (pos.X - xFloor); + pos.X = xFloor; + } + else if (!bigX && pos.Y > yFloor) + { + pos.X -= vec.X * (pos.Y - yFloor); + pos.Y = yFloor; + } + + // Last 1x1 rectangle under ray + if ((bigX && pos.X >= posEnd.X) || (!bigX && pos.Y >= posEnd.Y)) + { + pos = posEnd; + xFloor = (float)Math.Floor(pos.X); + yFloor = (float)Math.Floor(pos.Y); + } + + // Add new 1x1 rectangle in lane + if ((bigX && xFloor != xFloorOld) || (!bigX && yFloor != yFloorOld)) + AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); + // Add last 1x1 rectangle in old lane at lane shift + if (bigX && yFloor != yFloorOld) + AddTrisFromHeightmap(xFloor, yFloorOld, ref triangles, ref zLower, ref zUpper); + if (!bigX && xFloor != xFloorOld) + AddTrisFromHeightmap(xFloorOld, yFloor, ref triangles, ref zLower, ref zUpper); + } + + // Finalize bounding box Z + lower.Z = zLower; + upper.Z = zUpper; + + // Done and returning Tri (triangle)List + return triangles; + } + + /// + /// Helper to add HeightMap squares into Tri (triangle) List and adjust bounding box. + /// + private void AddTrisFromHeightmap(float xPos, float yPos, ref List triangles, ref float zLower, ref float zUpper) + { + int xInt = (int)xPos; + int yInt = (int)yPos; + + // Corner 1 of 1x1 rectangle + int x = Util.Clamp(xInt+1, 0, World.Heightmap.Width - 1); + int y = Util.Clamp(yInt+1, 0, World.Heightmap.Height - 1); + Vector3 pos1 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos1.Z); + zUpper = Math.Max(zUpper, pos1.Z); + + // Corner 2 of 1x1 rectangle + x = Util.Clamp(xInt, 0, World.Heightmap.Width - 1); + y = Util.Clamp(yInt+1, 0, World.Heightmap.Height - 1); + Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos1.Z); + zUpper = Math.Max(zUpper, pos1.Z); + + // Corner 3 of 1x1 rectangle + x = Util.Clamp(xInt, 0, World.Heightmap.Width - 1); + y = Util.Clamp(yInt, 0, World.Heightmap.Height - 1); + Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos1.Z); + zUpper = Math.Max(zUpper, pos1.Z); + + // Corner 4 of 1x1 rectangle + x = Util.Clamp(xInt+1, 0, World.Heightmap.Width - 1); + y = Util.Clamp(yInt, 0, World.Heightmap.Height - 1); + Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); + // Adjust bounding box + zLower = Math.Min(zLower, pos1.Z); + zUpper = Math.Max(zUpper, pos1.Z); + + // Add triangle 1 + Tri triangle1 = new Tri(); + triangle1.p1 = pos1; + triangle1.p2 = pos2; + triangle1.p3 = pos3; + triangles.Add(triangle1); + + // Add triangle 2 + Tri triangle2 = new Tri(); + triangle2.p1 = pos3; + triangle2.p2 = pos4; + triangle2.p3 = pos1; + triangles.Add(triangle2); + } + + /// + /// Helper to check if a ray intersects bounding shapes. + /// + private bool InBoundingShapes(Vector3 ray, float rayLength, Vector3 scale, Vector3 posPartRel, Vector3 posPartProj, Quaternion rotProj) + { + float tol = m_floatToleranceInCastRay; + + // Check if ray intersects projected bounding box + Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); + int dummy = 0; + AddBoundingBoxOfSimpleBox(scale * -0.5f, scale * 0.5f, posPartProj, rotProj, true, ref lowerBox, ref upperBox, ref dummy); + if (lowerBox.X > tol || lowerBox.Y > tol || lowerBox.Z > tol || upperBox.X < -tol || upperBox.Y < -tol || upperBox.Z < -rayLength - tol) + return false; + + // Passed bounding shape filters, so return true + return true; + } + + /// + /// Helper to get link number for a UUID. + /// + private int UUID2LinkNumber(SceneObjectPart part, UUID id) + { + SceneObjectGroup group = part.ParentGroup; + if (group != null) + { + // Parse every link for UUID + int linkCount = group.PrimCount + group.GetSittingAvatarsCount(); + for (int link = linkCount; link > 0; link--) + { + ISceneEntity entity = GetLinkEntity(part, link); + // Return link number if UUID match + if (entity != null && entity.UUID == id) + return link; + } + } + // Return link number 0 if no links or UUID matches + return 0; + } + public LSL_Integer llManageEstateAccess(int action, string avatar) { m_host.AddScriptLPS(1); -- cgit v1.1 From c96ee68953eb31fc2ad6d1df9b7a4bb19c584e17 Mon Sep 17 00:00:00 2001 From: Magnuz Binder Date: Mon, 4 May 2015 10:51:04 +0200 Subject: Patch llCastRay fully-simplified to V2. Signed-off-by: Michael Cerquoni --- .../Shared/Api/Implementation/LSL_Api.cs | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index cf1bd2b..58b3930 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -221,6 +221,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected float m_primSafetyCoeffX = 2.414214f; protected float m_primSafetyCoeffY = 2.414214f; protected float m_primSafetyCoeffZ = 1.618034f; + protected bool m_useCastRayV2 = false; + protected int RC_USE_V2 = 512; protected float m_floatToleranceInCastRay = 0.000001f; protected float m_floatTolerance2InCastRay = 0.0001f; protected int m_maxHitsInCastRay = 16; @@ -229,7 +231,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected bool m_detectExitsInCastRay = false; protected bool m_filterPartsInCastRay = false; protected bool m_doAttachmentsInCastRay = false; - protected bool m_useCastRayV1 = true; //An array of HTTP/1.1 headers that are not allowed to be used //as custom headers by llHTTPRequest. @@ -336,6 +337,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); + m_useCastRayV2 = lslConfig.GetBoolean("UseLlCastRayV2", m_useCastRayV2); + RC_USE_V2 = lslConfig.GetInt("RC_USE_V2", RC_USE_V2); m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); @@ -344,7 +347,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); - m_useCastRayV1 = lslConfig.GetBoolean("UseLlCastRayV1", m_useCastRayV1); } IConfig smtpConfig = seConfigSource.Configs["SMTP"]; @@ -13763,7 +13765,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return contacts[0]; } - public LSL_List llCastRayV1(LSL_Vector start, LSL_Vector end, LSL_List options) + public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) { LSL_List list = new LSL_List(); @@ -13792,6 +13794,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api rejectTypes = options.GetLSLIntegerItem(i + 1); } + // Use llCastRay v2 if configured or requested + if (m_useCastRayV2 || (dataFlags & RC_USE_V2) == RC_USE_V2) + return llCastRayV2(start, end, options); + if (count > 16) count = 16; @@ -13955,25 +13961,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// Full implementation of llCastRay similar to SL 2015-04-21. + /// Implementation of llCastRay similar to SL 2015-04-21. /// http://wiki.secondlife.com/wiki/LlCastRay /// Uses pure geometry, bounding shapes, meshing and no physics /// for prims, sculpts, meshes, avatars and terrain. /// Implements all flags, reject types and data flags. /// Can handle both objects/groups and prims/parts, by config. - /// May give poor results with multi-part meshes where "root" - /// part doesn't dominate, owing to "guessed" bounding boxes. /// May sometimes be inaccurate owing to calculation precision /// and a bug in libopenmetaverse PrimMesher. /// - public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + public LSL_List llCastRayV2(LSL_Vector start, LSL_Vector end, LSL_List options) { - // Use llCastRay v1 if configured - if (m_useCastRayV1) - return llCastRayV1(start, end, options); - // Initialize - m_host.AddScriptLPS(1); + // Keep AddScriptLPS commented while called from llCastRay + // m_host.AddScriptLPS(1); List rayHits = new List(); LSL_List result = new LSL_List(); float tol = m_floatToleranceInCastRay; @@ -14009,10 +14010,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Vector3 ray = end - start; float rayLength = ray.Length(); - // Try to get a mesher and return failure if none or degenerate ray + // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits IRendering primMesher = null; List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); - if (renderers.Count < 1 || rayLength < tol) + if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1) { result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); return result; -- cgit v1.1 From 5a2440dfdf4a4ab769692330f6d4f98521e271ce Mon Sep 17 00:00:00 2001 From: Magnuz Binder Date: Fri, 1 May 2015 07:00:45 +0200 Subject: Implement llGetGeometricCenter correctly. Signed-off-by: Michael Cerquoni --- .../Shared/Api/Implementation/LSL_Api.cs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 58b3930..2fcfcbe 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -10087,9 +10087,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return prim; } + /// + /// Implementation of llGetGeometricCenter according to SL 2015-04-30. + /// http://wiki.secondlife.com/wiki/LlGetGeometricCenter + /// Returns the average position offset of all linked parts, + /// including the root prim and seated avatars, + /// relative to the root prim in local coordinates. + /// public LSL_Vector llGetGeometricCenter() { - return new LSL_Vector(m_host.GetGeometricCenter()); + // Subtract whatever position the root prim has to make it zero + Vector3 offset = m_host.ParentGroup.RootPart.OffsetPosition * -1.0f; + + // Add all prim/part position offsets + foreach (SceneObjectPart part in m_host.ParentGroup.Parts) + offset = offset + part.OffsetPosition; + // Add all avatar/scene presence position offsets + foreach (ScenePresence sp in m_host.ParentGroup.GetSittingAvatars()) + offset = offset + sp.OffsetPosition; + + // Calculate and return the average offset + offset = offset / (float)(m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount()); + return new LSL_Vector(offset); } public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules) -- cgit v1.1 From 382e05df143a2434a855d097c764fb7cbac16ceb Mon Sep 17 00:00:00 2001 From: Talun Date: Thu, 30 Apr 2015 21:39:11 +0100 Subject: Missing constants for llGetObjectDetails OBJECT_BODY_SHAPE_TYPE OBJECT_HOVER_HEIGHT OBJECT_LAST_OWNER_ID OBJECT_RENDER_WEIGHT Signed-off-by: Michael Cerquoni --- .../Shared/Api/Implementation/LSL_Api.cs | 29 ++++++++++++++++++++++ .../Shared/Api/Runtime/LSL_Constants.cs | 4 +++ 2 files changed, 33 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 2fcfcbe..25f1958 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -13051,6 +13051,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_TEMP_ON_REZ: ret.Add(new LSL_Integer(0)); break; + case ScriptBaseClass.OBJECT_RENDER_WEIGHT: + ret.Add(new LSL_Integer(-1)); + break; + case ScriptBaseClass.OBJECT_HOVER_HEIGHT: + ret.Add(new LSL_Float(0)); + break; + case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: + LSL_Float shapeType; + if (av.Appearance.VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MALE] != 0) + shapeType = new LSL_Float(1); + else + shapeType = new LSL_Float(0); + ret.Add(shapeType); + break; + case ScriptBaseClass.OBJECT_LAST_OWNER_ID: + ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY)); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); @@ -13215,6 +13232,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_TEMP_ON_REZ: ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0)); break; + case ScriptBaseClass.OBJECT_RENDER_WEIGHT: + ret.Add(new LSL_Integer(0)); + break; + case ScriptBaseClass.OBJECT_HOVER_HEIGHT: + ret.Add(new LSL_Float(0)); + break; + case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: + ret.Add(new LSL_Float(-1)); + break; + case ScriptBaseClass.OBJECT_LAST_OWNER_ID: + ret.Add(new LSL_Key(obj.ParentGroup.LastOwnerID.ToString())); + break; default: // Invalid or unhandled constant. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index a96cd16..e37d3af 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -596,6 +596,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OBJECT_PHYSICS = 21; public const int OBJECT_PHANTOM = 22; public const int OBJECT_TEMP_ON_REZ = 23; + public const int OBJECT_RENDER_WEIGHT = 24; + public const int OBJECT_HOVER_HEIGHT = 25; + public const int OBJECT_BODY_SHAPE_TYPE = 26; + public const int OBJECT_LAST_OWNER_ID = 27; // Pathfinding types public const int OPT_OTHER = -1; -- cgit v1.1 From 49991d055a889f2bd082695383b664a40107db40 Mon Sep 17 00:00:00 2001 From: H-H-H Date: Fri, 1 May 2015 19:30:56 +0100 Subject: Adding the command to opensim console which requires a region name as an argument and will do an oar of that region if the autobackup module is enabled Signed-off-by: Michael Cerquoni --- .../World/AutoBackup/AutoBackupModule.cs | 42 ++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs index 28dc5f5..c17a368 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs @@ -115,6 +115,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup private delegate T DefaultGetter(string settingName, T defaultValue); private bool m_enabled; + private ICommandConsole m_console; + private List m_Scenes = new List (); + /// /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! @@ -206,8 +209,20 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded. /// /// - void IRegionModuleBase.AddRegion(Scene scene) + void IRegionModuleBase.AddRegion (Scene scene) { + if (!this.m_enabled) { + return; + } + lock (m_Scenes) { + m_Scenes.Add (scene); + } + m_console = MainConsole.Instance; + + m_console.Commands.AddCommand ( + "AutoBackup", false, "dobackup", + "dobackup", + "do backup.", DoBackup); } /// @@ -220,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup { return; } - + m_Scenes.Remove (scene); if (this.m_states.ContainsKey(scene)) { AutoBackupModuleState abms = this.m_states[scene]; @@ -275,6 +290,29 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup #endregion + + private void DoBackup (string module, string[] args) + { + if (args.Length != 2) { + MainConsole.Instance.OutputFormat ("Usage: dobackup "); + return; + } + bool found = false; + string name = args [1]; + lock (m_Scenes) { + foreach (Scene s in m_Scenes) { + string test = s.Name.ToString (); + if (test == name) { + found = true; + DoRegionBackup (s); + } + } + if (!found) { + MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name); + } + } + } + /// /// Set up internal state for a given scene. Fairly complex code. /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene. -- cgit v1.1 From dfb73c1464b981c158661bc443d7323f4928d2b9 Mon Sep 17 00:00:00 2001 From: Michael Cerquoni Date: Mon, 4 May 2015 15:56:12 -0400 Subject: fix a minor whitespace issue --- OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs index c17a368..ceb3332 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs @@ -290,7 +290,6 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup #endregion - private void DoBackup (string module, string[] args) { if (args.Length != 2) { -- cgit v1.1 From 44b8b9fef625f6f562a7d8cb0531bd518f11d037 Mon Sep 17 00:00:00 2001 From: Michael Cerquoni Date: Mon, 4 May 2015 16:23:16 -0400 Subject: Revert "Patch llCastRay fully-simplified to V2." for further review. This reverts commit c96ee68953eb31fc2ad6d1df9b7a4bb19c584e17. --- .../Shared/Api/Implementation/LSL_Api.cs | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 25f1958..c90f015 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -221,8 +221,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected float m_primSafetyCoeffX = 2.414214f; protected float m_primSafetyCoeffY = 2.414214f; protected float m_primSafetyCoeffZ = 1.618034f; - protected bool m_useCastRayV2 = false; - protected int RC_USE_V2 = 512; protected float m_floatToleranceInCastRay = 0.000001f; protected float m_floatTolerance2InCastRay = 0.0001f; protected int m_maxHitsInCastRay = 16; @@ -231,6 +229,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected bool m_detectExitsInCastRay = false; protected bool m_filterPartsInCastRay = false; protected bool m_doAttachmentsInCastRay = false; + protected bool m_useCastRayV1 = true; //An array of HTTP/1.1 headers that are not allowed to be used //as custom headers by llHTTPRequest. @@ -337,8 +336,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); - m_useCastRayV2 = lslConfig.GetBoolean("UseLlCastRayV2", m_useCastRayV2); - RC_USE_V2 = lslConfig.GetInt("RC_USE_V2", RC_USE_V2); m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); @@ -347,6 +344,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); + m_useCastRayV1 = lslConfig.GetBoolean("UseLlCastRayV1", m_useCastRayV1); } IConfig smtpConfig = seConfigSource.Configs["SMTP"]; @@ -13813,7 +13811,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return contacts[0]; } - public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + public LSL_List llCastRayV1(LSL_Vector start, LSL_Vector end, LSL_List options) { LSL_List list = new LSL_List(); @@ -13842,10 +13840,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api rejectTypes = options.GetLSLIntegerItem(i + 1); } - // Use llCastRay v2 if configured or requested - if (m_useCastRayV2 || (dataFlags & RC_USE_V2) == RC_USE_V2) - return llCastRayV2(start, end, options); - if (count > 16) count = 16; @@ -14009,20 +14003,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// Implementation of llCastRay similar to SL 2015-04-21. + /// Full implementation of llCastRay similar to SL 2015-04-21. /// http://wiki.secondlife.com/wiki/LlCastRay /// Uses pure geometry, bounding shapes, meshing and no physics /// for prims, sculpts, meshes, avatars and terrain. /// Implements all flags, reject types and data flags. /// Can handle both objects/groups and prims/parts, by config. + /// May give poor results with multi-part meshes where "root" + /// part doesn't dominate, owing to "guessed" bounding boxes. /// May sometimes be inaccurate owing to calculation precision /// and a bug in libopenmetaverse PrimMesher. /// - public LSL_List llCastRayV2(LSL_Vector start, LSL_Vector end, LSL_List options) + public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) { + // Use llCastRay v1 if configured + if (m_useCastRayV1) + return llCastRayV1(start, end, options); + // Initialize - // Keep AddScriptLPS commented while called from llCastRay - // m_host.AddScriptLPS(1); + m_host.AddScriptLPS(1); List rayHits = new List(); LSL_List result = new LSL_List(); float tol = m_floatToleranceInCastRay; @@ -14058,10 +14057,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Vector3 ray = end - start; float rayLength = ray.Length(); - // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits + // Try to get a mesher and return failure if none or degenerate ray IRendering primMesher = null; List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); - if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1) + if (renderers.Count < 1 || rayLength < tol) { result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); return result; -- cgit v1.1 From 1abbad71b4603245e5481c11e3ce55f57b64935f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 5 May 2015 20:59:09 -0700 Subject: Refactored some code that is used in two different dlls related to SOP rewriting. Also added some unit tests that relate to mantis #7514 --- .../Framework/InventoryAccess/HGAssetMapper.cs | 209 +-------------------- .../CoreModules/World/Archiver/AssetsRequest.cs | 2 +- .../Scenes/Tests/SceneObjectSerializationTests.cs | 136 ++++++++++++++ 3 files changed, 139 insertions(+), 208 deletions(-) create mode 100644 OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index c2010b1..f54298c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs @@ -35,6 +35,7 @@ using System.Xml; using log4net; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Serialization; @@ -189,217 +190,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return Utils.StringToBytes(RewriteSOP(xml)); } - protected void TransformXml(XmlReader reader, XmlWriter writer) - { -// m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML"); - - int sopDepth = -1; - UserAccount creator = null; - bool hasCreatorData = false; - - while (reader.Read()) - { -// Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name); - - switch (reader.NodeType) - { - case XmlNodeType.Attribute: -// Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name); - writer.WriteAttributeString(reader.Name, reader.Value); - break; - - case XmlNodeType.CDATA: - writer.WriteCData(reader.Value); - break; - - case XmlNodeType.Comment: - writer.WriteComment(reader.Value); - break; - - case XmlNodeType.DocumentType: - writer.WriteDocType(reader.Name, reader.Value, null, null); - break; - - case XmlNodeType.Element: -// m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name); - - writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI); - - if (reader.HasAttributes) - { - while (reader.MoveToNextAttribute()) - writer.WriteAttributeString(reader.Name, reader.Value); - - reader.MoveToElement(); - } - - if (reader.LocalName == "SceneObjectPart") - { - if (sopDepth < 0) - { - sopDepth = reader.Depth; -// m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth); - } - } - else - { - if (sopDepth >= 0 && reader.Depth == sopDepth + 1) - { - if (reader.Name == "CreatorID") - { - reader.Read(); - if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID") - { - reader.Read(); - - if (reader.NodeType == XmlNodeType.Text) - { - UUID uuid = UUID.Zero; - UUID.TryParse(reader.Value, out uuid); - creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); - writer.WriteElementString("UUID", reader.Value); - reader.Read(); - } - else - { - // If we unexpected run across mixed content in this node, still carry on - // transforming the subtree (this replicates earlier behaviour). - TransformXml(reader, writer); - } - } - else - { - // If we unexpected run across mixed content in this node, still carry on - // transforming the subtree (this replicates earlier behaviour). - TransformXml(reader, writer); - } - } - else if (reader.Name == "CreatorData") - { - reader.Read(); - if (reader.NodeType == XmlNodeType.Text) - { - hasCreatorData = true; - writer.WriteString(reader.Value); - } - else - { - // If we unexpected run across mixed content in this node, still carry on - // transforming the subtree (this replicates earlier behaviour). - TransformXml(reader, writer); - } - } - } - } - - if (reader.IsEmptyElement) - { -// m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name); - writer.WriteEndElement(); - } - - break; - - case XmlNodeType.EndElement: -// m_log.DebugFormat("Depth {0} at EndElement", reader.Depth); - if (sopDepth == reader.Depth) - { - if (!hasCreatorData && creator != null) - writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", m_HomeURI, creator.FirstName, creator.LastName)); - -// m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth"); - sopDepth = -1; - creator = null; - hasCreatorData = false; - } - writer.WriteEndElement(); - break; - - case XmlNodeType.EntityReference: - writer.WriteEntityRef(reader.Name); - break; - - case XmlNodeType.ProcessingInstruction: - writer.WriteProcessingInstruction(reader.Name, reader.Value); - break; - - case XmlNodeType.Text: - writer.WriteString(reader.Value); - break; - - case XmlNodeType.XmlDeclaration: - // For various reasons, not all serializations have xml declarations (or consistent ones) - // and as it's embedded inside a byte stream we don't need it anyway, so ignore. - break; - - default: - m_log.WarnFormat( - "[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}", - reader.NodeType, m_scene.Name); - break; - } - } - } - protected string RewriteSOP(string xmlData) { // Console.WriteLine("Input XML [{0}]", xmlData); + return ExternalRepresentationUtils.RewriteSOP(xmlData, m_scene.Name, m_HomeURI, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID); - using (StringWriter sw = new StringWriter()) - using (XmlTextWriter writer = new XmlTextWriter(sw)) - using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null)) - using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment })) - { - TransformXml(reader, writer); - -// Console.WriteLine("Output: [{0}]", sw.ToString()); - - return sw.ToString(); - } - - // We are now taking the more complex streaming approach above because some assets can be very large - // and can trigger higher CPU use or possibly memory problems. -// XmlDocument doc = new XmlDocument(); -// doc.LoadXml(xml); -// XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart"); -// -// foreach (XmlNode sop in sops) -// { -// UserAccount creator = null; -// bool hasCreatorData = false; -// XmlNodeList nodes = sop.ChildNodes; -// foreach (XmlNode node in nodes) -// { -// if (node.Name == "CreatorID") -// { -// UUID uuid = UUID.Zero; -// UUID.TryParse(node.InnerText, out uuid); -// creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); -// } -// if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty) -// hasCreatorData = true; -// -// //if (node.Name == "OwnerID") -// //{ -// // UserAccount owner = GetUser(node.InnerText); -// // if (owner != null) -// // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName; -// //} -// } -// -// if (!hasCreatorData && creator != null) -// { -// XmlElement creatorData = doc.CreateElement("CreatorData"); -// creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName; -// sop.AppendChild(creatorData); -// } -// } -// -// using (StringWriter wr = new StringWriter()) -// { -// doc.Save(wr); -// return wr.ToString(); -// } } // TODO: unused diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index 4d99a6e..db66c83 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs @@ -335,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) { //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); - string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), m_options["home"].ToString(), m_userAccountService, m_scopeID); + string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), string.Empty, m_options["home"].ToString(), m_userAccountService, m_scopeID); asset.Data = Utils.StringToBytes(xml); } return asset; diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs new file mode 100644 index 0000000..927d8e8 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs @@ -0,0 +1,136 @@ +/* + * 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.Reflection; +using System.Threading; +using System.Xml; +using System.Linq; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Serialization.External; +using OpenSim.Framework.Communications; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Basic scene object serialization tests. + /// + [TestFixture] + public class SceneObjectSerializationTests : OpenSimTestCase + { + + /// + /// Serialize and deserialize. + /// + [Test] + public void TestSerialDeserial() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + int partsToTestCount = 3; + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; + so.Name = "obj1"; + so.Description = "xpto"; + + string xml = SceneObjectSerializer.ToXml2Format(so); + Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string"); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart"); + Assert.That(nodes.Count, Is.EqualTo(3), "SOG serialization resulted in wrong number of SOPs"); + + SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml); + Assert.IsNotNull(so2, "SOG deserialization resulted in null object"); + Assert.That(so2.Name == so.Name, "Name of deserialized object does not match original name"); + Assert.That(so2.Description == so.Description, "Description of deserialized object does not match original name"); + } + + /// + /// This checks for a bug reported in mantis #7514 + /// + [Test] + public void TestNamespaceAttribute() + { + TestHelpers.InMethod(); + + Scene scene = new SceneHelpers().SetupScene(); + UserAccount account = new UserAccount(UUID.Zero, UUID.Random(), "Test", "User", string.Empty); + scene.UserAccountService.StoreUserAccount(account); + int partsToTestCount = 1; + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; + so.Name = "obj1"; + so.Description = "xpto"; + so.OwnerID = account.PrincipalID; + so.RootPart.CreatorID = so.OwnerID; + + string xml = SceneObjectSerializer.ToXml2Format(so); + Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string"); + + xml = ExternalRepresentationUtils.RewriteSOP(xml, "Test Scene", "http://localhost", scene.UserAccountService, UUID.Zero); + //Console.WriteLine(xml); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml(xml); + + XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart"); + Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no SOPs"); + foreach (XmlAttribute a in nodes[0].Attributes) + { + int count = a.Name.Count(c => c == ':'); + Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in SOP"); + } + nodes = doc.GetElementsByTagName("CreatorData"); + Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no CreatorData"); + foreach (XmlAttribute a in nodes[0].Attributes) + { + int count = a.Name.Count(c => c == ':'); + Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in CreatorData"); + } + + SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml); + Assert.IsNotNull(so2, "SOG deserialization resulted in null object"); + Assert.AreNotEqual(so.RootPart.CreatorIdentification, so2.RootPart.CreatorIdentification, "RewriteSOP failed to transform CreatorData."); + Assert.That(so2.RootPart.CreatorIdentification.Contains("http://"), "RewriteSOP failed to add the homeURL to CreatorData"); + } + } +} \ No newline at end of file -- cgit v1.1 From 8676b017b24009cc26b274d211d43890594551c1 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 5 May 2015 21:28:27 -0700 Subject: Attempt at fixing mantis #7054. The two inventory threads are stepping on each other's feet. This needs real-world testing, as I'm not sure of all the consequences of reducing the number of worker threads to 1. --- OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 053a6a2..e402b0b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -201,11 +201,12 @@ namespace OpenSim.Region.ClientStack.Linden Scene.EventManager.OnRegisterCaps += RegisterCaps; + int nworkers = 1; // was 2 if (ProcessQueuedRequestsAsync && m_workerThreads == null) { - m_workerThreads = new Thread[2]; + m_workerThreads = new Thread[nworkers]; - for (uint i = 0; i < 2; i++) + for (uint i = 0; i < nworkers; i++) { m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, String.Format("InventoryWorkerThread{0}", i), -- cgit v1.1 From 4bf62e11b6a99c024e3dfa42db7425ea790009ee Mon Sep 17 00:00:00 2001 From: Dev Random Date: Wed, 6 May 2015 13:15:41 -0400 Subject: 'terrain modify' command for area-of-effect operations Signed-off-by: Michael Cerquoni --- .../CoreModules/World/Terrain/ITerrainModifier.cs | 77 +++++ .../World/Terrain/Modifiers/FillModifier.cs | 94 +++++ .../World/Terrain/Modifiers/LowerModifier.cs | 93 +++++ .../World/Terrain/Modifiers/MaxModifier.cs | 93 +++++ .../World/Terrain/Modifiers/MinModifier.cs | 93 +++++ .../World/Terrain/Modifiers/RaiseModifier.cs | 93 +++++ .../World/Terrain/Modifiers/SmoothModifier.cs | 132 +++++++ .../CoreModules/World/Terrain/TerrainModifier.cs | 378 +++++++++++++++++++++ .../World/Terrain/TerrainModifierData.cs | 17 + .../CoreModules/World/Terrain/TerrainModule.cs | 339 ++++++++++-------- 10 files changed, 1266 insertions(+), 143 deletions(-) create mode 100644 OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs new file mode 100644 index 0000000..0e0a0e4 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs @@ -0,0 +1,77 @@ +/* + * 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 OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain +{ + public interface ITerrainModifier + { + /// + /// Creates the feature. + /// + /// + /// Empty string if successful, otherwise error message. + /// + /// + /// ITerrainChannel holding terrain data. + /// + /// + /// command-line arguments from console. + /// + string ModifyTerrain(ITerrainChannel map, string[] args); + + /// + /// Gets a string describing the usage. + /// + /// + /// A string describing parameters for creating the feature. + /// Format is "feature-name ..." + /// + string GetUsage(); + + /// + /// Apply the appropriate operation on the specified map, at (x, y). + /// + /// + /// Map. + /// + /// + /// Data. + /// + /// + /// X. + /// + /// + /// Y. + /// + double operate(double[,] map, TerrainModifierData data, int x, int y); + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs new file mode 100644 index 0000000..0df7132 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs @@ -0,0 +1,94 @@ +/* + * 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 OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class FillModifier : TerrainModifier + { + + public FillModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "fill [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nSets all points within the specified range to the specified value."; + return val; + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = data.elevation - (data.elevation - data.bevelevation) * factor; + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs new file mode 100644 index 0000000..3e4a457 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs @@ -0,0 +1,93 @@ +/* + * 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 OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class LowerModifier : TerrainModifier + { + public LowerModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "lower [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nLowers all points within the specified range by the specified amount."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = map[x, y] - (data.elevation - (data.elevation - data.bevelevation) * factor); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs new file mode 100644 index 0000000..02f1852 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs @@ -0,0 +1,93 @@ +/* + * 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 OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class MaxModifier : TerrainModifier + { + public MaxModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "max [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nEnsures that all points within the specified range are no higher than the specified value."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = Math.Min(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs new file mode 100644 index 0000000..2db49c8 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs @@ -0,0 +1,93 @@ +/* + * 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 OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class MinModifier : TerrainModifier + { + public MinModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "min [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nEnsures that all points within the specified range are no lower than the specified value."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = Math.Max(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs new file mode 100644 index 0000000..9ac1edd --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs @@ -0,0 +1,93 @@ +/* + * 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 OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class RaiseModifier : TerrainModifier + { + public RaiseModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "raise [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nRaises all points within the specified range by the specified amount."; + return val; + + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double result = map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor); + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs new file mode 100644 index 0000000..1731cd8 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs @@ -0,0 +1,132 @@ +/* + * 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 OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class SmoothModifier : TerrainModifier + { + public SmoothModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.bevel == "taper") + { + if (data.bevelevation < 0.01 || data.bevelevation > 0.99) + { + result = String.Format("Taper must be 0.01 to 0.99 {0}", data.bevelevation); + } + } + else + { + data.bevelevation = 2.0f / 3.0f; + } + + if (data.elevation < 0.0 || data.elevation > 1.0) + { + result = String.Format("Scaling factor must be 0.0 to 1.0: {0}", data.elevation); + } + + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "smooth [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nSmooths all points within the specified range using a simple averaging algorithm."; + return val; + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double[] scale = new double[3]; + scale[0] = data.elevation; + scale[1] = ((1.0 - scale[0]) * data.bevelevation) / 8.0; + scale[2] = ((1.0 - scale[0]) * (1.0 - data.bevelevation)) / 16.0; + int xMax = map.GetLength(0); + int yMax = map.GetLength(1); + double result; + if ((x == 0) || (y == 0) || (x == (xMax - 1)) || (y == (yMax - 1))) + { + result = map[x, y]; + } + else + { + result = 0.0; + for(int yPos = (y - 2); yPos < (y + 3); yPos++) + { + int yVal = (yPos <= 0) ? 0 : ((yPos < yMax) ? yPos : yMax - 1); + for(int xPos = (x - 2); xPos < (x + 3); xPos++) + { + int xVal = (xPos <= 0) ? 0 : ((xPos < xMax) ? xPos : xMax - 1); + int dist = Math.Max(Math.Abs(x - xVal), Math.Abs(y - yVal)); + result += map[xVal, yVal] * scale[dist]; + } + } + } + return result; + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs new file mode 100644 index 0000000..7ebd08e --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs @@ -0,0 +1,378 @@ +/* + * 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.Reflection; +using log4net; + +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Region.CoreModules.World.Terrain +{ + public abstract class TerrainModifier : ITerrainModifier + { + protected ITerrainModule m_module; + protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected TerrainModifier(ITerrainModule module) + { + m_module = module; + } + + public abstract string ModifyTerrain(ITerrainChannel map, string[] args); + + public abstract string GetUsage(); + + public abstract double operate(double[,] map, TerrainModifierData data, int x, int y); + + protected String parseParameters(string[] args, out TerrainModifierData data) + { + string val; + string arg; + string result; + data = new TerrainModifierData(); + data.shape = String.Empty; + data.bevel = String.Empty; + data.dx = 0; + data.dy = 0; + if (args.Length < 4) + { + result = "Usage: " + GetUsage(); + } + else + { + result = this.parseFloat(args[3], out data.elevation); + } + if (result == String.Empty) + { + int index = 3; + while(++index < args.Length && result == String.Empty) + { + arg = args[index]; + // check for shape + if (arg.StartsWith("-rec=") || arg.StartsWith("-ell=")) + { + if (data.shape != String.Empty) + { + result = "Only 1 '-rec' or '-ell' parameter is permitted."; + } + else + { + data.shape = arg.StartsWith("-ell=") ? "ellipse" : "rectangle"; + val = arg.Substring(arg.IndexOf("=") + 1); + string[] coords = val.Split(new char[] {','}); + if ((coords.Length < 3) || (coords.Length > 4)) + { + result = String.Format("Bad format for shape parameter {0}", arg); + } + else + { + result = this.parseInt(coords[0], out data.x0); + if (result == String.Empty) + { + result = this.parseInt(coords[1], out data.y0); + } + if (result == String.Empty) + { + result = this.parseInt(coords[2], out data.dx); + } + if (result == String.Empty) + { + if (coords.Length == 4) + { + result = this.parseInt(coords[3], out data.dy); + } + else + { + data.dy = data.dx; + } + } + if (result == String.Empty) + { + if ((data.dx <= 0) || (data.dy <= 0)) + { + result = "Shape sizes must be positive integers"; + } + } + else + { + result = String.Format("Bad value in shape parameters {0}", arg); + } + } + } + } + else if (arg.StartsWith("-taper=")) + { + if (data.bevel != String.Empty) + { + result = "Only 1 '-taper' parameter is permitted."; + } + else + { + data.bevel = "taper"; + val = arg.Substring(arg.IndexOf("=") + 1); + result = this.parseFloat(val, out data.bevelevation); + if (result != String.Empty) + { + result = String.Format("Bad format for taper parameter {0}", arg); + } + } + } + else + { + result = String.Format("Unrecognized parameter {0}", arg); + } + } + } + return result; + } + + protected string parseFloat(String s, out float f) + { + string result; + double d; + if (Double.TryParse(s, out d)) + { + try + { + f = (float)d; + result = String.Empty; + } + catch(InvalidCastException) + { + result = String.Format("{0} is invalid", s); + f = -1.0f; + } + } + else + { + f = -1.0f; + result = String.Format("{0} is invalid", s); + } + return result; + } + + protected string parseInt(String s, out int i) + { + string result; + if (Int32.TryParse(s, out i)) + { + result = String.Empty; + } + else + { + result = String.Format("{0} is invalid", s); + } + return result; + } + + protected void applyModification(ITerrainChannel map, TerrainModifierData data) + { + bool[,] mask; + int xMax; + int yMax; + int xMid; + int yMid; + if (data.shape == "ellipse") + { + mask = this.ellipticalMask(data.dx, data.dy); + xMax = mask.GetLength(0); + yMax = mask.GetLength(1); + xMid = xMax / 2 + xMax % 2; + yMid = yMax / 2 + yMax % 2; + } + else + { + mask = this.rectangularMask(data.dx, data.dy); + xMax = mask.GetLength(0); + yMax = mask.GetLength(1); + xMid = 0; + yMid = 0; + } +// m_log.DebugFormat("Apply {0} mask {1}x{2} @ {3},{4}", data.shape, xMax, yMax, xMid, yMid); + double[,] buffer = map.GetDoubles(); + int yDim = yMax; + while(--yDim >= 0) + { + int yPos = data.y0 + yDim - yMid; + if ((yPos >= 0) && (yPos < map.Height)) + { + int xDim = xMax; + while(--xDim >= 0) + { + int xPos = data.x0 + xDim - xMid; + if ((xPos >= 0) && (xPos < map.Width) && (mask[xDim, yDim])) + { + double endElevation = this.operate(buffer, data, xPos, yPos); + map[xPos, yPos] = endElevation; + } + } + } + } + } + + protected double computeBevel(TerrainModifierData data, int x, int y) + { + int deltaX; + int deltaY; + int xMax; + int yMax; + double factor; + if (data.bevel == "taper") + { + if (data.shape == "ellipse") + { + deltaX = x - data.x0; + deltaY = y - data.y0; + xMax = data.dx; + yMax = data.dy; + factor = (double)((deltaX * deltaX) + (deltaY * deltaY)); + factor /= ((xMax * xMax) + (yMax * yMax)); + } + else + { + // pyramid + xMax = data.dx / 2 + data.dx % 2; + yMax = data.dy / 2 + data.dy % 2; + deltaX = Math.Abs(data.x0 + xMax - x); + deltaY = Math.Abs(data.y0 + yMax - y); + factor = Math.Max(((double)(deltaY) / yMax), ((double)(deltaX) / xMax)); + } + } + else + { + factor = 0.0; + } + return factor; + } + + private bool[,] rectangularMask(int xSize, int ySize) + { + bool[,] mask = new bool[xSize, ySize]; + int yPos = ySize; + while(--yPos >= 0) + { + int xPos = xSize; + while(--xPos >= 0) + { + mask[xPos, yPos] = true; + } + } + return mask; + } + + /* + * Fast ellipse-based derivative of Bresenham algorithm. + * https://web.archive.org/web/20120225095359/http://homepage.smc.edu/kennedy_john/belipse.pdf + */ + private bool[,] ellipticalMask(int xRadius, int yRadius) + { + long twoASquared = 2L * xRadius * xRadius; + long twoBSquared = 2L * yRadius * yRadius; + + bool[,] mask = new bool[2 * xRadius + 1, 2 * yRadius + 1]; + + long ellipseError = 0L; + long stoppingX = twoBSquared * xRadius; + long stoppingY = 0L; + long xChange = yRadius * yRadius * (1L - 2L * xRadius); + long yChange = xRadius * xRadius; + + int xPos = xRadius; + int yPos = 0; + + // first set of points + while(stoppingX >= stoppingY) + { + int yUpper = yRadius + yPos; + int yLower = yRadius - yPos; + // fill in the mask + int xNow = xPos; + while(xNow >= 0) + { + mask[xRadius + xNow, yUpper] = true; + mask[xRadius - xNow, yUpper] = true; + mask[xRadius + xNow, yLower] = true; + mask[xRadius - xNow, yLower] = true; + --xNow; + } + yPos++; + stoppingY += twoASquared; + ellipseError += yChange; + yChange += twoASquared; + if ((2L * ellipseError + xChange) > 0L) + { + xPos--; + stoppingX -= twoBSquared; + ellipseError += xChange; + xChange += twoBSquared; + } + } + + // second set of points + xPos = 0; + yPos = yRadius; + xChange = yRadius * yRadius; + yChange = xRadius * xRadius * (1L - 2L * yRadius); + + ellipseError = 0L; + stoppingX = 0L; + stoppingY = twoASquared * yRadius; + + while(stoppingX <= stoppingY) + { + int xUpper = xRadius + xPos; + int xLower = xRadius - xPos; + // fill in the mask + int yNow = yPos; + while(yNow >= 0) + { + mask[xUpper, yRadius + yNow] = true; + mask[xUpper, yRadius - yNow] = true; + mask[xLower, yRadius + yNow] = true; + mask[xLower, yRadius - yNow] = true; + --yNow; + } + xPos++; + stoppingX += twoBSquared; + ellipseError += xChange; + xChange += twoBSquared; + if ((2L * ellipseError + yChange) > 0L) + { + yPos--; + stoppingY -= twoASquared; + ellipseError += yChange; + yChange += twoASquared; + } + } + return mask; + } + + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs new file mode 100644 index 0000000..4e0f8d7 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs @@ -0,0 +1,17 @@ +using System; + +namespace OpenSim.Region.CoreModules.World.Terrain +{ + public struct TerrainModifierData + { + public float elevation; + public string shape; + public int x0; + public int y0; + public int dx; + public int dy; + public string bevel; + public float bevelevation; + } +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 3bb8040..02f21b9 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -24,7 +24,6 @@ * (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; @@ -43,6 +42,7 @@ using OpenSim.Framework.Console; using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; using OpenSim.Region.CoreModules.World.Terrain.Features; +using OpenSim.Region.CoreModules.World.Terrain.Modifiers; using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; using OpenSim.Region.Framework.Interfaces; @@ -90,26 +90,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain #pragma warning restore 414 private readonly Commander m_commander = new Commander("terrain"); - private readonly Dictionary m_floodeffects = new Dictionary(); - private readonly Dictionary m_loaders = new Dictionary(); - private readonly Dictionary m_painteffects = new Dictionary(); - private Dictionary m_plugineffects; - private Dictionary m_featureEffects = new Dictionary(); - + private Dictionary m_modifyOperations = + new Dictionary(); private ITerrainChannel m_channel; private ITerrainChannel m_revert; private Scene m_scene; private volatile bool m_tainted; private readonly Stack m_undo = new Stack(5); - private String m_InitialTerrain = "pinhead-island"; // If true, send terrain patch updates to clients based on their view distance @@ -136,14 +131,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain { return (updateCount > 0); } + public void SetByXY(int x, int y, bool state) { this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state); } + public bool GetByPatch(int patchX, int patchY) { return updated[patchX, patchY]; } + public void SetByPatch(int patchX, int patchY, bool state) { bool prevState = updated[patchX, patchY]; @@ -153,11 +151,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain updateCount--; updated[patchX, patchY] = state; } + public void SetAll(bool state) { updateCount = 0; - for (int xx = 0; xx < updated.GetLength(0); xx++) - for (int yy = 0; yy < updated.GetLength(1); yy++) + for(int xx = 0; xx < updated.GetLength(0); xx++) + for(int yy = 0; yy < updated.GetLength(1); yy++) updated[xx, yy] = state; if (state) updateCount = updated.GetLength(0) * updated.GetLength(1); @@ -174,9 +173,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) ); } - for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) + for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) { - for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) + for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) { // Only set tainted. The patch bit may be set if the patch was to be sent later. if (terrData.IsTaintedAt(xx, yy, false)) @@ -201,8 +200,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain #region ICommandableModule Members - public ICommander CommandInterface - { + public ICommander CommandInterface { get { return m_commander; } } @@ -230,7 +228,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene = scene; // Install terrain module in the simulator - lock (m_scene) + lock(m_scene) { if (m_scene.Heightmap == null) { @@ -262,7 +260,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain string supportedFilesSeparatorForTileSave = ""; m_supportFileExtensionsForTileSave = ""; - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; supportedFilesSeparator = ", "; @@ -285,7 +283,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void RemoveRegion(Scene scene) { - lock (m_scene) + lock(m_scene) { // remove the commands m_scene.UnregisterModuleCommander(m_commander.Name); @@ -304,13 +302,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain { } - public Type ReplaceableInterface - { + public Type ReplaceableInterface { get { return null; } } - public string Name - { + public string Name { get { return "TerrainModule"; } } @@ -329,11 +325,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// Filename to terrain file. Type is determined by extension. public void LoadFromFile(string filename) { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { - lock (m_scene) + lock(m_scene) { try { @@ -349,20 +345,20 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel = channel; UpdateRevertMap(); } - catch (NotImplementedException) + catch(NotImplementedException) { m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + " parser does not support file loading. (May be save only)"); throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); } - catch (FileNotFoundException) + catch(FileNotFoundException) { m_log.Error( "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); throw new TerrainException( String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); } - catch (ArgumentException e) + catch(ArgumentException e) { m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); throw new TerrainException( @@ -386,7 +382,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { try { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { @@ -396,7 +392,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } } - catch (IOException ioe) + catch(IOException ioe) { m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); } @@ -429,11 +425,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void LoadFromStream(string filename, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement, Stream stream) { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { - lock (m_scene) + lock(m_scene) { try { @@ -441,7 +437,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); UpdateRevertMap(); } - catch (NotImplementedException) + catch(NotImplementedException) { m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + " parser does not support file loading. (May be save only)"); @@ -501,7 +497,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { try { - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { @@ -510,7 +506,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } } - catch (NotImplementedException) + catch(NotImplementedException) { m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); @@ -519,12 +515,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients. // ITerrainModule.TaintTerrain() - public void TaintTerrain () + public void TaintTerrain() { - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { // Set the flags for all clients so the tainted patches will be sent out - foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) + foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) { pups.SetAll(m_scene.Heightmap.GetTerrainData()); } @@ -539,7 +535,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); if (presence != null) { - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { PatchUpdates pups; if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) @@ -572,7 +568,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain return; string[] files = Directory.GetFiles(plugineffectsPath); - foreach (string file in files) + foreach(string file in files) { m_log.Info("Loading effects in " + file); try @@ -580,7 +576,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain Assembly library = Assembly.LoadFrom(file); LoadPlugins(library); } - catch (BadImageFormatException) + catch(BadImageFormatException) { } } @@ -588,7 +584,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void LoadPlugins(Assembly library) { - foreach (Type pluginType in library.GetTypes()) + foreach(Type pluginType in library.GetTypes()) { try { @@ -610,7 +606,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_log.Info("L ... " + typeName); } } - catch (AmbiguousMatchException) + catch(AmbiguousMatchException) { } } @@ -618,7 +614,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void InstallPlugin(string pluginName, ITerrainEffect effect) { - lock (m_plugineffects) + lock(m_plugineffects) { if (!m_plugineffects.ContainsKey(pluginName)) { @@ -664,6 +660,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Terrain Feature effects m_featureEffects["rectangle"] = new RectangleFeature(this); + // Terrain Modifier operations + m_modifyOperations["min"] = new MinModifier(this); + m_modifyOperations["max"] = new MaxModifier(this); + m_modifyOperations["raise"] = new RaiseModifier(this); + m_modifyOperations["lower"] = new LowerModifier(this); + m_modifyOperations["fill"] = new FillModifier(this); + m_modifyOperations["smooth"] = new SmoothModifier(this); + // Filesystem load/save loaders m_loaders[".r32"] = new RAW32(); m_loaders[".f32"] = m_loaders[".r32"]; @@ -707,22 +711,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// Where to begin our slice public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) { - int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX; - int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY; + int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX; + int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY; if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) { // this region is included in the tile request - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key)) { - lock (m_scene) + lock(m_scene) { ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, fileWidth, fileHeight, - (int) m_scene.RegionInfo.RegionSizeX, - (int) m_scene.RegionInfo.RegionSizeY); + (int)m_scene.RegionInfo.RegionSizeX, + (int)m_scene.RegionInfo.RegionSizeY); m_scene.Heightmap = channel; m_channel = channel; UpdateRevertMap(); @@ -761,11 +765,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain } // this region is included in the tile request - foreach (KeyValuePair loader in m_loaders) + foreach(KeyValuePair loader in m_loaders) { if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) { - lock (m_scene) + lock(m_scene) { loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, fileWidth, fileHeight, @@ -799,9 +803,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain TerrainData terrData = m_channel.GetTerrainData(); bool shouldTaint = false; - for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) + for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) { - for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) + for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) { if (terrData.IsTaintedAt(x, y)) { @@ -856,7 +860,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain string[] tmpArgs = new string[args.Length - 2]; int i; - for (i = 2; i < args.Length; i++) + for(i = 2; i < args.Length; i++) tmpArgs[i - 2] = args[i]; m_commander.ProcessConsoleCommand(args[1], tmpArgs); @@ -890,7 +894,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; } - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) m_perClientPatchUpdates.Remove(client); } @@ -904,12 +908,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain TerrainData terrData = m_channel.GetTerrainData(); bool wasLimited = false; - for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) + for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) { - for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) + for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) { if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) - { + { // If we should respect the estate settings then // fixup and height deltas that don't respect them. // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. @@ -933,9 +937,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain // loop through the height map for this patch and compare it against // the revert map - for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) + for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) { - for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) + for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) { float requestedHeight = terrData[x, y]; float bakedHeight = (float)m_revert[x, y]; @@ -959,7 +963,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void client_OnLandUndo(IClientAPI client) { - lock (m_undo) + lock(m_undo) { if (m_undo.Count > 0) { @@ -981,19 +985,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (m_sendTerrainUpdatesByViewDistance) { // Add that this patch needs to be sent to the accounting for each client. - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { m_scene.ForEachScenePresence(presence => + { + PatchUpdates thisClientUpdates; + if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) { - PatchUpdates thisClientUpdates; - if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) - { - // There is a ScenePresence without a send patch map. Create one. - thisClientUpdates = new PatchUpdates(terrData, presence); - m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); - } - thisClientUpdates.SetByXY(x, y, true); + // There is a ScenePresence without a send patch map. Create one. + thisClientUpdates = new PatchUpdates(terrData, presence); + m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); } + thisClientUpdates.SetByXY(x, y, true); + } ); } } @@ -1005,11 +1009,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain float[] heightMap = new float[10]; m_scene.ForEachClient( delegate(IClientAPI controller) - { - controller.SendLayerData(x / Constants.TerrainPatchSize, + { + controller.SendLayerData(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, heightMap); - } + } ); } } @@ -1019,12 +1023,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain public int PatchX; public int PatchY; public float Dist; + public PatchesToSend(int pX, int pY, float pDist) { PatchX = pX; PatchY = pY; Dist = pDist; } + public int CompareTo(PatchesToSend other) { return Dist.CompareTo(other.Dist); @@ -1036,9 +1042,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Loop through all the per-client info and send any patches necessary. private void CheckSendingPatchesToClients() { - lock (m_perClientPatchUpdates) + lock(m_perClientPatchUpdates) { - foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) + foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) { if (pups.HasUpdates()) { @@ -1062,7 +1068,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain int[] yPieces = new int[toSend.Count]; float[] patchPieces = new float[toSend.Count * 2]; int pieceIndex = 0; - foreach (PatchesToSend pts in toSend) + foreach(PatchesToSend pts in toSend) { patchPieces[pieceIndex++] = pts.PatchX; patchPieces[pieceIndex++] = pts.PatchY; @@ -1083,25 +1089,25 @@ namespace OpenSim.Region.CoreModules.World.Terrain return ret; // Compute the area of patches within our draw distance - int startX = (((int) (presence.AbsolutePosition.X - presence.DrawDistance))/Constants.TerrainPatchSize) - 2; + int startX = (((int)(presence.AbsolutePosition.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; startX = Math.Max(startX, 0); - startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); - int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2; + startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); + int startY = (((int)(presence.AbsolutePosition.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; startY = Math.Max(startY, 0); - startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize); - int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; + startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); + int endX = (((int)(presence.AbsolutePosition.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; endX = Math.Max(endX, 0); - endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); - int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; + endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); + int endY = (((int)(presence.AbsolutePosition.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; endY = Math.Max(endY, 0); - endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize); + endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>", // LogHeader, m_scene.RegionInfo.RegionName, // presence.DrawDistance, presence.AbsolutePosition, // startX, startY, endX, endY); - for (int x = startX; x < endX; x++) + for(int x = startX; x < endX; x++) { - for (int y = startY; y < endY; y++) + for(int y = startY; y < endY; y++) { //Need to make sure we don't send the same ones over and over Vector3 presencePos = presence.AbsolutePosition; @@ -1133,28 +1139,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain bool allowed = false; if (north == south && east == west) { - if (m_painteffects.ContainsKey((StandardTerrainEffects) action)) + if (m_painteffects.ContainsKey((StandardTerrainEffects)action)) { - bool[,] allowMask = new bool[m_channel.Width,m_channel.Height]; + bool[,] allowMask = new bool[m_channel.Width, m_channel.Height]; allowMask.Initialize(); int n = size + 1; if (n > 2) n = 4; - int zx = (int) (west + 0.5); - int zy = (int) (north + 0.5); + int zx = (int)(west + 0.5); + int zy = (int)(north + 0.5); int dx; - for (dx=-n; dx<=n; dx++) + for(dx=-n; dx<=n; dx++) { int dy; - for (dy=-n; dy<=n; dy++) + for(dy=-n; dy<=n; dy++) { int x = zx + dx; int y = zy + dy; - if (x>=0 && y>=0 && x= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height) { - if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) + if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) { allowMask[x, y] = true; allowed = true; @@ -1165,7 +1171,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (allowed) { StoreUndoState(); - m_painteffects[(StandardTerrainEffects) action].PaintEffect( + m_painteffects[(StandardTerrainEffects)action].PaintEffect( m_channel, allowMask, west, south, height, size, seconds); //revert changes outside estate limits @@ -1180,22 +1186,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain } else { - if (m_floodeffects.ContainsKey((StandardTerrainEffects) action)) + if (m_floodeffects.ContainsKey((StandardTerrainEffects)action)) { - bool[,] fillArea = new bool[m_channel.Width,m_channel.Height]; + bool[,] fillArea = new bool[m_channel.Width, m_channel.Height]; fillArea.Initialize(); int x; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { int y; - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { if (x < east && x > west) { if (y < north && y > south) { - if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) + if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) { fillArea[x, y] = true; allowed = true; @@ -1208,7 +1214,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (allowed) { StoreUndoState(); - m_floodeffects[(StandardTerrainEffects) action].FloodEffect(m_channel, fillArea, size); + m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size); //revert changes outside estate limits if (!god) @@ -1243,7 +1249,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void StoreUndoState() { - lock (m_undo) + lock(m_undo) { if (m_undo.Count > 0) { @@ -1264,21 +1270,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceLoadFile(Object[] args) { - LoadFromFile((string) args[0]); + LoadFromFile((string)args[0]); } private void InterfaceLoadTileFile(Object[] args) { - LoadFromFile((string) args[0], - (int) args[1], - (int) args[2], - (int) args[3], - (int) args[4]); + LoadFromFile((string)args[0], + (int)args[1], + (int)args[2], + (int)args[3], + (int)args[4]); } private void InterfaceSaveFile(Object[] args) { - SaveToFile((string) args[0]); + SaveToFile((string)args[0]); } private void InterfaceSaveTileFile(Object[] args) @@ -1298,8 +1304,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceRevertTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) m_channel[x, y] = m_revert[x, y]; } @@ -1310,9 +1316,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (direction.ToLower().StartsWith("y")) { - for (int x = 0; x < m_channel.Width; x++) + for(int x = 0; x < m_channel.Width; x++) { - for (int y = 0; y < m_channel.Height / 2; y++) + for(int y = 0; y < m_channel.Height / 2; y++) { double height = m_channel[x, y]; double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; @@ -1324,9 +1330,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain } else if (direction.ToLower().StartsWith("x")) { - for (int y = 0; y < m_channel.Height; y++) + for(int y = 0; y < m_channel.Height; y++) { - for (int x = 0; x < m_channel.Width / 2; x++) + for(int x = 0; x < m_channel.Width / 2; x++) { double height = m_channel[x, y]; double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; @@ -1365,9 +1371,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain int width = m_channel.Width; int height = m_channel.Height; - for (int x = 0; x < width; x++) + for(int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) + for(int y = 0; y < height; y++) { double currHeight = m_channel[x, y]; if (currHeight < currMin) @@ -1388,12 +1394,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain //m_log.InfoFormat("Scale = {0}", scale); // scale the heightmap accordingly - for (int x = 0; x < width; x++) + for(int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) + for(int y = 0; y < height; y++) { - double currHeight = m_channel[x, y] - currMin; - m_channel[x, y] = desiredMin + (currHeight * scale); + double currHeight = m_channel[x, y] - currMin; + m_channel[x, y] = desiredMin + (currHeight * scale); } } @@ -1404,42 +1410,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceElevateTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] += (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] += (double)args[0]; } private void InterfaceMultiplyTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] *= (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] *= (double)args[0]; } private void InterfaceLowerTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] -= (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] -= (double)args[0]; } public void InterfaceFillTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) - for (y = 0; y < m_channel.Height; y++) - m_channel[x, y] = (double) args[0]; + for(x = 0; x < m_channel.Width; x++) + for(y = 0; y < m_channel.Height; y++) + m_channel[x, y] = (double)args[0]; } private void InterfaceMinTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); } @@ -1449,9 +1455,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceMaxTerrain(Object[] args) { int x, y; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); } @@ -1480,10 +1486,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain double sum = 0; int x; - for (x = 0; x < m_channel.Width; x++) + for(x = 0; x < m_channel.Width; x++) { int y; - for (y = 0; y < m_channel.Height; y++) + for(y = 0; y < m_channel.Height; y++) { sum += m_channel[x, y]; if (max < m_channel[x, y]) @@ -1501,7 +1507,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void InterfaceEnableExperimentalBrushes(Object[] args) { - if ((bool) args[0]) + if ((bool)args[0]) { m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); @@ -1520,7 +1526,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (firstArg == "list") { MainConsole.Instance.Output("List of loaded plugins"); - foreach (KeyValuePair kvp in m_plugineffects) + foreach(KeyValuePair kvp in m_plugineffects) { MainConsole.Instance.Output(kvp.Key); } @@ -1668,6 +1674,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Add Feature command to Scene, since Command object requires fixed-length arglists m_scene.AddCommand("Terrain", this, "terrain feature", "terrain feature ", "Constructs a feature of the requested type.", FeatureCommand); + // Add Modify command to Scene, since Command object requires fixed-length arglists + m_scene.AddCommand("Terrain", this, "terrain modify", + "terrain modify [] []", + "Modifies the terrain as instructed." + + "\nEach operation can be limited to an area of effect:" + + "\n * -ell=x,y,rx[,ry] constrains the operation to an ellipse centred at x,y" + + "\n * -rec=x,y,dx[,dy] constrains the operation to a rectangle based at x,y" + + "\nEach operation can have its effect tapered based on distance from centre:" + + "\n * elliptical operations taper as cones" + + "\n * rectangular operations taper as pyramids" + , + ModifyCommand); } @@ -1683,7 +1701,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain { result = String.Format("Terrain Feature \"{0}\" not found.", featureType); } - else if ((cmd.Length > 3) && (cmd[3] == "usage")) + else if ((cmd.Length > 3) && (cmd[3] == "usage")) { result = "Usage: " + feature.GetUsage(); } @@ -1692,7 +1710,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain result = feature.CreateFeature(m_channel, cmd); } - if(result == String.Empty) + if (result == String.Empty) { result = "Created Feature"; m_log.DebugFormat("Created terrain feature {0}", featureType); @@ -1704,7 +1722,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain } MainConsole.Instance.Output(result); } - #endregion + + public void ModifyCommand(string module, string[] cmd) + { + string result; + if (cmd.Length > 2) + { + string operationType = cmd[2]; + + ITerrainModifier operation; + if (!m_modifyOperations.TryGetValue(operationType, out operation)) + { + result = String.Format("Terrain Modify \"{0}\" not found.", operationType); + } + else if ((cmd.Length > 3) && (cmd[3] == "usage")) + { + result = "Usage: " + operation.GetUsage(); + } + else + { + result = operation.ModifyTerrain(m_channel, cmd); + } + + if (result == String.Empty) + { + result = "Modified terrain"; + m_log.DebugFormat("Performed terrain operation {0}", operationType); + } + } + else + { + result = "Usage: ..."; + } + MainConsole.Instance.Output(result); + } + +#endregion } } -- cgit v1.1 From a9dd3028b94b35fb9c504b05466522cd2f9be306 Mon Sep 17 00:00:00 2001 From: Dev Random Date: Thu, 7 May 2015 13:25:36 -0400 Subject: Add 'terrain modify noise' and code cleanup Signed-off-by: Michael Cerquoni --- .../World/Terrain/Features/RectangleFeature.cs | 149 --------------------- .../World/Terrain/Modifiers/NoiseModifier.cs | 110 +++++++++++++++ .../World/Terrain/Modifiers/SmoothModifier.cs | 4 +- .../CoreModules/World/Terrain/TerrainFeature.cs | 89 ------------ .../CoreModules/World/Terrain/TerrainModule.cs | 52 +------ 5 files changed, 113 insertions(+), 291 deletions(-) delete mode 100644 OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs create mode 100644 OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs delete mode 100644 OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs deleted file mode 100644 index 33c3fbe..0000000 --- a/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs +++ /dev/null @@ -1,149 +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 OpenSim.Region.CoreModules.World.Terrain; -using OpenSim.Region.Framework.Interfaces; - -namespace OpenSim.Region.CoreModules.World.Terrain.Features -{ - public class RectangleFeature : TerrainFeature - { - public RectangleFeature(ITerrainModule module) : base(module) - { - } - - public override string CreateFeature(ITerrainChannel map, string[] args) - { - string val; - string result; - if (args.Length < 7) - { - result = "Usage: " + GetUsage(); - } - else - { - result = String.Empty; - - float targetElevation; - val = base.parseFloat(args[3], out targetElevation); - if (val != String.Empty) - { - result = val; - } - - int xOrigin; - val = base.parseInt(args[4], out xOrigin); - if (val != String.Empty) - { - result = val; - } - else if (xOrigin < 0 || xOrigin >= map.Width) - { - result = "x-origin must be within the region"; - } - - int yOrigin; - val = base.parseInt(args[5], out yOrigin); - if (val != String.Empty) - { - result = val; - } - else if (yOrigin < 0 || yOrigin >= map.Height) - { - result = "y-origin must be within the region"; - } - - int xDelta; - val = base.parseInt(args[6], out xDelta); - if (val != String.Empty) - { - result = val; - } - else if (xDelta <= 0) - { - result = "x-size must be greater than zero"; - } - - int yDelta; - if (args.Length > 7) - { - val = base.parseInt(args[7], out yDelta); - if (val != String.Empty) - { - result = val; - } - else if (yDelta <= 0) - { - result = "y-size must be greater than zero"; - } - } - else - { - // no y-size.. make it square - yDelta = xDelta; - } - - // slightly more complex validation, if required. - if (result == String.Empty) - { - if (xOrigin + xDelta > map.Width) - { - result = "(x-origin + x-size) must be within the region size"; - } - else if (yOrigin + yDelta > map.Height) - { - result = "(y-origin + y-size) must be within the region size"; - } - } - - // if it's all good, then do the work - if (result == String.Empty) - { - int yPos = yOrigin + yDelta; - while(--yPos >= yOrigin) - { - int xPos = xOrigin + xDelta; - while(--xPos >= xOrigin) - { - map[xPos, yPos] = (double)targetElevation; - } - } - } - } - - return result; - } - - public override string GetUsage() - { - return "rectangle []"; - } - } - -} - diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs new file mode 100644 index 0000000..b31bab1 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs @@ -0,0 +1,110 @@ +/* + * 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 OpenSim.Region.CoreModules.World.Terrain; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers +{ + public class NoiseModifier : TerrainModifier + { + public NoiseModifier(ITerrainModule module) : base(module) + { + } + + public override string ModifyTerrain(ITerrainChannel map, string[] args) + { + string val; + string result; + if (args.Length < 3) + { + result = "Usage: " + GetUsage(); + } + else + { + TerrainModifierData data; + result = this.parseParameters(args, out data); + + // Context-specific validation + if (result == String.Empty) + { + if (data.bevel == "taper") + { + if (data.bevelevation < 0.0 || data.bevelevation > 1.0) + { + result = String.Format("Taper must be 0.0 to 1.0: {0}", data.bevelevation); + } + } + else + { + data.bevelevation = 1.0f; + } + + if (data.elevation < 0.0 || data.elevation > 1.0) + { + result = String.Format("Noise strength must be 0.0 to 1.0: {0}", data.elevation); + } + + if (data.shape == String.Empty) + { + data.shape = "rectangle"; + data.x0 = 0; + data.y0 = 0; + data.dx = map.Width; + data.dy = map.Height; + } + } + + // if it's all good, then do the work + if (result == String.Empty) + { + this.applyModification(map, data); + } + } + + return result; + } + + public override string GetUsage() + { + string val = "noise [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=]" + + "\nAdds noise to all points within the specified range."; + return val; + } + + public override double operate(double[,] map, TerrainModifierData data, int x, int y) + { + double factor = this.computeBevel(data, x, y); + double noise = TerrainUtil.PerlinNoise2D((double)x / map.GetLength(0), (double)y / map.GetLength(1), 8, 1.0); + return map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor) * (noise - .5); + } + + } + +} + diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs index 1731cd8..72b172c 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs @@ -56,7 +56,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers { if (data.bevelevation < 0.01 || data.bevelevation > 0.99) { - result = String.Format("Taper must be 0.01 to 0.99 {0}", data.bevelevation); + result = String.Format("Taper must be 0.01 to 0.99: {0}", data.bevelevation); } } else @@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers if (data.elevation < 0.0 || data.elevation > 1.0) { - result = String.Format("Scaling factor must be 0.0 to 1.0: {0}", data.elevation); + result = String.Format("Smoothing strength must be 0.0 to 1.0: {0}", data.elevation); } if (data.shape == String.Empty) diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs deleted file mode 100644 index 701a729..0000000 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs +++ /dev/null @@ -1,89 +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.Reflection; - -using OpenSim.Region.Framework.Interfaces; - -namespace OpenSim.Region.CoreModules.World.Terrain -{ - public abstract class TerrainFeature : ITerrainFeature - { - protected ITerrainModule m_module; - - protected TerrainFeature(ITerrainModule module) - { - m_module = module; - } - - public abstract string CreateFeature(ITerrainChannel map, string[] args); - - public abstract string GetUsage(); - - protected string parseFloat(String s, out float f) - { - string result; - double d; - if (Double.TryParse(s, out d)) - { - try - { - f = (float)d; - result = String.Empty; - } - catch(InvalidCastException) - { - result = String.Format("{0} is invalid", s); - f = -1.0f; - } - } - else - { - f = -1.0f; - result = String.Format("{0} is invalid", s); - } - return result; - } - - protected string parseInt(String s, out int i) - { - string result; - if (Int32.TryParse(s, out i)) - { - result = String.Empty; - } - else - { - result = String.Format("{0} is invalid", s); - } - return result; - } - - } - -} - diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 02f21b9..05c5fca 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -41,7 +41,6 @@ using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; -using OpenSim.Region.CoreModules.World.Terrain.Features; using OpenSim.Region.CoreModules.World.Terrain.Modifiers; using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; @@ -75,14 +74,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain #endregion - /// - /// Terrain Features - /// - public enum TerrainFeatures: byte - { - Rectangle = 1, - } - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); #pragma warning disable 414 @@ -96,8 +87,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain private readonly Dictionary m_painteffects = new Dictionary(); private Dictionary m_plugineffects; - private Dictionary m_featureEffects = - new Dictionary(); private Dictionary m_modifyOperations = new Dictionary(); private ITerrainChannel m_channel; @@ -657,9 +646,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); - // Terrain Feature effects - m_featureEffects["rectangle"] = new RectangleFeature(this); - // Terrain Modifier operations m_modifyOperations["min"] = new MinModifier(this); m_modifyOperations["max"] = new MaxModifier(this); @@ -667,6 +653,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_modifyOperations["lower"] = new LowerModifier(this); m_modifyOperations["fill"] = new FillModifier(this); m_modifyOperations["smooth"] = new SmoothModifier(this); + m_modifyOperations["noise"] = new NoiseModifier(this); // Filesystem load/save loaders m_loaders[".r32"] = new RAW32(); @@ -1671,9 +1658,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain // Add this to our scene so scripts can call these functions m_scene.RegisterModuleCommander(m_commander); - // Add Feature command to Scene, since Command object requires fixed-length arglists - m_scene.AddCommand("Terrain", this, "terrain feature", - "terrain feature ", "Constructs a feature of the requested type.", FeatureCommand); // Add Modify command to Scene, since Command object requires fixed-length arglists m_scene.AddCommand("Terrain", this, "terrain modify", "terrain modify [] []", @@ -1689,40 +1673,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain } - public void FeatureCommand(string module, string[] cmd) - { - string result; - if (cmd.Length > 2) - { - string featureType = cmd[2]; - - ITerrainFeature feature; - if (!m_featureEffects.TryGetValue(featureType, out feature)) - { - result = String.Format("Terrain Feature \"{0}\" not found.", featureType); - } - else if ((cmd.Length > 3) && (cmd[3] == "usage")) - { - result = "Usage: " + feature.GetUsage(); - } - else - { - result = feature.CreateFeature(m_channel, cmd); - } - - if (result == String.Empty) - { - result = "Created Feature"; - m_log.DebugFormat("Created terrain feature {0}", featureType); - } - } - else - { - result = "Usage: ..."; - } - MainConsole.Instance.Output(result); - } - public void ModifyCommand(string module, string[] cmd) { string result; -- cgit v1.1 From dc4c9b1bb0c3b3ac628135450776a2854d5014e5 Mon Sep 17 00:00:00 2001 From: Michael Cerquoni Date: Thu, 7 May 2015 14:09:29 -0400 Subject: Minor whitespace removal --- OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs index b31bab1..53a64df 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs @@ -107,4 +107,3 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers } } - -- cgit v1.1 From c74cef0f4261191962959e42c7e349adafd42a04 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 7 May 2015 19:24:08 -0700 Subject: Major change in the way inventory is downloaded: added a method throughout IIventoryService that fetches sets of folders at once. Also added folder id in the InventoryCollection data structure, so that we don't need to go to inventory server again just for that. This reduces the chatter between sims and inventory server by... a lot. On my tests, this reduces initial inventory download down to 30% of what it currently is. --- .../ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 6 +++++- .../Framework/Library/LocalInventoryService.cs | 14 +++++++++++++- .../Inventory/HGInventoryBroker.cs | 19 +++++++++++++++++++ .../ServiceConnectorsOut/Inventory/InventoryCache.cs | 2 +- .../Inventory/LocalInventoryServiceConnector.cs | 13 +++++++++++++ .../Inventory/RemoteXInventoryServiceConnector.cs | 5 +++++ 6 files changed, 56 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index e402b0b..30d1921 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -201,7 +201,7 @@ namespace OpenSim.Region.ClientStack.Linden Scene.EventManager.OnRegisterCaps += RegisterCaps; - int nworkers = 1; // was 2 + int nworkers = 2; // was 2 if (ProcessQueuedRequestsAsync && m_workerThreads == null) { m_workerThreads = new Thread[nworkers]; @@ -365,7 +365,11 @@ namespace OpenSim.Region.ClientStack.Linden requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); lock (responses) + { + if (responses.ContainsKey(requestID)) + m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); responses[requestID] = response; + } WebFetchInvDescModule.ProcessedRequestsCount++; } diff --git a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs index 01814a1..eb7d3a9 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs @@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library { InventoryFolderImpl folder = null; InventoryCollection inv = new InventoryCollection(); - inv.UserID = m_Library.Owner; + inv.OwnerID = m_Library.Owner; if (folderID != m_Library.ID) { @@ -87,6 +87,18 @@ namespace OpenSim.Region.CoreModules.Framework.Library return inv; } + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length]; + int i = 0; + foreach (UUID fid in folderIDs) + { + invColl[i++] = GetFolderContent(principalID, fid); + } + + return invColl; + } + /// /// Add a new folder to the user's inventory /// diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index e13ee42..232cfdf 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs @@ -389,6 +389,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.GetFolderContent(userID, folderID); } + public InventoryCollection[] GetMultipleFoldersContent(UUID userID, UUID[] folderIDs) + { + string invURL = GetInventoryServiceURL(userID); + + if (invURL == null) // not there, forward to local inventory connector to resolve + lock (m_Lock) + return m_LocalGridInventoryService.GetMultipleFoldersContent(userID, folderIDs); + + else + { + InventoryCollection[] coll = new InventoryCollection[folderIDs.Length]; + int i = 0; + foreach (UUID fid in folderIDs) + coll[i++] = GetFolderContent(userID, fid); + + return coll; + } + } + public List GetFolderItems(UUID userID, UUID folderID) { //m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolderItems " + folderID); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs index 499ca5e..71dc337 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs @@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory if (m_Inventories.TryGetValue(userID, out inv)) { c = new InventoryCollection(); - c.UserID = userID; + c.OwnerID = userID; c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f) { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index cbe0e37..75dd200 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -195,6 +195,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return invCol; } + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length]; + int i = 0; + foreach (UUID fid in folderIDs) + { + invColl[i++] = GetFolderContent(principalID, fid); + } + + return invColl; + + } + public List GetFolderItems(UUID userID, UUID folderID) { return m_InventoryService.GetFolderItems(userID, folderID); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 166e4a1..9beb382 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -204,6 +204,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return invCol; } + public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) + { + return m_RemoteConnector.GetMultipleFoldersContent(principalID, folderIDs); + } + public List GetFolderItems(UUID userID, UUID folderID) { return m_RemoteConnector.GetFolderItems(userID, folderID); -- cgit v1.1 From 0bf1209f908bb9a384ddb3a4255a75bf2317c478 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 8 May 2015 20:53:28 -0700 Subject: Another major overhaul of inventory downloading, this time pertaining to inventory links. Added yet another function to IInventoryService to get multiple items at once, so that fetching collections of linked items is done once per folder instead of once per item. --- .../Framework/Library/LocalInventoryService.cs | 16 ++++++++++++++++ .../ServiceConnectorsOut/Inventory/HGInventoryBroker.cs | 17 +++++++++++++++++ .../Inventory/LocalInventoryServiceConnector.cs | 5 +++++ .../Inventory/RemoteXInventoryServiceConnector.cs | 8 ++++++++ 4 files changed, 46 insertions(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs index eb7d3a9..e657f53 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs @@ -99,6 +99,22 @@ namespace OpenSim.Region.CoreModules.Framework.Library return invColl; } + public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs) + { + InventoryItemBase[] itemColl = new InventoryItemBase[itemIDs.Length]; + int i = 0; + InventoryItemBase item = new InventoryItemBase(); + item.Owner = principalID; + foreach (UUID fid in itemIDs) + { + item.ID = fid; + itemColl[i++] = GetItem(item); + } + + return itemColl; + } + + /// /// Add a new folder to the user's inventory /// diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index 232cfdf..6a83b42 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs @@ -615,6 +615,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.GetItem(item); } + public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) + { + if (itemIDs == null) + return new InventoryItemBase[0]; + //m_log.Debug("[HG INVENTORY CONNECTOR]: GetItem " + item.ID); + + string invURL = GetInventoryServiceURL(userID); + + if (invURL == null) // not there, forward to local inventory connector to resolve + lock (m_Lock) + return m_LocalGridInventoryService.GetMultipleItems(userID, itemIDs); + + IInventoryService connector = GetConnector(invURL); + + return connector.GetMultipleItems(userID, itemIDs); + } + public InventoryFolderBase GetFolder(InventoryFolderBase folder) { if (folder == null) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index 75dd200..2f29a7c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -307,6 +307,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return item; } + public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) + { + return m_InventoryService.GetMultipleItems(userID, itemIDs); + } + public InventoryFolderBase GetFolder(InventoryFolderBase folder) { return m_InventoryService.GetFolder(folder); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 9beb382..e0cc1e8 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -303,6 +303,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return m_RemoteConnector.GetItem(item); } + public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) + { + if (itemIDs == null) + return new InventoryItemBase[0]; + + return m_RemoteConnector.GetMultipleItems(userID, itemIDs); + } + public InventoryFolderBase GetFolder(InventoryFolderBase folder) { //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID); -- cgit v1.1 From f20728fc86accb4df56024e587e8d5762a8dda34 Mon Sep 17 00:00:00 2001 From: Dev Random Date: Sat, 9 May 2015 15:26:34 -0400 Subject: Constrain 'terrain modify' to selected Region Signed-off-by: Michael Cerquoni --- .../CoreModules/World/Terrain/TerrainModule.cs | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 05c5fca..cec17e2 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -551,11 +551,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_plugineffects = new Dictionary(); LoadPlugins(Assembly.GetCallingAssembly()); string plugineffectsPath = "Terrain"; - + // Load the files in the Terrain/ dir if (!Directory.Exists(plugineffectsPath)) return; - + string[] files = Directory.GetFiles(plugineffectsPath); foreach(string file in files) { @@ -768,7 +768,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, m_scene.RegionInfo.RegionName, filename); } - + return; } } @@ -865,7 +865,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain client.OnLandUndo += client_OnLandUndo; client.OnUnackedTerrain += client_OnUnackedTerrain; } - + /// /// Installs terrain brush hook to IClientAPI /// @@ -884,7 +884,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain lock(m_perClientPatchUpdates) m_perClientPatchUpdates.Remove(client); } - + /// /// Scan over changes in the terrain and limit height changes. This enforces the /// non-estate owner limits on rate of terrain editting. @@ -1225,7 +1225,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter } } - + protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) { //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); @@ -1676,10 +1676,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain public void ModifyCommand(string module, string[] cmd) { string result; - if (cmd.Length > 2) + Scene scene = SceneManager.Instance.CurrentScene; + if ((scene != null) && (scene != m_scene)) + { + result = String.Empty; + } + else if (cmd.Length > 2) { string operationType = cmd[2]; + ITerrainModifier operation; if (!m_modifyOperations.TryGetValue(operationType, out operation)) { @@ -1704,7 +1710,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain { result = "Usage: ..."; } - MainConsole.Instance.Output(result); + if (result != String.Empty) + { + MainConsole.Instance.Output(result); + } } #endregion -- cgit v1.1 From 3c596e47c6322ef608233fb45624c2f26fa6b5f0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 10 May 2015 21:54:24 -0700 Subject: Knocked off a few compiler warnings regarding unused variables. --- OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs | 1 - OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs | 1 - OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs | 1 - OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs | 1 - OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs | 1 - OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs | 1 - OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs | 1 - 7 files changed, 7 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs index 0df7132..32f1de9 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs @@ -40,7 +40,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers public override string ModifyTerrain(ITerrainChannel map, string[] args) { - string val; string result; if (args.Length < 3) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs index 3e4a457..2ab4bcc 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs @@ -38,7 +38,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers public override string ModifyTerrain(ITerrainChannel map, string[] args) { - string val; string result; if (args.Length < 3) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs index 02f1852..0939c0a 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs @@ -38,7 +38,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers public override string ModifyTerrain(ITerrainChannel map, string[] args) { - string val; string result; if (args.Length < 3) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs index 2db49c8..cbbccc0 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs @@ -38,7 +38,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers public override string ModifyTerrain(ITerrainChannel map, string[] args) { - string val; string result; if (args.Length < 3) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs index 53a64df..d6b95d0 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs @@ -39,7 +39,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers public override string ModifyTerrain(ITerrainChannel map, string[] args) { - string val; string result; if (args.Length < 3) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs index 9ac1edd..35fb9d6 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs @@ -38,7 +38,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers public override string ModifyTerrain(ITerrainChannel map, string[] args) { - string val; string result; if (args.Length < 3) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs index 72b172c..9f8d5b2 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs @@ -38,7 +38,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers public override string ModifyTerrain(ITerrainChannel map, string[] args) { - string val; string result; if (args.Length < 3) { -- cgit v1.1 From d348f871612c5f241f33885604391d1f30a416bc Mon Sep 17 00:00:00 2001 From: Magnuz Binder Date: Sun, 10 May 2015 20:01:50 +0200 Subject: Patch llCastRay fully simplified to V3. --- .../Shared/Api/Implementation/LSL_Api.cs | 429 +++++++++++---------- 1 file changed, 217 insertions(+), 212 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c90f015..089a5a8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -221,15 +221,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected float m_primSafetyCoeffX = 2.414214f; protected float m_primSafetyCoeffY = 2.414214f; protected float m_primSafetyCoeffZ = 1.618034f; + protected bool m_useCastRayV3 = false; protected float m_floatToleranceInCastRay = 0.000001f; protected float m_floatTolerance2InCastRay = 0.0001f; + protected DetailLevel m_primLodInCastRay = DetailLevel.Medium; + protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium; + protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest; + protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium; protected int m_maxHitsInCastRay = 16; protected int m_maxHitsPerPrimInCastRay = 16; protected int m_maxHitsPerObjectInCastRay = 16; protected bool m_detectExitsInCastRay = false; protected bool m_filterPartsInCastRay = false; protected bool m_doAttachmentsInCastRay = false; - protected bool m_useCastRayV1 = true; //An array of HTTP/1.1 headers that are not allowed to be used //as custom headers by llHTTPRequest. @@ -336,15 +340,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); + m_useCastRayV3 = lslConfig.GetBoolean("UseLlCastRayV3", m_useCastRayV3); m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); + m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay); + m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay); + m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay); + m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay); m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); - m_useCastRayV1 = lslConfig.GetBoolean("UseLlCastRayV1", m_useCastRayV1); } IConfig smtpConfig = seConfigSource.Configs["SMTP"]; @@ -13811,8 +13819,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return contacts[0]; } - public LSL_List llCastRayV1(LSL_Vector start, LSL_Vector end, LSL_List options) + public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) { + // Use llCastRay V3 if configured + if (m_useCastRayV3) + return llCastRayV3(start, end, options); + LSL_List list = new LSL_List(); m_host.AddScriptLPS(1); @@ -14003,29 +14015,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// Full implementation of llCastRay similar to SL 2015-04-21. + /// Implementation of llCastRay similar to SL 2015-04-21. /// http://wiki.secondlife.com/wiki/LlCastRay /// Uses pure geometry, bounding shapes, meshing and no physics /// for prims, sculpts, meshes, avatars and terrain. /// Implements all flags, reject types and data flags. /// Can handle both objects/groups and prims/parts, by config. - /// May give poor results with multi-part meshes where "root" - /// part doesn't dominate, owing to "guessed" bounding boxes. - /// May sometimes be inaccurate owing to calculation precision - /// and a bug in libopenmetaverse PrimMesher. + /// May sometimes be inaccurate owing to calculation precision, + /// meshing detail level and a bug in libopenmetaverse PrimMesher. /// - public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + public LSL_List llCastRayV3(LSL_Vector start, LSL_Vector end, LSL_List options) { - // Use llCastRay v1 if configured - if (m_useCastRayV1) - return llCastRayV1(start, end, options); - // Initialize m_host.AddScriptLPS(1); List rayHits = new List(); LSL_List result = new LSL_List(); float tol = m_floatToleranceInCastRay; - float tol2 = m_floatTolerance2InCastRay; + Vector3 pos1Ray = start; + Vector3 pos2Ray = end; // Get input options int rejectTypes = 0; @@ -14054,25 +14061,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); // Calculate some basic parameters - Vector3 ray = end - start; - float rayLength = ray.Length(); + Vector3 vecRay = pos2Ray - pos1Ray; + float rayLength = vecRay.Length(); - // Try to get a mesher and return failure if none or degenerate ray + // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits IRendering primMesher = null; List renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); - if (renderers.Count < 1 || rayLength < tol) + if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1) { result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); return result; } primMesher = RenderingLoader.LoadRenderer(renderers[0]); - // Used to translate and rotate world so ray is along negative Z axis from origo and - // calculations mostly simplified to a 2D projecttion on the X-Y plane - Vector3 posProj = new Vector3(-start); - Quaternion rotProj = Vector3.RotationBetween(ray, new Vector3(0.0f, 0.0f, -1.0f)); - Quaternion rotBack = Quaternion.Inverse(rotProj); - // Iterate over all objects/groups and prims/parts in region World.ForEachSOG( delegate(SceneObjectGroup group) @@ -14115,51 +14116,51 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!doPart) continue; } - // Parse prim/part if passed filters - // Estimate bounding box from size box - Vector3 scaleSafe = part.Scale; - if (!part.Shape.SculptEntry) - scaleSafe = scaleSafe * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); + // Parse prim/part and project ray if passed filters + Vector3 scalePart = part.Scale; + Vector3 posPart = part.GetWorldPosition(); + Quaternion rotPart = part.GetWorldRotation(); + Quaternion rotPartInv = Quaternion.Inverse(rotPart); + Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; + Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; - // Filter parts by bounding shapes - Vector3 posPartRel = part.GetWorldPosition() + posProj; - Vector3 posPartProj = posPartRel * rotProj; - if (InBoundingShapes(ray, rayLength, scaleSafe, posPartRel, posPartProj, rotProj)) + // Filter parts by shape bounding boxes + Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); + if (!part.Shape.SculptEntry) + shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); + shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); + if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) { // Prepare data needed to check for ray hits RayTrans rayTrans = new RayTrans(); rayTrans.PartId = part.UUID; rayTrans.GroupId = part.ParentGroup.UUID; rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; - rayTrans.Scale = part.Scale; - rayTrans.PositionPartProj = posPartProj; - rayTrans.PositionProj = posProj; - rayTrans.RotationPartProj = rotProj * part.GetWorldRotation(); - rayTrans.RotationBack = rotBack; - rayTrans.NeedsEnds = true; - rayTrans.RayLength = rayLength; - rayTrans.Tolerance = tol; - rayTrans.Tolerance2 = tol2; + rayTrans.ScalePart = scalePart; + rayTrans.PositionPart = posPart; + rayTrans.RotationPart = rotPart; + rayTrans.ShapeNeedsEnds = true; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1RayProj; + rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; // Make an OMV prim to be able to mesh part - Primitive omvPrim = part.Shape.ToOmvPrimitive(posPartProj, rayTrans.RotationPartProj); + Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); byte[] sculptAsset = null; if (omvPrim.Sculpt != null) sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); + FacetedMesh mesh = null; - // When part is mesh, get and check mesh + // When part is mesh, get mesh and check for hits if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) { AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); - FacetedMesh mesh = null; - FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); + FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); meshAsset = null; - AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); - mesh = null; } - // When part is sculpt, create and check mesh + // When part is sculpt, create mesh and check for hits // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) { @@ -14169,15 +14170,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Image sculpt = imgDecoder.DecodeToImage(sculptAsset); if (sculpt != null) { - SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); + mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); sculpt.Dispose(); - AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); - mesh = null; } } } - // When part is prim, create and check mesh + // When part is prim, create mesh and check for hits else if (omvPrim.Sculpt == null) { if ( @@ -14186,12 +14185,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api omvPrim.PrimData.PathSkew == 0.0 && omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 ) - rayTrans.NeedsEnds = false; - SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); - AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); - mesh = null; + rayTrans.ShapeNeedsEnds = false; + mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); } + // Check mesh for ray hits + AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); + mesh = null; } } } @@ -14205,38 +14205,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.ForEachRootScenePresence( delegate (ScenePresence sp) { - // Parse avatar - // Get bounding box Vector3 lower; Vector3 upper; BoundingBoxOfScenePresence(sp, out lower, out upper); - Vector3 scale = upper - lower; - - // Filter avatars by bounding shapes - Vector3 posPartRel = sp.AbsolutePosition + posProj + (lower + upper) * 0.5f * sp.Rotation; - Vector3 posPartProj = posPartRel * rotProj; - if (InBoundingShapes(ray, rayLength, scale, posPartRel, posPartProj, rotProj)) + // Parse avatar + Vector3 scalePart = upper - lower; + Vector3 posPart = sp.AbsolutePosition; + Quaternion rotPart = sp.GetWorldRotation(); + Quaternion rotPartInv = Quaternion.Inverse(rotPart); + posPart = posPart + (lower + upper) * 0.5f * rotPart; + // Project ray + Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; + Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; + + // Filter avatars by shape bounding boxes + Vector3 shapeBoxMax = new Vector3(0.5f + tol, 0.5f + tol, 0.5f + tol); + if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) { // Prepare data needed to check for ray hits RayTrans rayTrans = new RayTrans(); rayTrans.PartId = sp.UUID; rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; - rayTrans.Scale = scale; - rayTrans.PositionPartProj = posPartProj; - rayTrans.PositionProj = posProj; - rayTrans.RotationPartProj = rotProj * sp.Rotation; - rayTrans.RotationBack = rotBack; - rayTrans.NeedsEnds = false; - rayTrans.RayLength = rayLength; - rayTrans.Tolerance = tol; - rayTrans.Tolerance2 = tol2; + rayTrans.ScalePart = scalePart; + rayTrans.PositionPart = posPart; + rayTrans.RotationPart = rotPart; + rayTrans.ShapeNeedsEnds = false; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1RayProj; + rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; // Make OMV prim, create and check mesh - Primitive omvPrim = MakeOpenMetaversePrim(scale, posPartProj, rayTrans.RotationPartProj, ScriptBaseClass.PRIM_TYPE_SPHERE); - SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); - AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); + PrimitiveBaseShape prim = PrimitiveBaseShape.CreateSphere(); + prim.Scale = scalePart; + Primitive omvPrim = prim.ToOmvPrimitive(posPart, rotPart); + FacetedMesh mesh = primMesher.GenerateFacetedMesh(omvPrim, m_meshLodInCastRay); + AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); mesh = null; } } @@ -14248,32 +14253,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // Parse terrain - // Mesh terrain and check projected bounding box - Vector3 posPartProj = posProj * rotProj; - Quaternion rotPartProj = rotProj; + // Mesh terrain and check bounding box Vector3 lower; Vector3 upper; - List triangles = TrisFromHeightmapUnderRay(start, end, out lower, out upper); - Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); - Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); - int dummy = 0; - AddBoundingBoxOfSimpleBox(lower, upper, posPartProj, rotPartProj, true, ref lowerBox, ref upperBox, ref dummy); - if (lowerBox.X <= tol && lowerBox.Y <= tol && lowerBox.Z <= tol && upperBox.X >= -tol && upperBox.Y >= -tol && upperBox.Z >= -rayLength - tol) + List triangles = TrisFromHeightmapUnderRay(pos1Ray, pos2Ray, out lower, out upper); + lower.Z -= tol; + upper.Z += tol; + if ((pos1Ray.Z >= lower.Z || pos2Ray.Z >= lower.Z) && (pos1Ray.Z <= upper.Z || pos2Ray.Z <= upper.Z)) { // Prepare data needed to check for ray hits RayTrans rayTrans = new RayTrans(); rayTrans.PartId = UUID.Zero; rayTrans.GroupId = UUID.Zero; rayTrans.Link = 0; - rayTrans.Scale = new Vector3 (1.0f, 1.0f, 1.0f); - rayTrans.PositionPartProj = posPartProj; - rayTrans.PositionProj = posProj; - rayTrans.RotationPartProj = rotPartProj; - rayTrans.RotationBack = rotBack; - rayTrans.NeedsEnds = true; - rayTrans.RayLength = rayLength; - rayTrans.Tolerance = tol; - rayTrans.Tolerance2 = tol2; + rayTrans.ScalePart = new Vector3 (1.0f, 1.0f, 1.0f); + rayTrans.PositionPart = Vector3.Zero; + rayTrans.RotationPart = Quaternion.Identity; + rayTrans.ShapeNeedsEnds = true; + rayTrans.Position1Ray = pos1Ray; + rayTrans.Position1RayProj = pos1Ray; + rayTrans.VectorRayProj = vecRay; // Check mesh AddRayInTris(triangles, rayTrans, ref rayHits); @@ -14358,15 +14357,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public UUID PartId; public UUID GroupId; public int Link; - public Vector3 Scale; - public Vector3 PositionPartProj; - public Vector3 PositionProj; - public Quaternion RotationPartProj; - public Quaternion RotationBack; - public bool NeedsEnds; - public float RayLength; - public float Tolerance; - public float Tolerance2; + public Vector3 ScalePart; + public Vector3 PositionPart; + public Quaternion RotationPart; + public bool ShapeNeedsEnds; + public Vector3 Position1Ray; + public Vector3 Position1RayProj; + public Vector3 VectorRayProj; } /// @@ -14383,21 +14380,63 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// Helper to parse SimpleMesh for ray hits. + /// Helper to check if a ray intersects a shape bounding box. /// - private void AddRayInSimpleMesh(SimpleMesh mesh, RayTrans rayTrans, ref List rayHits) - { - if (mesh != null) + private bool RayIntersectsShapeBox(Vector3 pos1RayProj, Vector3 pos2RayProj, Vector3 shapeBoxMax) + { + // Skip if ray can't intersect bounding box; + Vector3 rayBoxProjMin = Vector3.Min(pos1RayProj, pos2RayProj); + Vector3 rayBoxProjMax = Vector3.Max(pos1RayProj, pos2RayProj); + if ( + rayBoxProjMin.X > shapeBoxMax.X || rayBoxProjMin.Y > shapeBoxMax.Y || rayBoxProjMin.Z > shapeBoxMax.Z || + rayBoxProjMax.X < -shapeBoxMax.X || rayBoxProjMax.Y < -shapeBoxMax.Y || rayBoxProjMax.Z < -shapeBoxMax.Z + ) + return false; + + // Check if ray intersect any bounding box side + int sign = 0; + float dist = 0.0f; + Vector3 posProj = Vector3.Zero; + Vector3 vecRayProj = pos2RayProj - pos1RayProj; + + // Check both X sides unless ray is parallell to them + if (Math.Abs(vecRayProj.X) > m_floatToleranceInCastRay) + { + for (sign = -1; sign <= 1; sign += 2) + { + dist = ((float)sign * shapeBoxMax.X - pos1RayProj.X) / vecRayProj.X; + posProj = pos1RayProj + vecRayProj * dist; + if (Math.Abs(posProj.Y) <= shapeBoxMax.Y && Math.Abs(posProj.Z) <= shapeBoxMax.Z) + return true; + } + } + + // Check both Y sides unless ray is parallell to them + if (Math.Abs(vecRayProj.Y) > m_floatToleranceInCastRay) { - for (int i = 0; i < mesh.Indices.Count; i += 3) + for (sign = -1; sign <= 1; sign += 2) { - Tri triangle = new Tri(); - triangle.p1 = mesh.Vertices[mesh.Indices[i]].Position; - triangle.p2 = mesh.Vertices[mesh.Indices[i + 1]].Position; - triangle.p3 = mesh.Vertices[mesh.Indices[i + 2]].Position; - AddRayInTri(triangle, rayTrans, ref rayHits); + dist = ((float)sign * shapeBoxMax.Y - pos1RayProj.Y) / vecRayProj.Y; + posProj = pos1RayProj + vecRayProj * dist; + if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Z) <= shapeBoxMax.Z) + return true; } } + + // Check both Z sides unless ray is parallell to them + if (Math.Abs(vecRayProj.Z) > m_floatToleranceInCastRay) + { + for (sign = -1; sign <= 1; sign += 2) + { + dist = ((float)sign * shapeBoxMax.Z - pos1RayProj.Z) / vecRayProj.Z; + posProj = pos1RayProj + vecRayProj * dist; + if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Y) <= shapeBoxMax.Y) + return true; + } + } + + // No hits on bounding box so return false + return false; } /// @@ -14409,7 +14448,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { foreach (Face face in mesh.Faces) { - for (int i = 0; i /// Helper to add ray hit in a Tri (triangle). /// - private void AddRayInTri(Tri triangle, RayTrans rayTrans, ref List rayHits) + private void AddRayInTri(Tri triProj, RayTrans rayTrans, ref List rayHits) { // Check for hit in triangle - float distance; - Vector3 posHit; - Vector3 normal; - if (HitRayInTri(triangle, rayTrans, out distance, out posHit, out normal)) - { - // Project hit part back to normal coordinate system - Vector3 posPart = rayTrans.PositionPartProj * rayTrans.RotationBack - rayTrans.PositionProj; - // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) faces plane through shape center - if (Math.Abs(Vector3.Dot(posPart, normal) - Vector3.Dot(posHit, normal)) < rayTrans.Tolerance && !rayTrans.NeedsEnds) + Vector3 posHitProj; + Vector3 normalProj; + if (HitRayInTri(triProj, rayTrans.Position1RayProj, rayTrans.VectorRayProj, out posHitProj, out normalProj)) + { + // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) face plane through shape center + if (Math.Abs(Vector3.Dot(posHitProj, normalProj)) < m_floatToleranceInCastRay && !rayTrans.ShapeNeedsEnds) return; - // Remove duplicate hits at triangle edges and intersections + + // Transform hit and normal to region coordinate system + Vector3 posHit = rayTrans.PositionPart + (posHitProj * rayTrans.ScalePart) * rayTrans.RotationPart; + Vector3 normal = Vector3.Normalize((normalProj * rayTrans.ScalePart) * rayTrans.RotationPart); + + // Remove duplicate hits at triangle intersections + float distance = Vector3.Distance(rayTrans.Position1Ray, posHit); for (int i = rayHits.Count - 1; i >= 0; i--) { - if (rayHits[i].PartId == rayTrans.PartId && Math.Abs(rayHits[i].Distance - distance) < rayTrans.Tolerance2) + if (rayHits[i].PartId != rayTrans.PartId) + break; + if (Math.Abs(rayHits[i].Distance - distance) < m_floatTolerance2InCastRay) return; } @@ -14468,76 +14512,56 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// Helper to find ray hit in a Tri (triangle). + /// Helper to find ray hit in triangle /// - private bool HitRayInTri(Tri triangle, RayTrans rayTrans, out float distance, out Vector3 posHit, out Vector3 normal) + bool HitRayInTri(Tri triProj, Vector3 pos1RayProj, Vector3 vecRayProj, out Vector3 posHitProj, out Vector3 normalProj) { - // Initialize - distance = 0.0f; - posHit = Vector3.Zero; - normal = Vector3.Zero; - float tol = rayTrans.Tolerance; - - // Project triangle on X-Y plane - Vector3 pos1 = triangle.p1 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; - Vector3 pos2 = triangle.p2 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; - Vector3 pos3 = triangle.p3 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; - - // Check if ray/origo inside triangle bounding rectangle - Vector3 lower = Vector3.Min(pos1, Vector3.Min(pos2, pos3)); - Vector3 upper = Vector3.Max(pos1, Vector3.Max(pos2, pos3)); - if (lower.X > tol || lower.Y > tol || lower.Z > tol || upper.X < -tol || upper.Y < -tol || upper.Z < -rayTrans.RayLength - tol) - return false; + float tol = m_floatToleranceInCastRay; + posHitProj = Vector3.Zero; + + // Calculate triangle edge vectors + Vector3 vec1Proj = triProj.p2 - triProj.p1; + Vector3 vec2Proj = triProj.p3 - triProj.p2; + Vector3 vec3Proj = triProj.p1 - triProj.p3; - // Check if ray/origo inside every edge or reverse "outside" every edge on exit - float dist; - bool inside = true; - bool outside = true; - Vector3 vec1 = pos2 - pos1; - dist = pos1.X * vec1.Y - pos1.Y * vec1.X; - if (dist < -tol) - inside = false; - if (dist > tol) - outside = false; - Vector3 vec2 = pos3 - pos2; - dist = pos2.X * vec2.Y - pos2.Y * vec2.X; - if (dist < -tol) - inside = false; - if (dist > tol) - outside = false; - Vector3 vec3 = pos1 - pos3; - dist = pos3.X * vec3.Y - pos3.Y * vec3.X; - if (dist < -tol) - inside = false; - if (dist > tol) - outside = false; - - // Skip if ray/origo outside - if (!inside && !(outside && m_detectExitsInCastRay)) + // Calculate triangle normal + normalProj = Vector3.Cross(vec1Proj, vec2Proj); + + // Skip if degenerate triangle or ray parallell with triangle plane + float divisor = Vector3.Dot(vecRayProj, normalProj); + if (Math.Abs(divisor) < tol) return false; - // Calculate normal - Vector3 normalProj = Vector3.Cross(vec1, vec2); - float normalLength = normalProj.Length(); - // Skip if degenerate triangle - if (normalLength < tol) + // Skip if exit and not configured to detect + if (divisor > tol && !m_detectExitsInCastRay) return false; - normalProj = normalProj / normalLength; - // Skip if ray parallell to triangle plane - if (Math.Abs(normalProj.Z) < tol) + + // Skip if outside ray ends + float distanceProj = Vector3.Dot(triProj.p1 - pos1RayProj, normalProj) / divisor; + if (distanceProj < -tol || distanceProj > 1 + tol) return false; - // Calculate distance - distance = Vector3.Dot(normalProj, pos2) / normalProj.Z * -1.0f; - // Skip if outside ray - if (distance < -tol || distance > rayTrans.RayLength + tol) + // Calculate hit position in triangle + posHitProj = pos1RayProj + vecRayProj * distanceProj; + + // Skip if outside triangle bounding box + Vector3 triProjMin = Vector3.Min(Vector3.Min(triProj.p1, triProj.p2), triProj.p3); + Vector3 triProjMax = Vector3.Max(Vector3.Max(triProj.p1, triProj.p2), triProj.p3); + if ( + posHitProj.X < triProjMin.X - tol || posHitProj.Y < triProjMin.Y - tol || posHitProj.Z < triProjMin.Z - tol || + posHitProj.X > triProjMax.X + tol || posHitProj.Y > triProjMax.Y + tol || posHitProj.Z > triProjMax.Z + tol + ) return false; - // Calculate projected hit position - Vector3 posHitProj = new Vector3(0.0f, 0.0f, -distance); - // Project hit back to normal coordinate system - posHit = posHitProj * rayTrans.RotationBack - rayTrans.PositionProj; - normal = normalProj * rayTrans.RotationBack; + // Skip if outside triangle + if ( + Vector3.Dot(Vector3.Cross(vec1Proj, normalProj), posHitProj - triProj.p1) > tol || + Vector3.Dot(Vector3.Cross(vec2Proj, normalProj), posHitProj - triProj.p2) > tol || + Vector3.Dot(Vector3.Cross(vec3Proj, normalProj), posHitProj - triProj.p3) > tol + ) + return false; + + // Return hit return true; } @@ -14660,24 +14684,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api y = Util.Clamp(yInt+1, 0, World.Heightmap.Height - 1); Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); // Adjust bounding box - zLower = Math.Min(zLower, pos1.Z); - zUpper = Math.Max(zUpper, pos1.Z); + zLower = Math.Min(zLower, pos2.Z); + zUpper = Math.Max(zUpper, pos2.Z); // Corner 3 of 1x1 rectangle x = Util.Clamp(xInt, 0, World.Heightmap.Width - 1); y = Util.Clamp(yInt, 0, World.Heightmap.Height - 1); Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); // Adjust bounding box - zLower = Math.Min(zLower, pos1.Z); - zUpper = Math.Max(zUpper, pos1.Z); + zLower = Math.Min(zLower, pos3.Z); + zUpper = Math.Max(zUpper, pos3.Z); // Corner 4 of 1x1 rectangle x = Util.Clamp(xInt+1, 0, World.Heightmap.Width - 1); y = Util.Clamp(yInt, 0, World.Heightmap.Height - 1); Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); // Adjust bounding box - zLower = Math.Min(zLower, pos1.Z); - zUpper = Math.Max(zUpper, pos1.Z); + zLower = Math.Min(zLower, pos4.Z); + zUpper = Math.Max(zUpper, pos4.Z); // Add triangle 1 Tri triangle1 = new Tri(); @@ -14695,25 +14719,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// Helper to check if a ray intersects bounding shapes. - /// - private bool InBoundingShapes(Vector3 ray, float rayLength, Vector3 scale, Vector3 posPartRel, Vector3 posPartProj, Quaternion rotProj) - { - float tol = m_floatToleranceInCastRay; - - // Check if ray intersects projected bounding box - Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); - Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); - int dummy = 0; - AddBoundingBoxOfSimpleBox(scale * -0.5f, scale * 0.5f, posPartProj, rotProj, true, ref lowerBox, ref upperBox, ref dummy); - if (lowerBox.X > tol || lowerBox.Y > tol || lowerBox.Z > tol || upperBox.X < -tol || upperBox.Y < -tol || upperBox.Z < -rayLength - tol) - return false; - - // Passed bounding shape filters, so return true - return true; - } - - /// /// Helper to get link number for a UUID. /// private int UUID2LinkNumber(SceneObjectPart part, UUID id) -- cgit v1.1 From cb586d11582fa2641fe99edc6367edc800af0ba0 Mon Sep 17 00:00:00 2001 From: AliciaRaven Date: Mon, 4 May 2015 04:10:08 +0100 Subject: Enable grab feature (Ctrl+Drag) for non-physical link-sets and add code to handle spin (Ctrl+Shift+Drag) This patch fixes permission issues with dragging scripted objects. As on LL grid, scripted prims can not be dragged. Also after dragging, the group was not marked as updated. This meant that after the region was restarted the group would revert to its original position. This version fixes issues where scripts in child prims were not detected and also blocks grab for attachments. Signed-off-by: BlueWall --- .../Region/Framework/Scenes/SceneObjectGroup.cs | 30 +++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 0a1a226..866a43c 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2672,20 +2672,27 @@ namespace OpenSim.Region.Framework.Scenes } else { - //NonPhysicalGrabMovement(pos); + NonPhysicalGrabMovement(pos); } } else { - //NonPhysicalGrabMovement(pos); + NonPhysicalGrabMovement(pos); } } } + /// + /// Apply possition for grabbing non-physical linksets (Ctrl+Drag) + /// This MUST be blocked for linksets that contain touch scripts because the viewer triggers grab on the touch + /// event (Viewer Bug?) This would allow anyone to drag a linkset with a touch script. SL behaviour is also to + /// block grab on prims with touch events. + /// + /// New Position public void NonPhysicalGrabMovement(Vector3 pos) { - AbsolutePosition = pos; - m_rootPart.SendTerseUpdateToAllClients(); + if(!IsAttachment && ScriptCount() == 0) + UpdateGroupPosition(pos); } /// @@ -2781,17 +2788,28 @@ namespace OpenSim.Region.Framework.Scenes } else { - //NonPhysicalSpinMovement(pos); + NonPhysicalSpinMovement(newOrientation); } } else { - //NonPhysicalSpinMovement(pos); + NonPhysicalSpinMovement(newOrientation); } } } /// + /// Apply rotation for spinning non-physical linksets (Ctrl+Shift+Drag) + /// As with dragging, scripted objects must be blocked from spinning + /// + /// New Rotation + private void NonPhysicalSpinMovement(Quaternion newOrientation) + { + if(!IsAttachment && ScriptCount() == 0) + UpdateGroupRotationR(newOrientation); + } + + /// /// Set the name of a prim /// /// -- cgit v1.1 From 3c2886cd7507890b03f1213ca280c4a505af52c3 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 13 May 2015 14:31:28 -0500 Subject: Adding back command to clear region's user cache --- .../UserManagement/UserManagementModule.cs | 29 ++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index ba71dc5..7ecbd26 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #endregion ISharedRegionModule - + #region Event Handlers void EventManager_OnPrimsLoaded(Scene s) @@ -180,7 +180,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement void HandleUUIDNameRequest(UUID uuid, IClientAPI client) { // m_log.DebugFormat( -// "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", +// "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", // uuid, remote_client.Name); if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) @@ -212,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // appear to clear this when the user asks it to clear the cache, but others may not. // // So to avoid clients - // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will + // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will // instead drop the request entirely. if (GetUser(uuid, out user)) { @@ -220,7 +220,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // else // m_log.DebugFormat( -// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}", +// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}", // uuid, client.Name); }); } @@ -416,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e); userdata.ServerURLs = new Dictionary(); } - + if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) return userdata.ServerURLs[serverType].ToString(); } @@ -620,7 +620,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement AddUser(id, string.Empty, string.Empty, string.Empty); } else - { + { string homeURL; string firstname = string.Empty; string lastname = string.Empty; @@ -676,7 +676,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { lock(m_UserCache) - { + { if(!m_UserCache.ContainsKey(id)) { UserData newUser = new UserData(); @@ -726,6 +726,21 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement "Show the bindings between user UUIDs and user names", String.Empty, HandleShowUsers); + + MainConsole.Instance.Commands.AddCommand("Users", true, + "reset user cache", + "reset user cache", + "reset user cache to allow changed settings to be applied", + String.Empty, + HandleResetUserCache); + } + + private void HandleResetUserCache(string module, string[] cmd) + { + lock(m_UserCache) + { + m_UserCache.Clear(); + } } private void HandleShowUser(string module, string[] cmd) -- cgit v1.1 From 6a48c87cd20e9df5ebdd2898872618455106be4c Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 13 May 2015 15:59:58 -0700 Subject: resolve possible nullref when sending appearance packet. Thanks to zadark for pointing this out. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 855342f..284c5fa 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -3747,6 +3747,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP avp.Sender.IsTrial = false; avp.Sender.ID = agentID; avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; + avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0]; //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); OutPacket(avp, ThrottleOutPacketType.Task); } -- cgit v1.1