diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 5b76e0a5b8..e98bc0f151 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -249,7 +249,7 @@ namespace OpenSim.Groups // There might be some problem with the thread we're generating this on but not // doing the update at this time causes problems (Mantis #7920 and #7915) // TODO: move sending this update to a later time in the rootification of the client. - if(!sp.haveGroupInformation) + if(!sp.m_haveGroupInformation) SendAgentGroupDataUpdate(sp.ControllingClient, false); } diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs index 5a9eeb57f9..330a41e93d 100644 --- a/OpenSim/Framework/AgentCircuitData.cs +++ b/OpenSim/Framework/AgentCircuitData.cs @@ -173,6 +173,7 @@ namespace OpenSim.Framework /// Position the Agent's Avatar starts in the region /// public Vector3 startpos; + public float startfar = -1.0f; public Dictionary ServiceURLs; @@ -219,6 +220,8 @@ namespace OpenSim.Framework args["channel"] = OSD.FromString(Channel); args["mac"] = OSD.FromString(Mac); args["id0"] = OSD.FromString(Id0); + if(startfar > 0) + args["far"] = OSD.FromReal(startfar); if (Appearance != null) { @@ -327,6 +330,9 @@ namespace OpenSim.Framework if (args["start_pos"] != null) Vector3.TryParse(args["start_pos"].AsString(), out startpos); + if(args["far"] != null) + startfar = (float)args["far"].AsReal(); + //m_log.InfoFormat("[AGENTCIRCUITDATA]: agentid={0}, child={1}, startpos={2}", AgentID, child, startpos); try diff --git a/OpenSim/Framework/AgentCircuitManager.cs b/OpenSim/Framework/AgentCircuitManager.cs index b6e48b4372..2cd11ffe83 100644 --- a/OpenSim/Framework/AgentCircuitManager.cs +++ b/OpenSim/Framework/AgentCircuitManager.cs @@ -79,6 +79,7 @@ namespace OpenSim.Framework user.LoginInfo.InventoryFolder = validcircuit.InventoryFolder; user.LoginInfo.BaseFolder = validcircuit.BaseFolder; user.LoginInfo.StartPos = validcircuit.startpos; + user.LoginInfo.StartFar = (float)validcircuit.startfar; } else { @@ -175,7 +176,8 @@ namespace OpenSim.Framework { m_agentCircuits[(uint) agentData.circuitcode].firstname = agentData.firstname; m_agentCircuits[(uint) agentData.circuitcode].lastname = agentData.lastname; - m_agentCircuits[(uint) agentData.circuitcode].startpos = agentData.startpos; + m_agentCircuits[(uint)agentData.circuitcode].startpos = agentData.startpos; + m_agentCircuits[(uint)agentData.circuitcode].startfar = agentData.startfar; // Updated for when we don't know them before calling Scene.NewUserConnection m_agentCircuits[(uint) agentData.circuitcode].SecureSessionID = agentData.SecureSessionID; diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index ee5007abf8..2d00296460 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -398,7 +398,8 @@ namespace OpenSim.Framework // Scripted public ControllerData[] Controllers; - public string CallbackURI; + public string CallbackURI; // to remove + public string NewCallbackURI; // These two must have the same Count public List AttachmentObjects; @@ -528,6 +529,9 @@ namespace OpenSim.Framework if ((CallbackURI != null) && (!CallbackURI.Equals(""))) args["callback_uri"] = OSD.FromString(CallbackURI); + if ((NewCallbackURI != null) && (!NewCallbackURI.Equals(""))) + args["cb_uri"] = OSD.FromString(NewCallbackURI); + // Attachment objects for fatpack messages if (AttachmentObjects != null) { @@ -811,12 +815,7 @@ namespace OpenSim.Framework } // end of code to remove } -/* moved above - if (args.ContainsKey("packed_appearance") && (args["packed_appearance"]).Type == OSDType.Map) - Appearance = new AvatarAppearance((OSDMap)args["packed_appearance"]); - else - m_log.WarnFormat("[CHILDAGENTDATAUPDATE] No packed appearance"); -*/ + if ((args["controllers"] != null) && (args["controllers"]).Type == OSDType.Array) { OSDArray controls = (OSDArray)(args["controllers"]); @@ -834,6 +833,9 @@ namespace OpenSim.Framework if (args["callback_uri"] != null) CallbackURI = args["callback_uri"].AsString(); + if (args["cb_uri"] != null) + NewCallbackURI = args["cb_uri"].AsString(); + // Attachment objects if (args["attach_objects"] != null && args["attach_objects"].Type == OSDType.Array) { diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs index 1b5ebfaafb..1c0b97af98 100644 --- a/OpenSim/Framework/EstateSettings.cs +++ b/OpenSim/Framework/EstateSettings.cs @@ -153,7 +153,7 @@ namespace OpenSim.Framework private bool m_DenyAnonymous = false; public bool DenyAnonymous { - get { return m_DenyAnonymous; } + get { return (DoDenyAnonymous && m_DenyAnonymous); } set { m_DenyAnonymous = value; } } @@ -233,7 +233,7 @@ namespace OpenSim.Framework private bool m_DenyMinors = false; public bool DenyMinors { - get { return m_DenyMinors; } + get { return (DoDenyMinors && m_DenyMinors); } set { m_DenyMinors = value; } } @@ -379,14 +379,14 @@ namespace OpenSim.Framework if (!HasAccess(avatarID)) { - if (DoDenyMinors && DenyMinors) + if (DenyMinors) { if ((userFlags & 32) == 0) { return true; } } - if (DoDenyAnonymous && DenyAnonymous) + if (DenyAnonymous) { if ((userFlags & 4) == 0) { diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index d63136e332..68ca52e2ee 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -596,22 +596,33 @@ namespace OpenSim.Framework public PrimUpdateFlags Flags { get { return m_flags; } + set { m_flags = value; } } public virtual void Update() { // we are on the new one if (m_flags.HasFlag(PrimUpdateFlags.CancelKill)) - m_flags = PrimUpdateFlags.FullUpdatewithAnim; + { + if (m_flags.HasFlag(PrimUpdateFlags.UpdateProbe)) + m_flags = PrimUpdateFlags.UpdateProbe; + else + m_flags = PrimUpdateFlags.FullUpdatewithAnim; + } } public virtual void Update(EntityUpdate oldupdate) { // we are on the new one PrimUpdateFlags updateFlags = oldupdate.Flags; + if (updateFlags.HasFlag(PrimUpdateFlags.UpdateProbe)) + updateFlags &= ~PrimUpdateFlags.UpdateProbe; if (m_flags.HasFlag(PrimUpdateFlags.CancelKill)) { - m_flags = PrimUpdateFlags.FullUpdatewithAnim; + if(m_flags.HasFlag(PrimUpdateFlags.UpdateProbe)) + m_flags = PrimUpdateFlags.UpdateProbe; + else + m_flags = PrimUpdateFlags.FullUpdatewithAnim; } else m_flags |= updateFlags; @@ -679,6 +690,7 @@ namespace OpenSim.Framework FullUpdatewithAnim = FullUpdate | Animations, + UpdateProbe = 0x10000000, // 1 << 28 SendInTransit = 0x20000000, // 1 << 29 CancelKill = 0x40000000, // 1 << 30 Kill = 0x80000000 // 1 << 31 @@ -696,6 +708,7 @@ namespace OpenSim.Framework public interface IClientAPI { Vector3 StartPos { get; set; } + float StartFar { get; set; } UUID AgentId { get; } @@ -1097,8 +1110,6 @@ namespace OpenSim.Framework void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures); - void SendStartPingCheck(byte seq); - /// /// Tell the client that an object has been deleted /// @@ -1108,7 +1119,7 @@ namespace OpenSim.Framework // void SendPartFullUpdate(ISceneEntity ent, uint? parentID); void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); - void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); + void SendRegionHandshake(); /// /// Send chat to the viewer. @@ -1224,7 +1235,8 @@ namespace OpenSim.Framework /// void SendBulkUpdateInventory(InventoryNodeBase node); - void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory); + void SendXferPacket(ulong xferID, uint packet, + byte[] XferData, int XferDataOffset, int XferDatapktLen, bool isTaskInventory); void SendAbortXferPacket(ulong xferID); @@ -1502,6 +1514,6 @@ namespace OpenSim.Framework void SendAgentTerseUpdate(ISceneEntity presence); void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); - void CheckViewerCaps(); + uint GetViewerCaps(); } } diff --git a/OpenSim/Framework/ILandChannel.cs b/OpenSim/Framework/ILandChannel.cs index e5ea596327..6f4a07a293 100644 --- a/OpenSim/Framework/ILandChannel.cs +++ b/OpenSim/Framework/ILandChannel.cs @@ -98,6 +98,6 @@ namespace OpenSim.Region.Framework.Interfaces void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id); void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id); - void sendClientInitialLandInfo(IClientAPI remoteClient); + void sendClientInitialLandInfo(IClientAPI remoteClient, bool overlay); } } diff --git a/OpenSim/Framework/ISceneAgent.cs b/OpenSim/Framework/ISceneAgent.cs index 5d70b83357..43e1b085b8 100644 --- a/OpenSim/Framework/ISceneAgent.cs +++ b/OpenSim/Framework/ISceneAgent.cs @@ -70,14 +70,6 @@ namespace OpenSim.Framework AvatarAppearance Appearance { get; set; } /// - /// Send initial scene data to the client controlling this agent - /// - /// - /// This includes scene object data and the appearance data of other avatars. - /// - void SendInitialDataToMe(); - - /// /// Direction in which the scene presence is looking. /// /// Will be Vector3.Zero for a child agent. diff --git a/OpenSim/Framework/Login.cs b/OpenSim/Framework/Login.cs index 54a6654685..b8a24ea7a6 100644 --- a/OpenSim/Framework/Login.cs +++ b/OpenSim/Framework/Login.cs @@ -42,11 +42,13 @@ namespace OpenSim.Framework public UUID SecureSession = UUID.Zero; public UUID Session; public Vector3 StartPos; + public float StartFar; public AvatarAppearance Appearance; public Login() { StartPos = new Vector3(128, 128, 70); + StartFar = -1; } } } diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index a5f3ba6e55..a49f53c8d1 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -1039,6 +1039,7 @@ namespace OpenSim.Framework const byte LightEP = 0x20; const byte SculptEP = 0x30; const byte ProjectionEP = 0x40; + //const byte MeshEP = 0x60; const byte MeshFlagsEP = 0x70; int TotalBytesLength = 1; // ExtraParamsNum @@ -1121,7 +1122,10 @@ namespace OpenSim.Framework if (_sculptEntry) { - returnBytes[i] = SculptEP; + //if(_sculptType == 5) + // returnBytes[i] = MeshEP; + //else + returnBytes[i] = SculptEP; i += 2; returnBytes[i] = 17; i += 4; @@ -1164,6 +1168,7 @@ namespace OpenSim.Framework const ushort LightEP = 0x20; const ushort SculptEP = 0x30; const ushort ProjectionEP = 0x40; + const ushort MeshEP = 0x60; const ushort MeshFlagsEP = 0x70; switch (type) @@ -1186,6 +1191,7 @@ namespace OpenSim.Framework ReadLightData(data, 0); break; + case MeshEP: case SculptEP: if (!inUse) { @@ -1231,6 +1237,7 @@ namespace OpenSim.Framework const byte LightEP = 0x20; const byte SculptEP = 0x30; const byte ProjectionEP = 0x40; + const byte MeshEP = 0x60; const byte MeshFlagsEP = 0x70; byte extraParamCount = data[0]; @@ -1252,6 +1259,7 @@ namespace OpenSim.Framework i += 16; break; + case MeshEP: case SculptEP: ReadSculptData(data, i); i += 17; diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 75ed999601..98ef5d58e3 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -180,6 +180,7 @@ namespace OpenSim.Framework private Dictionary m_extraSettings = new Dictionary(); + public UUID CacheID { get; set;} // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. // MT: Yes. Estates can't span trust boundaries. Therefore, it can be @@ -196,6 +197,7 @@ namespace OpenSim.Framework public RegionInfo(string description, string filename, bool skipConsoleConfig, IConfigSource configSource, string configName) { // m_configSource = configSource; + CacheID = UUID.Random(); if (filename.ToLower().EndsWith(".ini")) { @@ -255,6 +257,7 @@ namespace OpenSim.Framework ReadNiniConfig(source, name); m_serverURI = string.Empty; + CacheID = UUID.Random(); } public RegionInfo(uint legacyRegionLocX, uint legacyRegionLocY, IPEndPoint internalEndPoint, string externalUri) @@ -266,11 +269,13 @@ namespace OpenSim.Framework m_internalEndPoint = internalEndPoint; m_externalHostName = externalUri; m_serverURI = string.Empty; + CacheID = UUID.Random(); } public RegionInfo() { m_serverURI = string.Empty; + CacheID = UUID.Random(); } public EstateSettings EstateSettings diff --git a/OpenSim/Framework/RegionInfoForEstateMenuArgs.cs b/OpenSim/Framework/RegionInfoForEstateMenuArgs.cs index f274da2e7a..1b828caad1 100644 --- a/OpenSim/Framework/RegionInfoForEstateMenuArgs.cs +++ b/OpenSim/Framework/RegionInfoForEstateMenuArgs.cs @@ -33,7 +33,7 @@ namespace OpenSim.Framework { public float billableFactor; public uint estateID; - public byte maxAgents; + public int maxAgents; public float objectBonusFactor; public uint parentEstateID; public int pricePerMeter; @@ -48,5 +48,7 @@ namespace OpenSim.Framework public float waterHeight; public string simName; public string regionType; + public int AgentCapacity; + public int ObjectsCapacity; } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 14e21a2167..790aa99974 100755 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -309,7 +309,8 @@ namespace OpenSim.Framework.Servers.HttpServer { Thread.ResetAbort(); // Shouldn't set this to 'false', the normal shutdown should cause things to exit - // m_running = false; + // but robust is still not normal neither is mono + m_running = false; } catch (Exception e) { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs index 8f65a69121..b0ba5a3779 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs @@ -77,6 +77,9 @@ namespace OpenSim.Region.ClientStack.LindenCaps { RegisterCaps(agentID, caps); }; + ISimulatorFeaturesModule simFeatures = scene.RequestModuleInterface(); + if(simFeatures != null) + simFeatures.AddFeature("AvatarHoverHeightEnabled",OSD.FromBoolean(true)); } public void PostInitialise() {} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 92f5a2cc24..ea68581f33 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -61,7 +61,7 @@ namespace OpenSim.Region.ClientStack.Linden string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, string assetType, int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, - bool IsAtestUpload, ref string error, ref int nextOwnerMask, ref int groupMask, ref int everyoneMask); + bool IsAtestUpload, ref string error, ref int nextOwnerMask, ref int groupMask, ref int everyoneMask, int[] meshesSides); public delegate UUID UpdateItem(UUID itemID, byte[] data); @@ -505,7 +505,7 @@ namespace OpenSim.Region.ClientStack.Linden case FileAgentInventoryState.processRequest: case FileAgentInventoryState.processUpload: LLSDAssetUploadError resperror = new LLSDAssetUploadError(); - resperror.message = "Uploader busy processing previus request"; + resperror.message = "Uploader busy processing previous request"; resperror.identifier = UUID.Zero; LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); @@ -529,6 +529,7 @@ namespace OpenSim.Region.ClientStack.Linden int nreqmeshs= 0; int nreqinstances = 0; bool IsAtestUpload = false; + int[] meshesSides = null; string assetName = llsdRequest.name; @@ -578,9 +579,8 @@ namespace OpenSim.Region.ClientStack.Linden string error; int modelcost; - if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost, - meshcostdata, out error, ref warning)) + meshcostdata, out error, ref warning, out meshesSides)) { LLSDAssetUploadError resperror = new LLSDAssetUploadError(); resperror.message = error; @@ -668,7 +668,7 @@ namespace OpenSim.Region.ClientStack.Linden new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, llsdRequest.asset_type, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost, texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload, - llsdRequest.next_owner_mask, llsdRequest.group_mask, llsdRequest.everyone_mask); + llsdRequest.next_owner_mask, llsdRequest.group_mask, llsdRequest.everyone_mask, meshesSides); m_HostCapsObj.HttpListener.AddStreamHandler( new BinaryStreamHandler( @@ -713,7 +713,7 @@ namespace OpenSim.Region.ClientStack.Linden string assetType, int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, bool IsAtestUpload, ref string error, - ref int nextOwnerMask, ref int groupMask, ref int everyoneMask) + ref int nextOwnerMask, ref int groupMask, ref int everyoneMask, int[] meshesSides) { lock (m_ModelCost) m_FileAgentInventoryState = FileAgentInventoryState.processUpload; @@ -967,7 +967,12 @@ namespace OpenSim.Region.ClientStack.Linden { int meshindx = inner_instance_list["mesh"].AsInteger(); if (meshAssets.Count > meshindx) - pbs = PrimitiveBaseShape.CreateMesh(face_list.Count, meshAssets[meshindx]); + { + if(meshesSides != null && meshesSides.Length > meshindx) + pbs = PrimitiveBaseShape.CreateMesh(meshesSides[i], meshAssets[meshindx]); + else + pbs = PrimitiveBaseShape.CreateMesh(face_list.Count, meshAssets[meshindx]); + } } if(pbs == null) // fallback pbs = PrimitiveBaseShape.CreateBox(); @@ -1012,17 +1017,25 @@ namespace OpenSim.Region.ClientStack.Linden textureEntry.FaceTextures[face] = f; } - pbs.TextureEntry = textureEntry.GetBytes(); + + if(face_list.Count > 0) + { + int last = face_list.Count - 1; + // we do need a better te compacting code + textureEntry.DefaultTexture = textureEntry.FaceTextures[last]; + textureEntry.FaceTextures[last] = null; + pbs.TextureEntry = textureEntry.GetBytes(last); + } Vector3 position = inner_instance_list["position"].AsVector3(); Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); - // for now viwers do send fixed defaults - // but this may change -// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger(); byte physicsShapeType = (byte)PhysShapeType.convex; // default is simple convex -// int material = inner_instance_list["material"].AsInteger(); + if (inner_instance_list.ContainsKey("physics_shape_type")) + physicsShapeType = (byte)inner_instance_list["physics_shape_type"].AsInteger(); byte material = (byte)Material.Wood; + if (inner_instance_list.ContainsKey("material")) + material = (byte)inner_instance_list["material"].AsInteger(); SceneObjectPart prim = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); @@ -2006,13 +2019,13 @@ namespace OpenSim.Region.ClientStack.Linden private int m_nextOwnerMask; private int m_groupMask; private int m_everyoneMask; - + private int[] m_meshesSides; public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolderID, string invType, string assetType, string path, IHttpServer httpServer, bool dumpAssetsToFile, int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, - bool IsAtestUpload, int nextOwnerMask, int groupMask, int everyoneMask) + bool IsAtestUpload, int nextOwnerMask, int groupMask, int everyoneMask, int[] meshesSides) { m_assetName = assetName; m_assetDes = description; @@ -2040,6 +2053,8 @@ namespace OpenSim.Region.ClientStack.Linden m_nextOwnerMask = nextOwnerMask; m_groupMask = groupMask; m_everyoneMask = everyoneMask; + + m_meshesSides = meshesSides; } /// @@ -2080,7 +2095,7 @@ namespace OpenSim.Region.ClientStack.Linden { handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType, m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, - ref m_error, ref m_nextOwnerMask, ref m_groupMask, ref m_everyoneMask); + ref m_error, ref m_nextOwnerMask, ref m_groupMask, ref m_everyoneMask, m_meshesSides); } uploadComplete.new_next_owner_mask = m_nextOwnerMask; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs index eb1ab4504a..9b8f11a52b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs @@ -40,7 +40,7 @@ using OpenSim.Region.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Framework.Capabilities; -using ComponentAce.Compression.Libs.zlib; +using System.IO.Compression; using OSDArray = OpenMetaverse.StructuredData.OSDArray; using OSDMap = OpenMetaverse.StructuredData.OSDMap; @@ -129,6 +129,7 @@ namespace OpenSim.Region.ClientStack.Linden public int medLODSize; public int lowLODSize; public int lowestLODSize; + public int highLODsides; // normalized fee based on compressed data sizes public float costFee; // physics cost @@ -144,11 +145,11 @@ namespace OpenSim.Region.ClientStack.Linden // avatarSkeleton if mesh includes a avatar skeleton // useAvatarCollider if we should use physics mesh for avatar public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost, - LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning) + LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning, out int[] meshesSides) { totalcost = 0; error = string.Empty; - + meshesSides = null; bool avatarSkeleton = false; if (resources == null || @@ -203,13 +204,14 @@ namespace OpenSim.Region.ClientStack.Linden if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0) { numberMeshs = resources.mesh_list.Array.Count; + meshesSides = new int[numberMeshs]; for (int i = 0; i < numberMeshs; i++) { ameshCostParam curCost = new ameshCostParam(); byte[] data = (byte[])resources.mesh_list.Array[i]; - if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error)) + if (!MeshCost(data, curCost, out curskeleton, out curAvatarPhys, out error)) { return false; } @@ -225,6 +227,7 @@ namespace OpenSim.Region.ClientStack.Linden } meshsCosts.Add(curCost); meshsfee += curCost.costFee; + meshesSides[i] = curCost.highLODsides; } haveMeshs = true; } @@ -275,6 +278,7 @@ namespace OpenSim.Region.ClientStack.Linden float sqdiam = scale.LengthSquared(); ameshCostParam curCost = meshsCosts[mesh]; + float mesh_streaming = streamingCost(curCost, sqdiam); meshcostdata.model_streaming_cost += mesh_streaming; @@ -339,6 +343,7 @@ namespace OpenSim.Region.ClientStack.Linden private bool MeshCost(byte[] data, ameshCostParam cost,out bool skeleton, out bool avatarPhys, out string error) { cost.highLODSize = 0; + cost.highLODsides = 0; cost.medLODSize = 0; cost.lowLODSize = 0; cost.lowestLODSize = 0; @@ -430,7 +435,8 @@ namespace OpenSim.Region.ClientStack.Linden submesh_offset = -1; - // only look for LOD meshs sizes + int nsides = 0; + int lod_ntriangles = 0; if (map.ContainsKey("high_lod")) { @@ -440,6 +446,15 @@ namespace OpenSim.Region.ClientStack.Linden submesh_offset = tmpmap["offset"].AsInteger() + start; if (tmpmap.ContainsKey("size")) highlod_size = tmpmap["size"].AsInteger(); + + if (submesh_offset >= 0 && highlod_size > 0) + { + if (!submesh(data, submesh_offset, highlod_size, out lod_ntriangles, out nsides)) + { + error = "Model data parsing error"; + return false; + } + } } if (submesh_offset < 0 || highlod_size <= 0) @@ -483,6 +498,7 @@ namespace OpenSim.Region.ClientStack.Linden } cost.highLODSize = highlod_size; + cost.highLODsides = nsides; cost.medLODSize = medlod_size; cost.lowLODSize = lowlod_size; cost.lowestLODSize = lowestlod_size; @@ -495,6 +511,7 @@ namespace OpenSim.Region.ClientStack.Linden else if (map.ContainsKey("physics_shape")) // old naming tmpmap = (OSDMap)map["physics_shape"]; + int phys_nsides = 0; if(tmpmap != null) { if (tmpmap.ContainsKey("offset")) @@ -502,10 +519,9 @@ namespace OpenSim.Region.ClientStack.Linden if (tmpmap.ContainsKey("size")) physmesh_size = tmpmap["size"].AsInteger(); - if (submesh_offset >= 0 || physmesh_size > 0) + if (submesh_offset >= 0 && physmesh_size > 0) { - - if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles)) + if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles, out phys_nsides)) { error = "Model data parsing error"; return false; @@ -541,34 +557,30 @@ namespace OpenSim.Region.ClientStack.Linden } // parses a LOD or physics mesh component - private bool submesh(byte[] data, int offset, int size, out int ntriangles) + private bool submesh(byte[] data, int offset, int size, out int ntriangles, out int nsides) { ntriangles = 0; + nsides = 0; OSD decodedMeshOsd = new OSD(); - byte[] meshBytes = new byte[size]; - System.Buffer.BlockCopy(data, offset, meshBytes, 0, size); try { - using (MemoryStream inMs = new MemoryStream(meshBytes)) + using (MemoryStream outMs = new MemoryStream()) { - using (MemoryStream outMs = new MemoryStream()) + using (MemoryStream inMs = new MemoryStream(data, offset, size)) { - using (ZOutputStream zOut = new ZOutputStream(outMs)) + using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress)) { - byte[] readBuffer = new byte[4096]; + byte[] readBuffer = new byte[2048]; + inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header int readLen = 0; - while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) - { - zOut.Write(readBuffer, 0, readLen); - } - zOut.Flush(); - outMs.Seek(0, SeekOrigin.Begin); - byte[] decompressedBuf = outMs.GetBuffer(); - decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); + while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0) + outMs.Write(readBuffer, 0, readLen); } } + outMs.Seek(0, SeekOrigin.Begin); + decodedMeshOsd = OSDParser.DeserializeLLSDBinary(outMs); } } catch @@ -599,6 +611,7 @@ namespace OpenSim.Region.ClientStack.Linden } else return false; + nsides++; } } @@ -612,29 +625,24 @@ namespace OpenSim.Region.ClientStack.Linden nhulls = 1; OSD decodedMeshOsd = new OSD(); - byte[] meshBytes = new byte[size]; - System.Buffer.BlockCopy(data, offset, meshBytes, 0, size); try { - using (MemoryStream inMs = new MemoryStream(meshBytes)) + using (MemoryStream outMs = new MemoryStream(4 * size)) { - using (MemoryStream outMs = new MemoryStream()) + using (MemoryStream inMs = new MemoryStream(data, offset, size)) { - using (ZOutputStream zOut = new ZOutputStream(outMs)) + using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress)) { - byte[] readBuffer = new byte[4096]; + byte[] readBuffer = new byte[8192]; + inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header int readLen = 0; - while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) - { - zOut.Write(readBuffer, 0, readLen); - } - zOut.Flush(); - outMs.Seek(0, SeekOrigin.Begin); - byte[] decompressedBuf = outMs.GetBuffer(); - decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); + while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0) + outMs.Write(readBuffer, 0, readLen); } } + outMs.Seek(0, SeekOrigin.Begin); + decodedMeshOsd = OSDParser.DeserializeLLSDBinary(outMs); } } catch @@ -716,7 +724,7 @@ namespace OpenSim.Region.ClientStack.Linden int m = curCost.medLODSize - 384; int h = curCost.highLODSize - 384; - // use previus higher LOD size on missing ones + // use previous higher LOD size on missing ones if (m <= 0) m = h; if (l <= 0) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index f56b212a2d..4e451b5c7e 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -233,7 +233,7 @@ namespace OpenSim.Region.ClientStack.Linden else { m_log.WarnFormat( - "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} in region {2}", + "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} in region {1}", avatarID, m_scene.Name); } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index ac041f500b..aeb728e8d1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -332,7 +332,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private readonly UUID m_secureSessionId; protected readonly UUID m_agentId; private readonly uint m_circuitCode; - private readonly byte[] m_channelVersion = Utils.EmptyBytes; + private readonly byte[] m_regionChannelVersion = Utils.EmptyBytes; private readonly IGroupsModule m_GroupsModule; // private int m_cachedTextureSerial; @@ -392,6 +392,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected IAssetService m_assetService; + protected bool m_supportViewerCache = false; #endregion Class Members #region Properties @@ -407,6 +408,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP get { return m_startpos; } set { m_startpos = value; } } + public float StartFar { get; set; } + public bool DeliverPackets { get { return m_deliverPackets; } @@ -531,7 +534,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_assetService = m_scene.RequestModuleInterface(); m_GroupsModule = scene.RequestModuleInterface(); ImageManager = new LLImageManager(this, m_assetService, Scene.RequestModuleInterface()); - m_channelVersion = Util.StringToBytes256(scene.GetSimulatorVersion()); + m_regionChannelVersion = Util.StringToBytes1024(scene.GetSimulatorVersion()); m_agentId = agentId; m_sessionId = sessionId; m_secureSessionId = sessionInfo.LoginInfo.SecureSession; @@ -539,6 +542,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_firstName = sessionInfo.LoginInfo.First; m_lastName = sessionInfo.LoginInfo.Last; m_startpos = sessionInfo.LoginInfo.StartPos; + StartFar = sessionInfo.LoginInfo.StartFar; m_udpServer = udpServer; m_udpClient = udpClient; @@ -552,6 +556,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP string name = string.Format("AsyncInUDP-{0}",m_agentId.ToString()); m_asyncPacketProcess = new JobEngine(name, name, 10000); IsActive = true; + + m_supportViewerCache = m_udpServer.SupportViewerObjectsCache; } #region Client Methods @@ -817,171 +823,535 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Scene/Avatar to Client - public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) + // temporary here ( from estatemanagermodule) + private uint GetRegionFlags() { - RegionHandshakePacket handshake = (RegionHandshakePacket)PacketPool.Instance.GetPacket(PacketType.RegionHandshake); - handshake.RegionInfo = new RegionHandshakePacket.RegionInfoBlock(); - handshake.RegionInfo.BillableFactor = args.billableFactor; - handshake.RegionInfo.IsEstateManager = args.isEstateManager; - handshake.RegionInfo.TerrainHeightRange00 = args.terrainHeightRange0; - handshake.RegionInfo.TerrainHeightRange01 = args.terrainHeightRange1; - handshake.RegionInfo.TerrainHeightRange10 = args.terrainHeightRange2; - handshake.RegionInfo.TerrainHeightRange11 = args.terrainHeightRange3; - handshake.RegionInfo.TerrainStartHeight00 = args.terrainStartHeight0; - handshake.RegionInfo.TerrainStartHeight01 = args.terrainStartHeight1; - handshake.RegionInfo.TerrainStartHeight10 = args.terrainStartHeight2; - handshake.RegionInfo.TerrainStartHeight11 = args.terrainStartHeight3; - handshake.RegionInfo.SimAccess = args.simAccess; - handshake.RegionInfo.WaterHeight = args.waterHeight; + RegionFlags flags = RegionFlags.None; - handshake.RegionInfo.RegionFlags = args.regionFlags; - handshake.RegionInfo.SimName = Util.StringToBytes256(args.regionName); - handshake.RegionInfo.SimOwner = args.SimOwner; - handshake.RegionInfo.TerrainBase0 = args.terrainBase0; - handshake.RegionInfo.TerrainBase1 = args.terrainBase1; - handshake.RegionInfo.TerrainBase2 = args.terrainBase2; - handshake.RegionInfo.TerrainBase3 = args.terrainBase3; - handshake.RegionInfo.TerrainDetail0 = args.terrainDetail0; - handshake.RegionInfo.TerrainDetail1 = args.terrainDetail1; - handshake.RegionInfo.TerrainDetail2 = args.terrainDetail2; - handshake.RegionInfo.TerrainDetail3 = args.terrainDetail3; - handshake.RegionInfo.CacheID = UUID.Random(); //I guess this is for the client to remember an old setting? - handshake.RegionInfo2 = new RegionHandshakePacket.RegionInfo2Block(); - handshake.RegionInfo2.RegionID = regionInfo.RegionID; + if (Scene.RegionInfo.RegionSettings.AllowDamage) + flags |= RegionFlags.AllowDamage; + if (Scene.RegionInfo.EstateSettings.AllowLandmark) + flags |= RegionFlags.AllowLandmark; + if (Scene.RegionInfo.EstateSettings.AllowSetHome) + flags |= RegionFlags.AllowSetHome; + if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport) + flags |= RegionFlags.ResetHomeOnTeleport; + if (Scene.RegionInfo.RegionSettings.FixedSun) + flags |= RegionFlags.SunFixed; + // allow access override (was taxfree) + if (Scene.RegionInfo.RegionSettings.BlockTerraform) + flags |= RegionFlags.BlockTerraform; + if (!Scene.RegionInfo.RegionSettings.AllowLandResell) + flags |= RegionFlags.BlockLandResell; + if (Scene.RegionInfo.RegionSettings.Sandbox) + flags |= RegionFlags.Sandbox; + // nulllayer not used + if (Scene.RegionInfo.RegionSettings.Casino) + flags |= RegionFlags.SkipAgentAction; // redefined + if (Scene.RegionInfo.RegionSettings.GodBlockSearch) + flags |= RegionFlags.SkipUpdateInterestList; // redefined + if (Scene.RegionInfo.RegionSettings.DisableCollisions) + flags |= RegionFlags.SkipCollisions; + if (Scene.RegionInfo.RegionSettings.DisableScripts) + flags |= RegionFlags.SkipScripts; + if (Scene.RegionInfo.RegionSettings.DisablePhysics) + flags |= RegionFlags.SkipPhysics; + if (Scene.RegionInfo.EstateSettings.PublicAccess) + flags |= RegionFlags.ExternallyVisible; // ???? need revision + //MainlandVisible -> allow return enc object + //PublicAllowed -> allow return enc estate object + if (Scene.RegionInfo.EstateSettings.BlockDwell) + flags |= RegionFlags.BlockDwell; + if (Scene.RegionInfo.RegionSettings.BlockFly) + flags |= RegionFlags.NoFly; + if (Scene.RegionInfo.EstateSettings.AllowDirectTeleport) + flags |= RegionFlags.AllowDirectTeleport; + if (Scene.RegionInfo.EstateSettings.EstateSkipScripts) + flags |= RegionFlags.EstateSkipScripts; + if (Scene.RegionInfo.RegionSettings.RestrictPushing) + flags |= RegionFlags.RestrictPushObject; + if (Scene.RegionInfo.EstateSettings.DenyAnonymous) + flags |= RegionFlags.DenyAnonymous; + //DenyIdentified unused + //DenyTransacted unused + if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide) + flags |= RegionFlags.AllowParcelChanges; + //AbuseEmailToEstateOwner -> block flyover + if (Scene.RegionInfo.EstateSettings.AllowVoice) + flags |= RegionFlags.AllowVoice; + if (Scene.RegionInfo.RegionSettings.BlockShowInSearch) + flags |= RegionFlags.BlockParcelSearch; + if (Scene.RegionInfo.EstateSettings.DenyMinors) + flags |= RegionFlags.DenyAgeUnverified; - handshake.RegionInfo3 = new RegionHandshakePacket.RegionInfo3Block(); - handshake.RegionInfo3.CPUClassID = 9; - handshake.RegionInfo3.CPURatio = 1; - - handshake.RegionInfo3.ColoName = Utils.EmptyBytes; - handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); - handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; - - handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; - handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); - handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; - handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported - - OutPacket(handshake, ThrottleOutPacketType.Unknown); + return (uint)flags; } + // Region handshake may need a more detailed look + static private readonly byte[] RegionHandshakeHeader = new byte[] { + Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, + 0, 0, 0, 0, // sequence number + 0, // extra + //0xff, 0xff, 0, 148 // ID 148 (low frequency bigendian) + 0xff, 0xff, 0, 1, 148 // ID 148 (low frequency bigendian) zero encoded + }; + + + public void SendRegionHandshake() + { + RegionInfo regionInfo = m_scene.RegionInfo; + RegionSettings regionSettings = regionInfo.RegionSettings; + EstateSettings es = regionInfo.EstateSettings; + + bool isEstateManager = m_scene.Permissions.IsEstateManager(AgentId); // go by oficial path + uint regionFlags = GetRegionFlags(); + + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(RegionHandshakeHeader, 0, buf.Data, 0, 11); + + // inline zeroencode + LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); + zc.Position = 11; + + //RegionInfo Block + //RegionFlags U32 + zc.AddUInt(regionFlags); + //SimAccess U8 + zc.AddByte(regionInfo.AccessLevel); + //SimName + zc.AddShortString(regionInfo.RegionName, 255); + //SimOwner + zc.AddUUID(es.EstateOwner); + //IsEstateManager + zc.AddByte((byte)(isEstateManager ? 1 : 0)); + //WaterHeight + zc.AddFloat((float)regionSettings.WaterHeight); // why is this a double ?? + //BillableFactor + zc.AddFloat(es.BillableFactor); + //CacheID + zc.AddUUID(regionInfo.CacheID); + //TerrainBase0 + //TerrainBase1 + //TerrainBase2 + //TerrainBase3 + // this seem not obsolete, sending zero uuids + // we should send the basic low resolution default ? + zc.AddZeros(16 * 4); + //TerrainDetail0 + zc.AddUUID(regionSettings.TerrainTexture1); + //TerrainDetail1 + zc.AddUUID(regionSettings.TerrainTexture2); + //TerrainDetail2 + zc.AddUUID(regionSettings.TerrainTexture3); + //TerrainDetail3 + zc.AddUUID(regionSettings.TerrainTexture4); + //TerrainStartHeight00 + zc.AddFloat((float)regionSettings.Elevation1SW); + //TerrainStartHeight01 + zc.AddFloat((float)regionSettings.Elevation1NW); + //TerrainStartHeight10 + zc.AddFloat((float)regionSettings.Elevation1SE); + //TerrainStartHeight11 + zc.AddFloat((float)regionSettings.Elevation1NE); + //TerrainHeightRange00 + zc.AddFloat((float)regionSettings.Elevation2SW); + //TerrainHeightRange01 + zc.AddFloat((float)regionSettings.Elevation2NW); + //TerrainHeightRange10 + zc.AddFloat((float)regionSettings.Elevation2SE); + //TerrainHeightRange11 + zc.AddFloat((float)regionSettings.Elevation2NE); + + //RegionInfo2 block + + //region ID + zc.AddUUID(regionInfo.RegionID); + + //RegionInfo3 block + + //CPUClassID + zc.AddInt(9); + //CPURatio + zc.AddInt(1); + // ColoName (string) + // ProductSKU (string) + // both empty strings + zc.AddZeros(2); + //ProductName + zc.AddShortString(regionInfo.RegionType, 255); + + //RegionInfo4 block + + //RegionFlagsExtended + zc.AddZeros(1); // we dont have this + //zc.AddByte(1); + //zc.AddUInt64(regionFlags); // we have nothing other base flags + //RegionProtocols + //zc.AddUInt64(0); // bit 0 signals server side texture baking" + + buf.DataLength = zc.Finish(); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown); + } + + static private readonly byte[] AgentMovementCompleteHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 0, 250 // ID 250 (low frequency bigendian) + }; public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) { + // reset agent update args m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue; m_thisAgentUpdateArgs.lastUpdateTS = 0; m_thisAgentUpdateArgs.ControlFlags = 0; - AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); - mov.SimData.ChannelVersion = m_channelVersion; - mov.AgentData.SessionID = m_sessionId; - mov.AgentData.AgentID = AgentId; - mov.Data.RegionHandle = regInfo.RegionHandle; - mov.Data.Timestamp = (uint)Util.UnixTimeSinceEpoch(); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + //setup header + Buffer.BlockCopy(AgentMovementCompleteHeader, 0, data, 0, 10); + + //AgentData block + AgentId.ToBytes(data, 10); // 26 + SessionId.ToBytes(data, 26); // 42 + + //Data block if ((pos.X == 0) && (pos.Y == 0) && (pos.Z == 0)) + m_startpos.ToBytes(data, 42); //54 + else + pos.ToBytes(data, 42); //54 + look.ToBytes(data, 54); // 66 + Utils.UInt64ToBytesSafepos(regInfo.RegionHandle, data, 66); // 74 + Utils.UIntToBytesSafepos((uint)Util.UnixTimeSinceEpoch(), data, 74); //78 + + //SimData + int len = m_regionChannelVersion.Length; + if(len == 0) { - mov.Data.Position = m_startpos; + data[78] = 0; + data[79] = 0; } else { - mov.Data.Position = pos; + data[78] = (byte)len; + data[79] = (byte)(len >> 8); + Buffer.BlockCopy(m_regionChannelVersion, 0, data, 80, len); } - mov.Data.LookAt = look; - // Hack to get this out immediately and skip the throttles - OutPacket(mov, ThrottleOutPacketType.Unknown); + buf.DataLength = 80 + len; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown); } - public void SendChatMessage( - string message, byte type, Vector3 fromPos, string fromName, - UUID fromAgentID, UUID ownerID, byte source, byte audible) - { - ChatFromSimulatorPacket reply = (ChatFromSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.ChatFromSimulator); - reply.ChatData.Audible = audible; - reply.ChatData.Message = Util.StringToBytes1024(message); - reply.ChatData.ChatType = type; - reply.ChatData.SourceType = source; - reply.ChatData.Position = fromPos; - reply.ChatData.FromName = Util.StringToBytes256(fromName); - reply.ChatData.OwnerID = ownerID; - reply.ChatData.SourceID = fromAgentID; + static private readonly byte[] ChatFromSimulatorHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 0, 139 // ID 139 (low frequency bigendian) + }; - OutPacket(reply, ThrottleOutPacketType.Unknown); + public void SendChatMessage(string message, byte chattype, Vector3 fromPos, string fromName, + UUID sourceID, UUID ownerID, byte sourcetype, byte audible) + { + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + //setup header + Buffer.BlockCopy(ChatFromSimulatorHeader, 0, data, 0, 10); + + byte[] fname = Util.StringToBytes256(fromName); + int len = fname.Length; + int pos = 11; + if (len == 0) + data[10] = 0; + else + { + data[10] = (byte)len; + Buffer.BlockCopy(fname, 0, data, 11, len); + pos += len; + } + + sourceID.ToBytes(data, pos); pos += 16; + ownerID.ToBytes(data, pos); pos += 16; + data[pos++] = sourcetype; + data[pos++] = chattype; + data[pos++] = audible; + fromPos.ToBytes(data, pos); pos += 12; + + byte[] msg = Util.StringToBytes1024(message); + len = msg.Length; + if (len == 0) + { + data[pos++] = 0; + data[pos++] = 0; + } + else + { + data[pos++] = (byte)len; + data[pos++] = (byte)(len >> 8); + Buffer.BlockCopy(msg, 0, data, pos, len); pos += len; + } + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown); } /// /// Send an instant message to this client /// // + + static private readonly byte[] ImprovedInstantMessageHeader = new byte[] { + Helpers.MSG_RELIABLE, //| Helpers.MSG_ZEROCODED, not doing spec zeroencode on this + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 0, 254 // ID 139 (low frequency bigendian) + }; + public void SendInstantMessage(GridInstantMessage im) { - if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID))) + UUID fromAgentID = new UUID(im.fromAgentID); + UUID toAgentID = new UUID(im.toAgentID); + + if (!m_scene.Permissions.CanInstantMessage(fromAgentID, toAgentID)) + return; + + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + //setup header + Buffer.BlockCopy(ImprovedInstantMessageHeader, 0, data, 0, 10); + + //agentdata block + fromAgentID.ToBytes(data, 10); // 26 + UUID.Zero.ToBytes(data, 26); // 42 sessionID zero?? TO check + + int pos = 42; + + //MessageBlock + data[pos++] = (byte)((im.fromGroup) ? 1 : 0); + toAgentID.ToBytes(data, pos); pos += 16; + Utils.UIntToBytesSafepos(im.ParentEstateID, data, pos); pos += 4; + (new UUID(im.RegionID)).ToBytes(data, pos); pos += 16; + (im.Position).ToBytes(data, pos); pos += 12; + data[pos++] = im.offline; + data[pos++] = im.dialog; + + // this is odd + if (im.imSessionID == UUID.Zero.Guid) + (fromAgentID ^ toAgentID).ToBytes(data, pos); + else + (new UUID(im.imSessionID)).ToBytes(data, pos); + + pos += 16; + + Utils.UIntToBytesSafepos(im.timestamp, data, pos); pos += 4; + + byte[] tmp = Util.StringToBytes256(im.fromAgentName); + int len = tmp.Length; + data[pos++] = (byte)len; + if(len > 0) + Buffer.BlockCopy(tmp, 0, data, pos, len); pos += len; + + tmp = Util.StringToBytes1024(im.message); + len = tmp.Length; + if (len == 0) { - ImprovedInstantMessagePacket msg - = (ImprovedInstantMessagePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedInstantMessage); - - msg.AgentData.AgentID = new UUID(im.fromAgentID); - msg.AgentData.SessionID = UUID.Zero; - msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName); - msg.MessageBlock.Dialog = im.dialog; - msg.MessageBlock.FromGroup = im.fromGroup; - // this is odd - if (im.imSessionID == UUID.Zero.Guid) - msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID); - else - msg.MessageBlock.ID = new UUID(im.imSessionID); - msg.MessageBlock.Offline = im.offline; - msg.MessageBlock.ParentEstateID = im.ParentEstateID; - msg.MessageBlock.Position = im.Position; - msg.MessageBlock.RegionID = new UUID(im.RegionID); - msg.MessageBlock.Timestamp = im.timestamp; - msg.MessageBlock.ToAgentID = new UUID(im.toAgentID); - msg.MessageBlock.Message = Util.StringToBytes1024(im.message); - msg.MessageBlock.BinaryBucket = im.binaryBucket; - - OutPacket(msg, ThrottleOutPacketType.Task); + data[pos++] = 0; + data[pos++] = 0; } + else + { + data[pos++] = (byte)len; + data[pos++] = (byte)(len >> 8); + Buffer.BlockCopy(tmp, 0, data, pos, len); pos += len; + } + + tmp = im.binaryBucket; + if(tmp == null) + { + data[pos++] = 0; + data[pos++] = 0; + } + else + { + len = tmp.Length; + if (len == 0) + { + data[pos++] = 0; + data[pos++] = 0; + } + else + { + data[pos++] = (byte)len; + data[pos++] = (byte)(len >> 8); + Buffer.BlockCopy(tmp, 0, data, pos, len); pos += len; + } + } + + //EstateBlock does not seem in use TODO + //Utils.UIntToBytesSafepos(m_scene.RegionInfo.EstateSettings.EstateID, data, pos); pos += 4; + data[pos++] = 0; + data[pos++] = 0; + data[pos++] = 0; + data[pos++] = 0; + + buf.DataLength = pos; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown); } + static private readonly byte[] GenericMessageHeader = new byte[] { + Helpers.MSG_RELIABLE, //| Helpers.MSG_ZEROCODED, not doing spec zeroencode on this + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 1, 5 // ID 261 (low frequency bigendian) + }; + public void SendGenericMessage(string method, UUID invoice, List message) { - GenericMessagePacket gmp = new GenericMessagePacket(); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; - gmp.AgentData.AgentID = AgentId; - gmp.AgentData.SessionID = m_sessionId; - gmp.AgentData.TransactionID = invoice; + //setup header + Buffer.BlockCopy(GenericMessageHeader, 0, data, 0, 10); - gmp.MethodData.Method = Util.StringToBytes256(method); - gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; - int i = 0; - foreach (string val in message) + //agentdata block + m_agentId.ToBytes(data, 10); // 26 + m_sessionId.ToBytes(data, 26); // 42 sessionID zero?? TO check + UUID.Zero.ToBytes(data, 42); // 58 + + int pos = 58; + + //method block + byte[] tmp = Util.StringToBytes256(method); + int len = tmp.Length; + data[pos++] = (byte)len; + if (len > 0) + Buffer.BlockCopy(tmp, 0, data, pos, len); pos += len; + invoice.ToBytes(data, pos); pos += 16; + + //ParamList block + if (message.Count == 0) { - gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); - gmp.ParamList[i++].Parameter = Util.StringToBytes256(val); + data[pos++] = 0; + buf.DataLength = pos; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + return; } - OutPacket(gmp, ThrottleOutPacketType.Task); + int countpos = pos; + ++pos; + + int count = 0; + foreach (string val in message) + { + tmp = Util.StringToBytes256(val); + len = tmp.Length; + + if (pos + len >= LLUDPServer.MAXPAYLOAD) + { + data[countpos] = (byte)count; + buf.DataLength = pos; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(data, 0, newbuf.Data, 0, countpos); + buf = newbuf; + data = buf.Data; + pos = countpos + 1; + count = 1; + } + else + ++count; + + data[pos++] = (byte)len; + if (len > 0) + Buffer.BlockCopy(tmp, 0, data, pos, len); pos += len; + } + if (count > 0) + { + data[countpos] = (byte)count; + buf.DataLength = pos; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + } } public void SendGenericMessage(string method, UUID invoice, List message) { - GenericMessagePacket gmp = new GenericMessagePacket(); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; - gmp.AgentData.AgentID = AgentId; - gmp.AgentData.SessionID = m_sessionId; - gmp.AgentData.TransactionID = invoice; + //setup header + Buffer.BlockCopy(GenericMessageHeader, 0, data, 0, 10); - gmp.MethodData.Method = Util.StringToBytes256(method); - gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; - int i = 0; - foreach (byte[] val in message) + //agentdata block + m_agentId.ToBytes(data, 10); // 26 + m_sessionId.ToBytes(data, 26); // 42 sessionID zero?? TO check + UUID.Zero.ToBytes(data, 42); // 58 + + int pos = 58; + + //method block + byte[] tmp = Util.StringToBytes256(method); + int len = tmp.Length; + data[pos++] = (byte)len; + if (len > 0) + Buffer.BlockCopy(tmp, 0, data, pos, len); pos += len; + invoice.ToBytes(data, pos); pos += 16; + + //ParamList block + if (message.Count == 0) { - gmp.ParamList[i] = new GenericMessagePacket.ParamListBlock(); - gmp.ParamList[i++].Parameter = val; + data[pos++] = 0; + buf.DataLength = pos; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + return; } - OutPacket(gmp, ThrottleOutPacketType.Task); + int countpos = pos; + ++pos; + + int count = 0; + foreach (byte[] val in message) + { + len = val.Length; + if(len > 255) + len = 255; + + if (pos + len >= LLUDPServer.MAXPAYLOAD) + { + data[countpos] = (byte)count; + buf.DataLength = pos; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(data, 0, newbuf.Data, 0, countpos); + buf = newbuf; + data = buf.Data; + pos = countpos + 1; + count = 1; + } + else + ++count; + + data[pos++] = (byte)len; + if (len > 0) + Buffer.BlockCopy(val, 0, data, pos, len); pos += len; + } + if (count > 0) + { + data[countpos] = (byte)count; + buf.DataLength = pos; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + } } public void SendGroupActiveProposals(UUID groupID, UUID transactionID, GroupActiveProposals[] Proposals) @@ -1302,7 +1672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { s = 2 * i; OpenSimTerrainCompressor.CreatePatchFromTerrainData(bitpack, terrData, map[s], map[s + 1]); - if (bitpack.BytePos > 950 && i != numberPatchs - 1) + if (bitpack.BytePos > 900 && i != numberPatchs - 1) { //finish this packet bitpack.PackBitsFromByte(END_OF_PATCHES); @@ -1313,7 +1683,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP data[9] = (byte)(datasize >> 8); buf.DataLength = bitpack.BytePos + 1; - m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land, null, false, false); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land); // start another buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); @@ -1341,7 +1711,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP data[9] = (byte)(datasize >> 8); buf.DataLength = bitpack.BytePos + 1; - m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land, null, false, false); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land); } catch (Exception e) @@ -1561,57 +1931,210 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(newSimPack, ThrottleOutPacketType.Unknown); } - internal void SendMapBlockSplit(List mapBlocks, uint flag) + static private readonly byte[] MapBlockItemHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 1, 155 // ID 411 (low frequency bigendian) + }; + + public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags) { - MapBlockReplyPacket mapReply = (MapBlockReplyPacket)PacketPool.Instance.GetPacket(PacketType.MapBlockReply); - // TODO: don't create new blocks if recycling an old packet + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; - MapBlockData[] mapBlocks2 = mapBlocks.ToArray(); + //setup header and agentinfo block + Buffer.BlockCopy(MapBlockItemHeader, 0, data, 0, 10); + AgentId.ToBytes(data, 10); // 26 + Utils.UIntToBytesSafepos(flags, data, 26); // 30 - mapReply.AgentData.AgentID = AgentId; - mapReply.Data = new MapBlockReplyPacket.DataBlock[mapBlocks2.Length]; - mapReply.Size = new MapBlockReplyPacket.SizeBlock[mapBlocks2.Length]; - mapReply.AgentData.Flags = flag; + //RequestData block + Utils.UIntToBytesSafepos(mapitemtype, data, 30); // 34 - for (int i = 0; i < mapBlocks2.Length; i++) + int countpos = 34; + int pos = 35; + int lastpos = 0; + + int capacity = LLUDPServer.MAXPAYLOAD - pos; + + int count = 0; + + mapItemReply mr; + for (int k = 0; k < replies.Length; ++k) { - mapReply.Data[i] = new MapBlockReplyPacket.DataBlock(); - mapReply.Data[i].MapImageID = mapBlocks2[i].MapImageId; - //m_log.Warn(mapBlocks2[i].MapImageId.ToString()); - mapReply.Data[i].X = mapBlocks2[i].X; - mapReply.Data[i].Y = mapBlocks2[i].Y; - mapReply.Data[i].WaterHeight = mapBlocks2[i].WaterHeight; - mapReply.Data[i].Name = Utils.StringToBytes(mapBlocks2[i].Name); - mapReply.Data[i].RegionFlags = mapBlocks2[i].RegionFlags; - mapReply.Data[i].Access = mapBlocks2[i].Access; - mapReply.Data[i].Agents = mapBlocks2[i].Agents; + lastpos = pos; + mr = replies[k]; - mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock(); - mapReply.Size[i].SizeX = mapBlocks2[i].SizeX; - mapReply.Size[i].SizeY = mapBlocks2[i].SizeY; + Utils.UIntToBytesSafepos(mr.x, data, pos); pos += 4; + Utils.UIntToBytesSafepos(mr.y, data, pos); pos += 4; + mr.id.ToBytes(data, pos); pos += 16; + Utils.IntToBytesSafepos(mr.Extra, data, pos); pos += 4; + Utils.IntToBytesSafepos(mr.Extra2, data, pos); pos += 4; + byte[] itemName = Util.StringToBytes256(mr.name); + data[pos++] = (byte)itemName.Length; + if (itemName.Length > 0) + Buffer.BlockCopy(itemName, 0, data, pos, itemName.Length); pos += itemName.Length; + + if (pos < capacity) + ++count; + else + { + // prepare next packet + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(data, 0, newbuf.Data, 0, 34); + + // copy the block we already did + int alreadyDone = pos - lastpos; + Buffer.BlockCopy(data, lastpos, newbuf.Data, 35, alreadyDone); // 34 is datablock size + + // finish current + data[countpos] = (byte)count; + + buf.DataLength = lastpos; + // send it + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land); + + buf = newbuf; + data = buf.Data; + pos = alreadyDone + 35; + capacity = LLUDPServer.MAXPAYLOAD - pos; + + count = 1; + } + } + + if (count > 0) + { + data[countpos] = (byte)count; + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land); } - OutPacket(mapReply, ThrottleOutPacketType.Land); } - public void SendMapBlock(List mapBlocks, uint flag) + static private readonly byte[] MapBlockReplyHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 1, 153 // ID 409 (low frequency bigendian) + }; + + public void SendMapBlock(List mapBlocks, uint flags) { - MapBlockData[] mapBlocks2 = mapBlocks.ToArray(); + ushort[] sizes = new ushort[2 * mapBlocks.Count]; + bool needSizes = false; + int sizesptr = 0; - int maxsend = 10; - - //int packets = Math.Ceiling(mapBlocks2.Length / maxsend); - - List sendingBlocks = new List(); - - for (int i = 0; i < mapBlocks2.Length; i++) + // check if we will need sizes block and get them aside + int count = 0; + ushort ut; + foreach (MapBlockData md in mapBlocks) { - sendingBlocks.Add(mapBlocks2[i]); - if (((i + 1) == mapBlocks2.Length) || (((i + 1) % maxsend) == 0)) + ut = md.SizeX; + sizes[count++] = ut; + if (ut > 256) + needSizes = true; + + ut = md.SizeY; + sizes[count++] = ut; + if (ut > 256) + needSizes = true; + } + + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + //setup header and agentinfo block + Buffer.BlockCopy(MapBlockReplyHeader, 0, data, 0, 10); + AgentId.ToBytes(data, 10); // 26 + Utils.UIntToBytesSafepos(flags, data, 26); // 30 + + int countpos = 30; + int pos = 31; + int lastpos = 0; + + int capacity = LLUDPServer.MAXPAYLOAD - pos; + + count = 0; + + foreach (MapBlockData md in mapBlocks) + { + lastpos = pos; + + Utils.UInt16ToBytes(md.X, data, pos); pos += 2; + Utils.UInt16ToBytes(md.Y, data, pos); pos += 2; + byte[] regionName = Util.StringToBytes256(md.Name); + data[pos++] = (byte)regionName.Length; + if(regionName.Length > 0) + Buffer.BlockCopy(regionName, 0, data, pos, regionName.Length); pos += regionName.Length; + data[pos++] = md.Access; + Utils.UIntToBytesSafepos(md.RegionFlags, data, pos); pos += 4; + data[pos++] = md.WaterHeight; + data[pos++] = md.Agents; + md.MapImageId.ToBytes(data, pos); pos += 16; + + if(needSizes) + capacity -= 4; // 2 shorts per entry + + if(pos < capacity) + ++count; + else { - SendMapBlockSplit(sendingBlocks, flag); - sendingBlocks = new List(); + // prepare next packet + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(data, 0, newbuf.Data, 0, 30); + + // copy the block we already did + int alreadyDone = pos - lastpos; + Buffer.BlockCopy(data, lastpos, newbuf.Data, 31, alreadyDone); // 30 is datablock size + + // finish current + data[countpos] = (byte)count; + if (needSizes) + { + data[lastpos++] = (byte)count; + while (--count >= 0) + { + Utils.UInt16ToBytes(sizes[sizesptr++], data, lastpos); lastpos += 2; + Utils.UInt16ToBytes(sizes[sizesptr++], data, lastpos); lastpos += 2; + } + } + else + data[lastpos++] = 0; + + buf.DataLength = lastpos; + // send it + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land); + + buf = newbuf; + data = buf.Data; + pos = alreadyDone + 31; + capacity = LLUDPServer.MAXPAYLOAD - pos; + if (needSizes) + capacity -= 4; // 2 shorts per entry + + count = 1; } } + + if (count > 0) + { + data[countpos] = (byte)count; + if (needSizes) + { + data[pos++] = (byte)count; + while (--count >= 0) + { + Utils.UInt16ToBytes(sizes[sizesptr++], data, pos); pos += 2; + Utils.UInt16ToBytes(sizes[sizesptr++], data, pos); pos += 2; + } + } + else + data[pos++] = 0; + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Land); + } } public void SendLocalTeleport(Vector3 position, Vector3 lookAt, uint flags) @@ -1738,19 +2261,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(payPriceReply, ThrottleOutPacketType.Task); } - public void SendStartPingCheck(byte seq) - { - StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); - pc.Header.Reliable = false; - - pc.PingID.PingID = seq; - // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit - pc.PingID.OldestUnacked = 0; - - OutPacket(pc, ThrottleOutPacketType.Unknown); - UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); - } - public void SendKillObject(List localIDs) { // foreach (uint id in localIDs) @@ -1815,14 +2325,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // An inventory descendents packet consists of a single agent section and an inventory details // section for each inventory item. The size of each inventory item is approximately 550 bytes. - // In theory, UDP has a maximum packet size of 64k, so it should be possible to send descendent - // packets containing metadata for in excess of 100 items. But in practice, there may be other - // factors (e.g. firewalls) restraining the maximum UDP packet size. See, - // - // http://opensimulator.org/mantis/view.php?id=226 - // - // for one example of this kind of thing. In fact, the Linden servers appear to only send about - // 6 to 7 items at a time, so let's stick with 6 + // limit to what may fit on MTU int MAX_ITEMS_PER_PACKET = 5; int MAX_FOLDERS_PER_PACKET = 6; @@ -2349,34 +2852,102 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(scriptcontrol, ThrottleOutPacketType.Task); } + static private readonly byte[] ReplyTaskInventoryHeader = new byte[] { + Helpers.MSG_RELIABLE, //| Helpers.MSG_ZEROCODED, not doing spec zeroencode on this + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 1, 34 // ID 90 (low frequency bigendian) + }; + public void SendTaskInventory(UUID taskID, short serial, byte[] fileName) { - ReplyTaskInventoryPacket replytask = (ReplyTaskInventoryPacket)PacketPool.Instance.GetPacket(PacketType.ReplyTaskInventory); - replytask.InventoryData.TaskID = taskID; - replytask.InventoryData.Serial = serial; - replytask.InventoryData.Filename = fileName; -// OutPacket(replytask, ThrottleOutPacketType.Task); - OutPacket(replytask, ThrottleOutPacketType.Asset); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + //setup header + Buffer.BlockCopy(ReplyTaskInventoryHeader, 0, data, 0, 10); + + taskID.ToBytes(data, 10); // 26 + Utils.Int16ToBytes(serial, data, 26); // 28 + data[28] = (byte)fileName.Length; + if(data[28] > 0) + Buffer.BlockCopy(fileName, 0, data, 29, data[28]); + + buf.DataLength = 29 + data[28]; + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); } - public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory) + + static private readonly byte[] SendXferPacketHeader = new byte[] { + 0, //Helpers.MSG_RELIABLE, Xfer control must provide reliabialty + 0, 0, 0, 0, // sequence number + 0, // extra + 18 // ID (high frequency bigendian) + }; + + public void SendXferPacket(ulong xferID, uint packet, + byte[] XferData, int XferDataOffset, int XferDatapktLen, bool isTaskInventory) { - ThrottleOutPacketType type = ThrottleOutPacketType.Asset; -// if (isTaskInventory) -// type = ThrottleOutPacketType.Task; + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; - SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); - sendXfer.XferID.ID = xferID; - sendXfer.XferID.Packet = packet; - sendXfer.DataPacket.Data = data; - OutPacket(sendXfer, type); + //setup header + Buffer.BlockCopy(SendXferPacketHeader, 0, data, 0, 7); + + Utils.UInt64ToBytesSafepos(xferID, data, 7); // 15 + Utils.UIntToBytesSafepos(packet, data, 15); // 19 + + int len = XferDatapktLen; + if (XferDataOffset == 0) // first packet needs to send the total xfer data len + len += 4; + + if (len > LLUDPServer.MAXPAYLOAD) // should never happen + len = LLUDPServer.MAXPAYLOAD; + if (len == 0) + { + data[19] = 0; + data[20] = 0; + } + else + { + data[19] = (byte)len; + data[20] = (byte)(len >> 8); + if(XferDataOffset == 0) + { + // need to send total xfer data len + Utils.IntToBytesSafepos(XferData.Length, data, 21); + if (XferDatapktLen > 0) + Buffer.BlockCopy(XferData, XferDataOffset, data, 25, XferDatapktLen); + } + else + Buffer.BlockCopy(XferData, XferDataOffset, data, 21, XferDatapktLen); + } + + buf.DataLength = 21 + len; + m_udpServer.SendUDPPacket(m_udpClient, buf, isTaskInventory ? ThrottleOutPacketType.Task : ThrottleOutPacketType.Asset); } + static private readonly byte[] AbortXferHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 0, 157 // ID 157 (low frequency bigendian) + }; + public void SendAbortXferPacket(ulong xferID) { - AbortXferPacket xferItem = (AbortXferPacket)PacketPool.Instance.GetPacket(PacketType.AbortXfer); - xferItem.XferID.ID = xferID; - OutPacket(xferItem, ThrottleOutPacketType.Asset); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + //setup header + Buffer.BlockCopy(AbortXferHeader, 0, data, 0, 10); + + Utils.UInt64ToBytesSafepos(xferID, data, 10); // 18 + Utils.IntToBytesSafepos(0, data, 18); // 22 reason TODO + + buf.DataLength = 22; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Asset); } public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, @@ -3405,28 +3976,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, ThrottleOutPacketType.Task); } - public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags) - { - MapItemReplyPacket mirplk = new MapItemReplyPacket(); - mirplk.AgentData.AgentID = AgentId; - mirplk.RequestData.ItemType = mapitemtype; - mirplk.Data = new MapItemReplyPacket.DataBlock[replies.Length]; - for (int i = 0; i < replies.Length; i++) - { - MapItemReplyPacket.DataBlock mrdata = new MapItemReplyPacket.DataBlock(); - mrdata.X = replies[i].x; - mrdata.Y = replies[i].y; - mrdata.ID = replies[i].id; - mrdata.Extra = replies[i].Extra; - mrdata.Extra2 = replies[i].Extra2; - mrdata.Name = Utils.StringToBytes(replies[i].name); - mirplk.Data[i] = mrdata; - } - //m_log.Debug(mirplk.ToString()); - OutPacket(mirplk, ThrottleOutPacketType.Task); - - } - public void SendOfferCallingCard(UUID srcID, UUID transactionID) { // a bit special, as this uses AgentID to store the source instead @@ -3871,96 +4420,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); } - public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) + static private readonly byte[] AvatarAppearanceHeader = new byte[] { + Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 0, 158 // ID 158 (low frequency bigendian) not zeroencoded + //0xff, 0xff, 0, 1, 158 // ID 158 (low frequency bigendian) zeroencoded + }; + + public void SendAppearance(UUID targetID, byte[] visualParams, byte[] textureEntry) { -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending avatar appearance for {0} with {1} bytes to {2} {3}", -// agentID, textureEntry.Length, Name, AgentId); + // doing post zero encode, because odds of beeing bad are not that low + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(AvatarAppearanceHeader, 0, buf.Data, 0, 10); + byte[] data = buf.Data; + int pos = 10; - AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); - // TODO: don't create new blocks if recycling an old packet - avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length]; - avp.ObjectData.TextureEntry = textureEntry; + //sender block + targetID.ToBytes(data, pos); pos += 16; + data[pos++] = 0;// is trial = false - AvatarAppearancePacket.VisualParamBlock avblock = null; - for (int i = 0; i < visualParams.Length; i++) + // objectdata block ie texture + int len = textureEntry.Length; + if (len == 0) { - avblock = new AvatarAppearancePacket.VisualParamBlock(); - avblock.ParamValue = visualParams[i]; - avp.VisualParam[i] = avblock; - } - - avp.Sender.IsTrial = false; - avp.Sender.ID = agentID; - avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; - avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0]; - -// this need be use in future ? -// avp.AppearanceData[0].AppearanceVersion = 0; -// avp.AppearanceData[0].CofVersion = 0; - - //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); - OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); - } - -/* - public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) - { -// m_log.DebugFormat("[LLCLIENTVIEW]: Sending animations for {0} to {1}", sourceAgentId, Name); - - AvatarAnimationPacket ani = (AvatarAnimationPacket)PacketPool.Instance.GetPacket(PacketType.AvatarAnimation); - // TODO: don't create new blocks if recycling an old packet - ani.Sender = new AvatarAnimationPacket.SenderBlock(); - ani.Sender.ID = sourceAgentId; - ani.AnimationList = new AvatarAnimationPacket.AnimationListBlock[animations.Length]; - ani.PhysicalAvatarEventList = new AvatarAnimationPacket.PhysicalAvatarEventListBlock[0]; - - //self animations - if (sourceAgentId == AgentId) - { - List withobjects = new List(animations.Length); - List noobjects = new List(animations.Length); - for(int i = 0; i < animations.Length; ++i) - { - if(objectIDs[i] == sourceAgentId || objectIDs[i] == UUID.Zero) - noobjects.Add(i); - else - withobjects.Add(i); - } - - ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[withobjects.Count]; - int k = 0; - foreach (int i in withobjects) - { - ani.AnimationList[k] = new AvatarAnimationPacket.AnimationListBlock(); - ani.AnimationList[k].AnimID = animations[i]; - ani.AnimationList[k].AnimSequenceID = seqs[i]; - ani.AnimationSourceList[k] = new AvatarAnimationPacket.AnimationSourceListBlock(); - ani.AnimationSourceList[k].ObjectID = objectIDs[i]; - k++; - } - foreach (int i in noobjects) - { - ani.AnimationList[k] = new AvatarAnimationPacket.AnimationListBlock(); - ani.AnimationList[k].AnimID = animations[i]; - ani.AnimationList[k].AnimSequenceID = seqs[i]; - k++; - } + data[pos++] = 0; + data[pos++] = 0; } else { - ani.AnimationSourceList = new AvatarAnimationPacket.AnimationSourceListBlock[0]; - for (int i = 0; i < animations.Length; ++i) - { - ani.AnimationList[i] = new AvatarAnimationPacket.AnimationListBlock(); - ani.AnimationList[i].AnimID = animations[i]; - ani.AnimationList[i].AnimSequenceID = seqs[i]; - } + data[pos++] = (byte)len; + data[pos++] = (byte)(len >> 8); + Buffer.BlockCopy(textureEntry, 0, data, pos, len); pos += len; } - OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); + // visual parameters + len = visualParams.Length; + data[pos++] = (byte)len; + if(len > 0) + Buffer.BlockCopy(visualParams, 0, data, pos, len); pos += len; + + // no AppearanceData + data[pos++] = 0; + // no AppearanceHover + data[pos++] = 0; + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority, null, false, true); } -*/ static private readonly byte[] AvatarAnimationHeader = new byte[] { Helpers.MSG_RELIABLE, @@ -4030,8 +4537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP data[pos++] = 0; // no physical avatar events buf.DataLength = pos; - m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority, - null, false, false); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); } public void SendObjectAnimations(UUID[] animations, int[] seqs, UUID senderId) @@ -4088,84 +4594,102 @@ namespace OpenSim.Region.ClientStack.LindenUDP CreatePrimUpdateBlock(ent as SceneObjectPart, (ScenePresence)SceneAgent, zc); buf.DataLength = zc.Finish(); - m_udpServer.SendUDPPacket(m_udpClient, buf, ptype , null, false, false); + m_udpServer.SendUDPPacket(m_udpClient, buf, ptype); } public void SendEntityTerseUpdateImmediate(ISceneEntity ent) { -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}", -// avatar.Name, avatar.UUID, Name, AgentId); - if (ent == null) return; - ImprovedTerseObjectUpdatePacket objupdate = - (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); - objupdate.Header.Zerocoded = true; + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); - objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); - objupdate.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; + //setup header and regioninfo block + Buffer.BlockCopy(terseUpdateHeader, 0, buf.Data, 0, 7); + if (ent is ScenePresence) + Utils.UInt64ToBytesSafepos(((ScenePresence)ent).RegionHandle, buf.Data, 7); + else + Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, buf.Data, 7); - if(ent is ScenePresence) - { - ScenePresence presence = ent as ScenePresence; - objupdate.RegionData.RegionHandle = presence.RegionHandle; - objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent); - } - else if(ent is SceneObjectPart) - { - SceneObjectPart part = ent as SceneObjectPart; - objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent); - } + Utils.UInt16ToBytes(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f), buf.Data, 15); + buf.Data[17] = 1; - OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority); + int pos = 18; + CreateImprovedTerseBlock(ent, buf.Data, ref pos, false); - // We need to record the avatar local id since the root prim of an attachment points to this. -// m_attachmentsSent.Add(avatar.LocalId); + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); } + //UUID m_courseLocationPrey = UUID.Zero; + bool m_couseLocationLastEmpty = false; + + static private readonly byte[] CoarseLocationUpdateHeader = new byte[] { + 0, // no acks plz + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 6 // ID 6 (medium frequency) + }; + public void SendCoarseLocationUpdate(List users, List CoarseLocations) { // We don't need to update inactive clients. if (!IsActive) return; - CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate); - loc.Header.Reliable = false; + int totalLocations = Math.Min(CoarseLocations.Count, 60); + if(totalLocations == 0) + { + if(m_couseLocationLastEmpty) + return; + m_couseLocationLastEmpty = true; + } + else + m_couseLocationLastEmpty = false; - // Each packet can only hold around 60 avatar positions and the client clears the mini-map each time - // a CoarseLocationUpdate packet is received. Oh well. - int total = Math.Min(CoarseLocations.Count, 60); - - CoarseLocationUpdatePacket.IndexBlock ib = new CoarseLocationUpdatePacket.IndexBlock(); - - loc.Location = new CoarseLocationUpdatePacket.LocationBlock[total]; - loc.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[total]; + int totalAgents = Math.Min(users.Count, 60); + if(totalAgents > totalLocations) + totalAgents = totalLocations; int selfindex = -1; - for (int i = 0; i < total; i++) + int preyindex = -1; + + //bool doprey = m_courseLocationPrey != UUID.Zero; + + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(CoarseLocationUpdateHeader, 0, buf.Data, 0, 8); + byte[] data = buf.Data; + + data[8] = (byte)totalLocations; + int pos = 9; + + for (int i = 0; i < totalLocations; ++i) { - CoarseLocationUpdatePacket.LocationBlock lb = - new CoarseLocationUpdatePacket.LocationBlock(); - - lb.X = (byte)CoarseLocations[i].X; - lb.Y = (byte)CoarseLocations[i].Y; - - lb.Z = CoarseLocations[i].Z > 1024 ? (byte)0 : (byte)(CoarseLocations[i].Z * 0.25f); - loc.Location[i] = lb; - loc.AgentData[i] = new CoarseLocationUpdatePacket.AgentDataBlock(); - loc.AgentData[i].AgentID = users[i]; - if (users[i] == AgentId) - selfindex = i; + data[pos++] = (byte)CoarseLocations[i].X; + data[pos++] = (byte)CoarseLocations[i].Y; + data[pos++] = CoarseLocations[i].Z > 1024 ? (byte)0 : (byte)(CoarseLocations[i].Z * 0.25f); + + if (i < totalAgents) + { + if (users[i] == AgentId) + selfindex = i; + //if (doprey && users[i] == m_courseLocationPrey) + // preyindex = i; + } } - ib.You = (short)selfindex; - ib.Prey = -1; - loc.Index = ib; + Utils.Int16ToBytes((short)selfindex, data, pos); pos += 2; + Utils.Int16ToBytes((short)preyindex, data, pos); pos += 2; - OutPacket(loc, ThrottleOutPacketType.Task); + data[pos++] = (byte)totalAgents; + for (int i = 0; i < totalAgents; ++i) + { + users[i].ToBytes(data, pos); + pos += 16; + } + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); } #endregion Avatar Packet/Data Sending Methods @@ -4178,20 +4702,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) { -/* - if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) - { - ImprovedTerseObjectUpdatePacket packet - = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); - - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = Utils.FloatToUInt16(1, 0.0f, 1.0f); - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; - packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false); - OutPacket(packet, ThrottleOutPacketType.Unknown, true); - return; - } -*/ if (entity is SceneObjectPart) { SceneObjectPart p = (SceneObjectPart)entity; @@ -4210,7 +4720,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - //double priority = m_prioritizer.GetUpdatePriority(this, entity); uint priority = m_prioritizer.GetUpdatePriority(this, entity); lock (m_entityUpdates.SyncRoot) @@ -4273,6 +4782,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP 15 // ID (high frequency) }; + static private readonly byte[] ObjectAnimationHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 30 // ID (high frequency) + }; + + static private readonly byte[] CompressedObjectHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 13 // ID (high frequency) + }; + + static private readonly byte[] ObjectUpdateCachedHeader = new byte[] { + Helpers.MSG_RELIABLE, + 0, 0, 0, 0, // sequence number + 0, // extra + 14 // ID (high frequency) + }; + private void ProcessEntityUpdates(int maxUpdatesBytes) { if (!IsActive) @@ -4282,9 +4812,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (mysp == null) return; - // List compressedUpdateBlocks = null; + List objectUpdates = null; - // List compressedUpdates = null; + List objectUpdateProbes = null; + List compressedUpdates = null; List terseUpdates = null; List ObjectAnimationUpdates = null; @@ -4296,6 +4827,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP EntityUpdate update; + bool viewerCache = m_supportViewerCache;// && mysp.IsChildAgent; // only on child agents bool doCulling = m_scene.ObjectsCullingByDistance; float cullingrange = 64.0f; Vector3 mypos = Vector3.Zero; @@ -4304,7 +4836,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP bool orderedDequeue = false; // temporary off HashSet GroupsNeedFullUpdate = new HashSet(); - + bool useCompressUpdate = false; if (doCulling) { @@ -4331,15 +4863,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; + PrimUpdateFlags updateFlags = update.Flags; - if(updateFlags.HasFlag(PrimUpdateFlags.Kill)) + if (updateFlags.HasFlag(PrimUpdateFlags.Kill)) { m_killRecord.Add(update.Entity.LocalId); maxUpdatesBytes -= 30; continue; } + useCompressUpdate = false; + bool istree = false; + if (update.Entity is SceneObjectPart) { SceneObjectPart part = (SceneObjectPart)update.Entity; @@ -4425,10 +4960,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (dpos > maxview * maxview) continue; - GroupsNeedFullUpdate.Add(grp); - continue; + if (!viewerCache || !updateFlags.HasFlag(PrimUpdateFlags.UpdateProbe)) + { + GroupsNeedFullUpdate.Add(grp); + continue; + } } } + + if (updateFlags.HasFlag(PrimUpdateFlags.UpdateProbe)) + { + if (objectUpdateProbes == null) + { + objectUpdateProbes = new List(); + maxUpdatesBytes -= 18; + } + objectUpdateProbes.Add(update); + maxUpdatesBytes -= 12; + continue; + } + + if (updateFlags == PrimUpdateFlags.Animations) + { + if (m_SupportObjectAnimations && part.Animations != null) + { + if (ObjectAnimationUpdates == null) + ObjectAnimationUpdates = new List(); + ObjectAnimationUpdates.Add(part); + maxUpdatesBytes -= 20 * part.Animations.Count + 24; + } + continue; + } + + if(viewerCache) + useCompressUpdate = grp.IsViewerCachable; + + istree = (part.Shape.PCode == (byte)PCode.Grass || part.Shape.PCode == (byte)PCode.NewTree || part.Shape.PCode == (byte)PCode.Tree); } else if (update.Entity is ScenePresence) { @@ -4448,42 +5015,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region UpdateFlags to packet type conversion - // bool canUseCompressed = true; - - if (update.Entity is SceneObjectPart) - { - if (m_SupportObjectAnimations && updateFlags.HasFlag(PrimUpdateFlags.Animations)) - { - SceneObjectPart sop = (SceneObjectPart)update.Entity; - if ( sop.Animations != null) - { - if(ObjectAnimationUpdates == null) - ObjectAnimationUpdates = new List(); - ObjectAnimationUpdates.Add(sop); - maxUpdatesBytes -= 20 * sop.Animations.Count + 24; - } - } - } - else - { - // canUseCompressed = false; - } - updateFlags &= PrimUpdateFlags.FullUpdate; // clear other control bits already handled if(updateFlags == PrimUpdateFlags.None) continue; - /* - const PrimUpdateFlags canNotUseCompressedMask = - PrimUpdateFlags.Velocity | PrimUpdateFlags.Acceleration | - PrimUpdateFlags.CollisionPlane | PrimUpdateFlags.Joint; - - if ((updateFlags & canNotUseCompressedMask) != 0) - { - canUseCompressed = false; - } - */ - const PrimUpdateFlags canNotUseImprovedMask = ~( PrimUpdateFlags.AttachmentPoint | PrimUpdateFlags.Position | @@ -4499,19 +5034,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Block Construction - // TODO: Remove this once we can build compressed updates - /* - if (canUseCompressed) - { - ObjectUpdateCompressedPacket.ObjectDataBlock ablock = - CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags); - compressedUpdateBlocks.Add(ablock); - compressedUpdates.Value.Add(update); - maxUpdatesBytes -= ablock.Length; - } - else if (canUseImproved) - */ - if ((updateFlags & canNotUseImprovedMask) == 0) { if (terseUpdates == null) @@ -4534,16 +5056,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP else { if (update.Entity is ScenePresence) - maxUpdatesBytes -= 150; // crude estimation - else - maxUpdatesBytes -= 300; - - if(objectUpdates == null) { - objectUpdates = new List(); - maxUpdatesBytes -= 18; + maxUpdatesBytes -= 150; // crude estimation + + if (objectUpdates == null) + { + objectUpdates = new List(); + maxUpdatesBytes -= 18; + } + objectUpdates.Add(update); + } + else + { + if (useCompressUpdate) + { + if (istree) + maxUpdatesBytes -= 64; + else + maxUpdatesBytes -= 120; // crude estimation + + if (compressedUpdates == null) + { + compressedUpdates = new List(); + maxUpdatesBytes -= 18; + } + compressedUpdates.Add(update); + } + else + { + if (istree) + maxUpdatesBytes -= 70; + else + maxUpdatesBytes -= 150; // crude estimation + + if (objectUpdates == null) + { + objectUpdates = new List(); + maxUpdatesBytes -= 18; + } + objectUpdates.Add(update); + } } - objectUpdates.Add(update); } #endregion Block Construction @@ -4560,7 +5113,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if(objectUpdates != null) { - int blocks = objectUpdates.Count; List tau = new List(30); UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); @@ -4570,7 +5122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP zc.Position = 7; zc.AddUInt64(m_scene.RegionInfo.RegionHandle); - zc.AddUInt16(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f)); + zc.AddUInt16(timeDilation); zc.AddByte(1); // tmp block count @@ -4587,14 +5139,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (eu.Entity is ScenePresence) CreateAvatarUpdateBlock((ScenePresence)eu.Entity, zc); else - CreatePrimUpdateBlock((SceneObjectPart)eu.Entity, mysp, zc); - if (zc.Position < LLUDPServer.MAXPAYLOAD) + { + SceneObjectPart part = (SceneObjectPart)eu.Entity; + if (eu.Flags.HasFlag(PrimUpdateFlags.Animations)) + { + if (m_SupportObjectAnimations && part.Animations != null) + { + if (ObjectAnimationUpdates == null) + ObjectAnimationUpdates = new List(); + ObjectAnimationUpdates.Add(part); + } + eu.Flags &= ~PrimUpdateFlags.Animations; + } + CreatePrimUpdateBlock(part, mysp, zc); + } + if (zc.Position < LLUDPServer.MAXPAYLOAD - 300) { tau.Add(eu); ++count; - --blocks; } - else if (blocks > 0) + else { // we need more packets UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); @@ -4610,7 +5174,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP buf.DataLength = lastpos; m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, - delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + null, false, false); buf = newbuf; zc.Data = buf.Data; @@ -4625,7 +5190,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP tau = new List(30); tau.Add(eu); count = 1; - --blocks; } } @@ -4634,22 +5198,232 @@ namespace OpenSim.Region.ClientStack.LindenUDP buf.Data[countposition] = (byte)count; buf.DataLength = zc.Finish(); m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, - delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + null, false, false); } } -/* - if (compressedUpdateBlocks != null) + /* no zero encode compressed updates + if(compressedUpdates != null) { - ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = compressedUpdateBlocks.ToArray(); - compressedUpdateBlocks.Clear(); + List tau = new List(30); - OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates, oPacket); }); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + Buffer.BlockCopy(CompressedObjectHeader, 0, data , 0, 7); + + Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, data, 7); // 15 + Utils.UInt16ToBytes(timeDilation, data, 15); // 17 + + int countposition = 17; // blocks count position + int pos = 18; + + int lastpos = 0; + + int count = 0; + foreach (EntityUpdate eu in compressedUpdates) + { + SceneObjectPart sop = (SceneObjectPart)eu.Entity; + if (sop.ParentGroup == null || sop.ParentGroup.IsDeleted) + continue; + lastpos = pos; + CreateCompressedUpdateBlock(sop, mysp, data, ref pos); + if (pos < LLUDPServer.MAXPAYLOAD) + { + tau.Add(eu); + ++count; + } + else + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same + + buf.Data[countposition] = (byte)count; + + buf.DataLength = lastpos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + + buf = newbuf; + data = buf.Data; + + pos = 18; + // im lazy now, just do last again + CreateCompressedUpdateBlock(sop, mysp, data, ref pos); + tau = new List(30); + tau.Add(eu); + count = 1; + } + } + + if (count > 0) + { + buf.Data[countposition] = (byte)count; + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + } } -*/ + */ + + if (compressedUpdates != null) + { + List tau = new List(30); + + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + Buffer.BlockCopy(CompressedObjectHeader, 0, data, 0, 7); + data[0] |= Helpers.MSG_ZEROCODED; + + LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); + zc.Position = 7; + + zc.AddUInt64(m_scene.RegionInfo.RegionHandle); + zc.AddUInt16(timeDilation); + + zc.AddByte(1); // tmp block count + + int countposition = zc.Position - 1; + + int lastpos = 0; + int lastzc = 0; + + int count = 0; + foreach (EntityUpdate eu in compressedUpdates) + { + SceneObjectPart sop = (SceneObjectPart)eu.Entity; + if (sop.ParentGroup == null || sop.ParentGroup.IsDeleted) + continue; + + if (eu.Flags.HasFlag(PrimUpdateFlags.Animations)) + { + if (m_SupportObjectAnimations && sop.Animations != null) + { + if (ObjectAnimationUpdates == null) + ObjectAnimationUpdates = new List(); + ObjectAnimationUpdates.Add(sop); + } + eu.Flags &= ~PrimUpdateFlags.Animations; + } + + lastpos = zc.Position; + lastzc = zc.ZeroCount; + + CreateCompressedUpdateBlockZC(sop, mysp, zc); + if (zc.Position < LLUDPServer.MAXPAYLOAD - 200) + { + //tau.Add(eu); + ++count; + } + else + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same + + buf.Data[countposition] = (byte)count; + // get pending zeros at cut point + if (lastzc > 0) + { + buf.Data[lastpos++] = 0; + buf.Data[lastpos++] = (byte)lastzc; + } + buf.DataLength = lastpos; + + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + null, false, false); + + buf = newbuf; + zc.Data = buf.Data; + + data[0] |= Helpers.MSG_ZEROCODED; + + zc.ZeroCount = 0; + zc.Position = countposition + 1; + + // im lazy now, just do last again + CreateCompressedUpdateBlockZC(sop, mysp, zc); + tau = new List(30); + //tau.Add(eu); + count = 1; + } + } + + if (count > 0) + { + buf.Data[countposition] = (byte)count; + buf.DataLength = zc.Finish(); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + null, false, false); + } + } + + if (objectUpdateProbes != null) + { + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; + + Buffer.BlockCopy(ObjectUpdateCachedHeader, 0, data, 0, 7); + + Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, data, 7); // 15 + Utils.UInt16ToBytes(timeDilation, data, 15); // 17 + + int countposition = 17; // blocks count position + int pos = 18; + + int count = 0; + foreach (EntityUpdate eu in objectUpdateProbes) + { + SceneObjectPart sop = (SceneObjectPart)eu.Entity; + if (sop.ParentGroup == null || sop.ParentGroup.IsDeleted) + continue; + uint primflags = m_scene.Permissions.GenerateClientFlags(sop, mysp); + if (mysp.UUID != sop.OwnerID) + primflags &= ~(uint)PrimFlags.CreateSelected; + else + { + if (sop.CreateSelected) + primflags |= (uint)PrimFlags.CreateSelected; + else + primflags &= ~(uint)PrimFlags.CreateSelected; + } + + Utils.UIntToBytes(sop.LocalId, data, pos); pos += 4; + Utils.UIntToBytes((uint)sop.ParentGroup.PseudoCRC, data, pos); pos += 4; //WRONG + Utils.UIntToBytes(primflags, data, pos); pos += 4; + + if (pos < (LLUDPServer.MAXPAYLOAD - 12)) + ++count; + else + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same + + buf.Data[countposition] = (byte)count; + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, false); + + buf = newbuf; + data = buf.Data; + pos = 18; + count = 0; + } + } + + if (count > 0) + { + buf.Data[countposition] = (byte)count; + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, false); + } + } + if (terseUpdates != null) { int blocks = terseUpdates.Count; @@ -4691,7 +5465,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP buf.DataLength = lastpos; // zero encode is not as spec m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, - delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, true); + //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, true); + null, false, true); tau = new List(30); tau.Add(eu); @@ -4706,7 +5481,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP buf.Data[17] = (byte)count; buf.DataLength = pos; m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, - delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, true); + //delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, true); + null, false, true); } } @@ -4716,6 +5492,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (sop.Animations == null) continue; + SceneObjectGroup sog = sop.ParentGroup; if (sog == null || sog.IsDeleted) continue; @@ -4728,18 +5505,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP int[] seqs = null; int count = sop.GetAnimations(out ids, out seqs); - ObjectAnimationPacket ani = (ObjectAnimationPacket)PacketPool.Instance.GetPacket(PacketType.ObjectAnimation); - ani.Sender = new ObjectAnimationPacket.SenderBlock(); - ani.Sender.ID = sop.UUID; - ani.AnimationList = new ObjectAnimationPacket.AnimationListBlock[count]; + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; - for(int i = 0; i< count; i++) + //setup header + Buffer.BlockCopy(ObjectAnimationHeader, 0, data , 0, 7); + + // sender block + sop.UUID.ToBytes(data, 7); // 23 + + //animations block + if (count > 255) + count = 255; + + data[23] = (byte)count; + + int pos = 24; + for(int i = 0; i < count; i++) { - ani.AnimationList[i] = new ObjectAnimationPacket.AnimationListBlock(); - ani.AnimationList[i].AnimID = ids[i]; - ani.AnimationList[i].AnimSequenceID = seqs[i]; + ids[i].ToBytes(data, pos); pos += 16; + Utils.IntToBytesSafepos(seqs[i], data, pos); pos += 4; } - OutPacket(ani, ThrottleOutPacketType.Task, true); + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); } } @@ -4758,8 +5547,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP { lock (GroupsInView) GroupsInView.Add(grp); + PrimUpdateFlags flags = PrimUpdateFlags.CancelKill; + if(viewerCache && grp.IsViewerCachable) + flags |= PrimUpdateFlags.UpdateProbe; foreach (SceneObjectPart p in grp.Parts) - SendEntityUpdate(p, PrimUpdateFlags.CancelKill); + SendEntityUpdate(p, flags); } } @@ -4838,27 +5630,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (e != null && e is SceneObjectGroup) { SceneObjectGroup grp = (SceneObjectGroup)e; - if(grp.IsDeleted || grp.IsAttachment) + if(grp.IsDeleted || grp.IsAttachment ) continue; bool inviewgroups; lock (GroupsInView) inviewgroups = GroupsInView.Contains(grp); - Vector3 grppos = grp.getCenterOffset(); - float dpos = (grppos - mypos).LengthSquared(); - - float maxview = grp.GetBoundsRadius() + cullingrange; - if (dpos > maxview * maxview) + //temp handling of sits + if(grp.GetSittingAvatarsCount() > 0) { - if(inviewgroups) - kills.Add(grp); + if (!inviewgroups) + GroupsNeedFullUpdate.Add(grp); + NewGroupsInView.Add(grp); } else { - if(!inviewgroups) - GroupsNeedFullUpdate.Add(grp); - NewGroupsInView.Add(grp); + Vector3 grppos = grp.getCenterOffset(); + float dpos = (grppos - mypos).LengthSquared(); + + float maxview = grp.GetBoundsRadius() + cullingrange; + if (dpos > maxview * maxview) + { + if(inviewgroups) + kills.Add(grp); + } + else + { + if (!inviewgroups) + GroupsNeedFullUpdate.Add(grp); + NewGroupsInView.Add(grp); + } } } } @@ -4890,13 +5692,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP if(GroupsNeedFullUpdate.Count > 0) { - foreach(SceneObjectGroup grp in GroupsNeedFullUpdate) + bool sendProbes = m_supportViewerCache && (m_viewerHandShakeFlags & 2) == 0; + + if(sendProbes) { - foreach(SceneObjectPart p in grp.Parts) - SendEntityUpdate(p, PrimUpdateFlags.CancelKill); + foreach (SceneObjectGroup grp in GroupsNeedFullUpdate) + { + PrimUpdateFlags flags = PrimUpdateFlags.CancelKill; + if (grp.IsViewerCachable) + flags |= PrimUpdateFlags.UpdateProbe; + foreach (SceneObjectPart p in grp.Parts) + SendEntityUpdate(p, flags); + } + } + else + { + m_viewerHandShakeFlags &= ~2U; // nexttime send probes + PrimUpdateFlags flags = PrimUpdateFlags.CancelKill; + foreach (SceneObjectGroup grp in GroupsNeedFullUpdate) + { + foreach (SceneObjectPart p in grp.Parts) + SendEntityUpdate(p, flags); + } } } - CheckGroupsInViewBusy = false; } @@ -5044,20 +5863,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(PacketPool.Instance.GetPacket(PacketType.DisableSimulator), ThrottleOutPacketType.Unknown); } + static private readonly byte[] SimStatsHeader = new byte[] { + 0, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 0, 140 // ID 140 (low frequency bigendian) + }; + public void SendSimStats(SimStats stats) { - SimStatsPacket pack = new SimStatsPacket(); - pack.Region = new SimStatsPacket.RegionBlock(); - pack.Region.RegionX = stats.RegionX; - pack.Region.RegionY = stats.RegionY; - pack.Region.RegionFlags = stats.RegionFlags; - pack.Region.ObjectCapacity = stats.ObjectCapacity; - //pack.Region = //stats.RegionBlock; - pack.Stat = stats.StatsBlock; + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + byte[] data = buf.Data; - pack.Header.Reliable = false; - pack.RegionInfo = new SimStatsPacket.RegionInfoBlock[0]; - OutPacket(pack, ThrottleOutPacketType.Task); + //setup header + Buffer.BlockCopy(SimStatsHeader, 0, data, 0, 10); + + // Region Block + Utils.UIntToBytesSafepos(stats.RegionX, data, 10); + Utils.UIntToBytesSafepos(stats.RegionY, data, 14); + Utils.UIntToBytesSafepos(stats.RegionFlags, data, 18); + Utils.UIntToBytesSafepos(stats.ObjectCapacity, data, 22); // 26 + + // stats + data[26] = (byte)stats.StatsBlock.Length; + int pos = 27; + + stats.StatsBlock[15].StatValue /= 1024; // unack is in KB + for (int i = 0; i< stats.StatsBlock.Length; ++i) + { + Utils.UIntToBytesSafepos(stats.StatsBlock[i].StatID, data, pos); pos += 4; + Utils.FloatToBytesSafepos(stats.StatsBlock[i].StatValue, data, pos); pos += 4; + } + + //no PID + Utils.IntToBytesSafepos(0, data, pos); pos += 4; + + // no regioninfo (extended flags) + data[pos++] = 0; // = 1; + //Utils.UInt64ToBytesSafepos(RegionFlagsExtended, data, pos); pos += 8; + + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); } private class ObjectPropertyUpdate : EntityUpdate @@ -5121,14 +5967,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); } + static private readonly byte[] ObjectPropertyUpdateHeader = new byte[] { + Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 9 // ID (medium frequency) + }; + + static private readonly byte[] ObjectFamilyUpdateHeader = new byte[] { + Helpers.MSG_RELIABLE | Helpers.MSG_ZEROCODED, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 10 // ID (medium frequency) + }; + private void ProcessEntityPropertyRequests(int maxUpdateBytes) { - List objectFamilyBlocks = null; - List objectPropertiesBlocks = null; + List objectPropertiesUpdates = null; + List objectPropertiesFamilyUpdates = null; List needPhysics = null; - bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; - + // bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance; + bool orderedDequeue = false; // for now EntityUpdate iupdate; while (maxUpdateBytes > 0) @@ -5153,11 +6013,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (update.Entity is SceneObjectPart) { SceneObjectPart sop = (SceneObjectPart)update.Entity; - ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); - if(objectFamilyBlocks == null) - objectFamilyBlocks = new List(); - objectFamilyBlocks.Add(objPropDB); - maxUpdateBytes -= objPropDB.Length; + if(objectPropertiesFamilyUpdates == null) + objectPropertiesFamilyUpdates = new List(); + objectPropertiesFamilyUpdates.Add(update); + maxUpdateBytes -= 100; } } @@ -5169,58 +6028,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP if(needPhysics == null) needPhysics = new List(); needPhysics.Add(sop); - ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); - if(objectPropertiesBlocks == null) - objectPropertiesBlocks = new List(); - objectPropertiesBlocks.Add(objPropDB); - maxUpdateBytes -= objPropDB.Length; + if(objectPropertiesUpdates == null) + objectPropertiesUpdates = new List(); + objectPropertiesUpdates.Add(update); + maxUpdateBytes -= 200; // aprox } } } - if (objectPropertiesBlocks != null) + if (objectPropertiesUpdates != null) { - ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count]; - for (int i = 0; i < objectPropertiesBlocks.Count; i++) - packet.ObjectData[i] = objectPropertiesBlocks[i]; + int blocks = objectPropertiesUpdates.Count; + //List tau = new List(30); - // Pass in the delegate so that if this packet needs to be resent, we send the current properties - // of the object rather than the properties when the packet was created - // HACK : Remove intelligent resending until it's fixed in core - //OutPacket(packet, ThrottleOutPacketType.Task, true, - // delegate(OutgoingPacket oPacket) - // { - // ResendPropertyUpdates(propertyUpdates.Value, oPacket); - // }); - OutPacket(packet, ThrottleOutPacketType.Task, true); - } + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(ObjectPropertyUpdateHeader, 0, buf.Data, 0, 8); - if (objectFamilyBlocks != null) - { - // one packet per object block... uggh... - for (int i = 0; i < objectFamilyBlocks.Count; i++) + LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); + zc.Position = 8; + + zc.AddByte(1); // tmp block count + + int countposition = zc.Position - 1; + + int lastpos = 0; + int lastzc = 0; + + int count = 0; + foreach (EntityUpdate eu in objectPropertiesUpdates) { - ObjectPropertiesFamilyPacket packet = - (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); + lastpos = zc.Position; + lastzc = zc.ZeroCount; + CreateObjectPropertiesBlock((SceneObjectPart)eu.Entity, zc); + if (zc.Position < LLUDPServer.MAXPAYLOAD) + { + //tau.Add(eu); + ++count; + --blocks; + } + else if (blocks > 0) + { + // we need more packets + UDPPacketBuffer newbuf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(buf.Data, 0, newbuf.Data, 0, countposition); // start is the same - packet.ObjectData = objectFamilyBlocks[i]; + buf.Data[countposition] = (byte)count; + // get pending zeros at cut point + if (lastzc > 0) + { + buf.Data[lastpos++] = 0; + buf.Data[lastpos++] = (byte)lastzc; + } + buf.DataLength = lastpos; - // Pass in the delegate so that if this packet needs to be resent, we send the current properties - // of the object rather than the properties when the packet was created -// List updates = new List(); -// updates.Add(familyUpdates.Value[i]); - // HACK : Remove intelligent resending until it's fixed in core - //OutPacket(packet, ThrottleOutPacketType.Task, true, - // delegate(OutgoingPacket oPacket) - // { - // ResendPropertyUpdates(updates, oPacket); - // }); - OutPacket(packet, ThrottleOutPacketType.Task, true); + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + // delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + buf = newbuf; + zc.Data = buf.Data; + zc.ZeroCount = 0; + zc.Position = countposition + 1; + // im lazy now, just do last again + CreateObjectPropertiesBlock((SceneObjectPart)eu.Entity, zc); + + //tau = new List(30); + //tau.Add(eu); + count = 1; + --blocks; + } + } + + if (count > 0) + { + buf.Data[countposition] = (byte)count; + buf.DataLength = zc.Finish(); + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + // delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); } } - if(needPhysics != null) + if (objectPropertiesFamilyUpdates != null) + { + foreach (EntityUpdate eu in objectPropertiesFamilyUpdates) + { + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); + Buffer.BlockCopy(ObjectFamilyUpdateHeader, 0, buf.Data, 0, 8); + + LLUDPZeroEncoder zc = new LLUDPZeroEncoder(buf.Data); + zc.Position = 8; + + CreateObjectPropertiesFamilyBlock((SceneObjectPart)eu.Entity, eu.Flags, zc); + buf.DataLength = zc.Finish(); + //List tau = new List(1); + //tau.Add(new ObjectPropertyUpdate((ISceneEntity) eu, (uint)eu.Flags, true, false)); + //m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, + // delegate (OutgoingPacket oPacket) { ResendPrimUpdates(tau, oPacket); }, false, false); + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task); + } + } + + if (needPhysics != null) { IEventQueue eq = Scene.RequestModuleInterface(); if(eq != null) @@ -5245,101 +6153,98 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, PrimUpdateFlags requestFlags) + private void CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, PrimUpdateFlags requestFlags, LLUDPZeroEncoder zc) { - ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - - block.RequestFlags = (uint)requestFlags; - block.ObjectID = sop.UUID; - if (sop.OwnerID == sop.GroupID) - block.OwnerID = UUID.Zero; - else - block.OwnerID = sop.OwnerID; - block.GroupID = sop.GroupID; - block.BaseMask = sop.BaseMask; - block.OwnerMask = sop.OwnerMask; - block.GroupMask = sop.GroupMask; - block.EveryoneMask = sop.EveryoneMask; - block.NextOwnerMask = sop.NextOwnerMask; - - // TODO: More properties are needed in SceneObjectPart! - block.OwnershipCost = sop.OwnershipCost; - block.SaleType = sop.ObjectSaleType; - block.SalePrice = sop.SalePrice; - block.Category = sop.Category; - block.LastOwnerID = sop.LastOwnerID; - block.Name = Util.StringToBytes256(sop.Name); - block.Description = Util.StringToBytes256(sop.Description); - - return block; - } - - private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) - { - //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - // TODO: don't create new blocks if recycling an old packet - - ObjectPropertiesPacket.ObjectDataBlock block = - new ObjectPropertiesPacket.ObjectDataBlock(); - - block.ObjectID = sop.UUID; - block.Name = Util.StringToBytes256(sop.Name); - block.Description = Util.StringToBytes256(sop.Description); - - block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds - block.CreatorID = sop.CreatorID; - block.GroupID = sop.GroupID; - block.LastOwnerID = sop.LastOwnerID; - if (sop.OwnerID == sop.GroupID) - block.OwnerID = UUID.Zero; - else - block.OwnerID = sop.OwnerID; - - block.ItemID = sop.FromUserInventoryItemID; - block.FolderID = UUID.Zero; // sog.FromFolderID ?? - block.FromTaskID = UUID.Zero; // ??? - block.InventorySerial = (short)sop.InventorySerial; - SceneObjectPart root = sop.ParentGroup.RootPart; - block.TouchName = Util.StringToBytes256(root.TouchName); + zc.AddUInt((uint)requestFlags); + zc.AddUUID(sop.UUID); + if (sop.OwnerID == sop.GroupID) + zc.AddZeros(16); + else + zc.AddUUID(sop.OwnerID); + zc.AddUUID(sop.GroupID); - // SL 3.3.4, at least, appears to read this information as a concatenated byte[] stream of UUIDs but - // it's not yet clear whether this is actually used. If this is done in the future then a pre-cached - // copy is really needed since it's less efficient to be constantly recreating this byte array. -// using (MemoryStream memStream = new MemoryStream()) -// { -// using (BinaryWriter binWriter = new BinaryWriter(memStream)) -// { -// for (int i = 0; i < sop.GetNumberOfSides(); i++) -// { -// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; -// -// UUID textureID; -// -// if (teFace != null) -// textureID = teFace.TextureID; -// else -// textureID = sop.Shape.Textures.DefaultTexture.TextureID; -// -// binWriter.Write(textureID.GetBytes()); -// } -// -// block.TextureID = memStream.ToArray(); -// } -// } + zc.AddUInt(root.BaseMask); + zc.AddUInt(root.OwnerMask); + zc.AddUInt(root.GroupMask); + zc.AddUInt(root.EveryoneMask); + zc.AddUInt(root.NextOwnerMask); - block.TextureID = new byte[0]; // TextureID ??? - block.SitName = Util.StringToBytes256(root.SitName); - block.OwnerMask = root.OwnerMask; - block.NextOwnerMask = root.NextOwnerMask; - block.GroupMask = root.GroupMask; - block.EveryoneMask = root.EveryoneMask; - block.BaseMask = root.BaseMask; - block.SaleType = root.ObjectSaleType; - block.SalePrice = root.SalePrice; + zc.AddZeros(4); // int ownership cost - return block; + //sale info block + zc.AddByte(root.ObjectSaleType); + zc.AddInt(root.SalePrice); + + zc.AddUInt(sop.Category); //Category + + zc.AddUUID(sop.LastOwnerID); + + //name + zc.AddShortString(sop.Name, 64); + + //Description + zc.AddShortString(sop.Description, 128); + } + + private void CreateObjectPropertiesBlock(SceneObjectPart sop, LLUDPZeroEncoder zc) + { + SceneObjectPart root = sop.ParentGroup.RootPart; + + zc.AddUUID(sop.UUID); + zc.AddUUID(sop.CreatorID); + if (sop.OwnerID == sop.GroupID) + zc.AddZeros(16); + else + zc.AddUUID(sop.OwnerID); + zc.AddUUID(sop.GroupID); + + zc.AddUInt64((ulong)sop.CreationDate * 1000000UL); + + zc.AddUInt(root.BaseMask); + zc.AddUInt(root.OwnerMask); + zc.AddUInt(root.GroupMask); + zc.AddUInt(root.EveryoneMask); + zc.AddUInt(root.NextOwnerMask); + + zc.AddZeros(4); // int ownership cost + + //sale info block + zc.AddByte(root.ObjectSaleType); + zc.AddInt(root.SalePrice); + + //aggregated perms we may will need to fix this + zc.AddByte(0); //AggregatePerms + zc.AddByte(0); //AggregatePermTextures; + zc.AddByte(0); //AggregatePermTexturesOwner + + //inventory info + zc.AddUInt(sop.Category); //Category + zc.AddInt16((short)sop.InventorySerial); + zc.AddUUID(sop.FromUserInventoryItemID); + zc.AddUUID(UUID.Zero); //FolderID + zc.AddUUID(UUID.Zero); //FromTaskID + + zc.AddUUID(sop.LastOwnerID); + + //name + zc.AddShortString(sop.Name, 64); + + //Description + zc.AddShortString(sop.Description, 128); + + // touch name + zc.AddShortString(root.TouchName, 9, 37); + + // sit name + zc.AddShortString(root.SitName, 9, 37); + + //texture ids block + // still not sending, not clear the impact on viewers, if any. + // does seem redundant + // to send we will need proper list of face texture ids without having to unpack texture entry all the time + zc.AddZeros(1); } #region Estate Data Sending Methods @@ -5442,7 +6347,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP rinfopack.AgentData.SessionID = SessionId; rinfoblk.BillableFactor = args.billableFactor; rinfoblk.EstateID = args.estateID; - rinfoblk.MaxAgents = args.maxAgents; + rinfoblk.MaxAgents = (byte)args.maxAgents; rinfoblk.ObjectBonusFactor = args.objectBonusFactor; rinfoblk.ParentEstateID = args.parentEstateID; rinfoblk.PricePerMeter = args.pricePerMeter; @@ -5458,9 +6363,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP rinfoblk.SimName = Utils.StringToBytes(args.simName); rinfopack.RegionInfo2 = new RegionInfoPacket.RegionInfo2Block(); - rinfopack.RegionInfo2.HardMaxAgents = uint.MaxValue; - rinfopack.RegionInfo2.HardMaxObjects = uint.MaxValue; - rinfopack.RegionInfo2.MaxAgents32 = uint.MaxValue; + rinfopack.RegionInfo2.HardMaxAgents = (uint)args.AgentCapacity; + rinfopack.RegionInfo2.HardMaxObjects = (uint)args.ObjectsCapacity; + rinfopack.RegionInfo2.MaxAgents32 = (uint)args.maxAgents; rinfopack.RegionInfo2.ProductName = Util.StringToBytes256(args.regionType); rinfopack.RegionInfo2.ProductSKU = Utils.EmptyBytes; @@ -5808,121 +6713,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity) - { - #region ScenePresence/SOP Handling - - bool avatar = (entity is ScenePresence); - uint localID = entity.LocalId; - uint attachPoint; - Vector4 collisionPlane; - Vector3 position, velocity, acceleration, angularVelocity; - Quaternion rotation; - - if (avatar) - { - ScenePresence presence = (ScenePresence)entity; - - position = presence.OffsetPosition; - velocity = presence.Velocity; - acceleration = Vector3.Zero; - rotation = presence.Rotation; - // tpvs can only see rotations around Z in some cases - if(!presence.Flying && !presence.IsSatOnObject) - { - rotation.X = 0f; - rotation.Y = 0f; - } - rotation.Normalize(); - angularVelocity = presence.AngularVelocity; - -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name); - - attachPoint = presence.State; - collisionPlane = presence.CollisionPlane; - } - else - { - SceneObjectPart part = (SceneObjectPart)entity; - - attachPoint = part.ParentGroup.AttachmentPoint; - attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", -// attachPoint, part.Name, part.LocalId, Name); - - collisionPlane = Vector4.Zero; - position = part.RelativePosition; - velocity = part.Velocity; - acceleration = part.Acceleration; - angularVelocity = part.AngularVelocity; - rotation = part.RotationOffset; - } - - #endregion ScenePresence/SOP Handling - - int pos = 0; - byte[] data = new byte[(avatar ? 60 : 44)]; - - // LocalID - Utils.UIntToBytes(localID, data, pos); - pos += 4; - - // Avatar/CollisionPlane - data[pos++] = (byte) attachPoint; - if (avatar) - { - data[pos++] = 1; - - if (collisionPlane == Vector4.Zero) - collisionPlane = Vector4.UnitW; - //m_log.DebugFormat("CollisionPlane: {0}",collisionPlane); - collisionPlane.ToBytes(data, pos); - pos += 16; - } - else - { - ++pos; - } - - // Position - position.ToBytes(data, pos); - pos += 12; - - // Velocity - ClampVectorForUint(ref velocity, 128f); - Utils.FloatToUInt16Bytes(velocity.X, 128.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(velocity.Y, 128.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(velocity.Z, 128.0f, data, pos); pos += 2; - - // Acceleration - ClampVectorForUint(ref acceleration, 64f); - Utils.FloatToUInt16Bytes(acceleration.X, 64.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(acceleration.Y, 64.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(acceleration.Z, 64.0f, data, pos); pos += 2; - - // Rotation - Utils.FloatToUInt16Bytes(rotation.X, 1.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(rotation.Y, 1.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(rotation.Z, 1.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(rotation.W, 1.0f, data, pos); pos += 2; - - // Angular Velocity - ClampVectorForUint(ref angularVelocity, 64f); - Utils.FloatToUInt16Bytes(angularVelocity.X, 64.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(angularVelocity.Y, 64.0f, data, pos); pos += 2; - Utils.FloatToUInt16Bytes(angularVelocity.Z, 64.0f, data, pos); pos += 2; - - ImprovedTerseObjectUpdatePacket.ObjectDataBlock block - = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); - - block.Data = data; - block.TextureEntry = Utils.EmptyBytes; - - return block; - } - protected void CreateImprovedTerseBlock(ISceneEntity entity, byte[] data, ref int pos, bool includeTexture) { #region ScenePresence/SOP Handling @@ -6059,73 +6849,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // total size 63 or 47 + (texture size + 4) } - protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) - { - Quaternion rotation = data.Rotation; - // tpvs can only see rotations around Z in some cases - if(!data.Flying && !data.IsSatOnObject) - { - rotation.X = 0f; - rotation.Y = 0f; - } - rotation.Normalize(); - -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name); - - byte[] objectData = new byte[76]; - - //Vector3 velocity = Vector3.Zero; - Vector3 acceleration = Vector3.Zero; - Vector3 angularvelocity = Vector3.Zero; - - data.CollisionPlane.ToBytes(objectData, 0); - data.OffsetPosition.ToBytes(objectData, 16); - data.Velocity.ToBytes(objectData, 28); - acceleration.ToBytes(objectData, 40); - rotation.ToBytes(objectData, 52); - angularvelocity.ToBytes(objectData, 64); - - ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); - - update.Data = Utils.EmptyBytes; - update.ExtraParams = Utils.EmptyBytes; - update.FullID = data.UUID; - update.ID = data.LocalId; - update.Material = (byte)Material.Flesh; - update.MediaURL = Utils.EmptyBytes; - update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + - data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); - update.ObjectData = objectData; - - SceneObjectPart parentPart = data.ParentPart; - if (parentPart != null) - update.ParentID = parentPart.ParentGroup.LocalId; - else - update.ParentID = 0; - - update.PathCurve = 16; - update.PathScaleX = 100; - update.PathScaleY = 100; - update.PCode = (byte)PCode.Avatar; - update.ProfileCurve = 1; - update.PSBlock = Utils.EmptyBytes; - update.Scale = data.Appearance.AvatarSize; -// update.Scale.Z -= 0.2f; - - update.Text = Utils.EmptyBytes; - update.TextColor = new byte[4]; - - // Don't send texture anim for avatars - this has no meaning for them. - update.TextureAnim = Utils.EmptyBytes; - - // Don't send texture entry for avatars here - this is accomplished via the AvatarAppearance packet - update.TextureEntry = Utils.EmptyBytes; - update.UpdateFlags = 0; - - return update; - } - protected void CreateAvatarUpdateBlock(ScenePresence data, byte[] dest, ref int pos) { Quaternion rotation = data.Rotation; @@ -6278,150 +7001,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP zc.AddZeros(lastzeros); } - protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart part, ScenePresence sp) - { - byte[] objectData = new byte[60]; - part.RelativePosition.ToBytes(objectData, 0); - part.Velocity.ToBytes(objectData, 12); - part.Acceleration.ToBytes(objectData, 24); - - Quaternion rotation = part.RotationOffset; - rotation.Normalize(); - rotation.ToBytes(objectData, 36); - part.AngularVelocity.ToBytes(objectData, 48); - - ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); - update.ClickAction = (byte)part.ClickAction; - update.CRC = 0; - update.ExtraParams = part.Shape.ExtraParams ?? Utils.EmptyBytes; - update.FullID = part.UUID; - update.ID = part.LocalId; - //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated - //update.JointPivot = Vector3.Zero; - //update.JointType = 0; - update.Material = part.Material; - - if (part.ParentGroup.IsAttachment) - { - if (part.IsRoot) - { - update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID); - } - else - update.NameValue = Utils.EmptyBytes; - - int st = (int)part.ParentGroup.AttachmentPoint; - update.State = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; - } - else - { - update.NameValue = Utils.EmptyBytes; - update.State = part.Shape.State; // not sure about this - } - - update.ObjectData = objectData; - update.ParentID = part.ParentID; - update.PathBegin = part.Shape.PathBegin; - update.PathCurve = part.Shape.PathCurve; - update.PathEnd = part.Shape.PathEnd; - update.PathRadiusOffset = part.Shape.PathRadiusOffset; - update.PathRevolutions = part.Shape.PathRevolutions; - update.PathScaleX = part.Shape.PathScaleX; - update.PathScaleY = part.Shape.PathScaleY; - update.PathShearX = part.Shape.PathShearX; - update.PathShearY = part.Shape.PathShearY; - update.PathSkew = part.Shape.PathSkew; - update.PathTaperX = part.Shape.PathTaperX; - update.PathTaperY = part.Shape.PathTaperY; - update.PathTwist = part.Shape.PathTwist; - update.PathTwistBegin = part.Shape.PathTwistBegin; - update.PCode = part.Shape.PCode; - update.ProfileBegin = part.Shape.ProfileBegin; - update.ProfileCurve = part.Shape.ProfileCurve; - - ushort profileBegin = part.Shape.ProfileBegin; - ushort profileHollow = part.Shape.ProfileHollow; - - if(part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack - { - update.ProfileCurve = (byte)(part.Shape.ProfileCurve & 0x0f); - // fix old values that confused viewers - if(profileBegin == 1) - profileBegin = 9375; - if(profileHollow == 1) - profileHollow = 27500; - // fix torus hole size Y that also confuse some viewers - if(update.ProfileCurve == (byte)ProfileShape.Circle && update.PathScaleY < 150) - update.PathScaleY = 150; - } - else - { - update.ProfileCurve = part.Shape.ProfileCurve; - } - - update.ProfileHollow = profileHollow; - update.ProfileBegin = profileBegin; - update.ProfileEnd = part.Shape.ProfileEnd; - update.PSBlock = part.ParticleSystem ?? Utils.EmptyBytes; - update.TextColor = part.GetTextColor().GetBytes(false); - update.TextureAnim = part.TextureAnimation ?? Utils.EmptyBytes; - update.TextureEntry = part.Shape.TextureEntry ?? Utils.EmptyBytes; - update.Scale = part.Shape.Scale; - update.Text = Util.StringToBytes(part.Text, 255); - update.MediaURL = Util.StringToBytes(part.MediaUrl, 255); - - #region PrimFlags - - PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp); - - // Don't send the CreateSelected flag to everyone - flags &= ~PrimFlags.CreateSelected; - - if (sp.UUID == part.OwnerID) - { - if (part.CreateSelected) - { - // Only send this flag once, then unset it - flags |= PrimFlags.CreateSelected; - part.CreateSelected = false; - } - } - -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Constructing client update for part {0} {1} with flags {2}, localId {3}", -// data.Name, update.FullID, flags, update.ID); - - update.UpdateFlags = (uint)flags; - - #endregion PrimFlags - - bool hassound = part.Sound != UUID.Zero || part.SoundFlags != 0; - if (hassound) - { - update.Sound = part.Sound; - update.Gain = (float)part.SoundGain; - update.Radius = (float)part.SoundRadius; - update.Flags = part.SoundFlags; - } - - if(hassound || update.PSBlock.Length > 1) - update.OwnerID = part.OwnerID; - - switch ((PCode)part.Shape.PCode) - { - case PCode.Grass: - case PCode.Tree: - case PCode.NewTree: - update.Data = new byte[] { part.Shape.State }; - break; - default: - update.Data = Utils.EmptyBytes; - break; - } - - return update; - } - protected void CreatePrimUpdateBlock(SceneObjectPart part, ScenePresence sp, LLUDPZeroEncoder zc) { // prepare data @@ -6453,7 +7032,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP zc.AddUInt(part.LocalId); zc.AddByte(state); // state zc.AddUUID(part.UUID); - zc.AddZeros(4); // crc unused + zc.AddUInt((uint)part.ParentGroup.PseudoCRC); zc.AddByte((byte)pcode); // material 1 // clickaction 1 @@ -6565,7 +7144,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP zc.AddUInt(part.LocalId); zc.AddByte(state); // state zc.AddUUID(part.UUID); - zc.AddZeros(4); // crc unused + zc.AddUInt((uint)part.ParentGroup.PseudoCRC); zc.AddByte((byte)pcode); zc.AddByte(part.Material); zc.AddByte(part.ClickAction); // clickaction @@ -6654,10 +7233,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP zc.AddZeros(5); else { - byte[] tbuf = Util.StringToBytes(part.Text, 254); - int len = tbuf.Length; - zc.AddByte((byte)len); - zc.AddBytes(tbuf, len); + zc.AddShortString(part.Text, 255); //textcolor byte[] tc = part.GetTextColor().GetBytes(false); @@ -6668,12 +7244,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (part.MediaUrl == null || part.MediaUrl.Length == 0) zc.AddZeros(1); else - { - byte[] tbuf = Util.StringToBytes(part.MediaUrl, 255); - int len = tbuf.Length; - zc.AddByte((byte)len); - zc.AddBytes(tbuf, len); - } + zc.AddShortString(part.MediaUrl, 255); bool hasps = false; //particle system @@ -6724,10 +7295,581 @@ namespace OpenSim.Region.ClientStack.LindenUDP zc.AddZeros(lastzeros); } - protected ObjectUpdateCompressedPacket.ObjectDataBlock CreateCompressedUpdateBlock(SceneObjectPart part, PrimUpdateFlags updateFlags) + [Flags] + private enum CompressedFlags : uint { - // TODO: Implement this - return null; + None = 0x00, + /// Unknown + ScratchPad = 0x01, + /// Whether the object has a TreeSpecies + Tree = 0x02, + /// Whether the object has floating text ala llSetText + HasText = 0x04, + /// Whether the object has an active particle system + HasParticlesLegacy = 0x08, + /// Whether the object has sound attached to it + HasSound = 0x10, + /// Whether the object is attached to a root object or not + HasParent = 0x20, + /// Whether the object has texture animation settings + TextureAnimation = 0x40, + /// Whether the object has an angular velocity + HasAngularVelocity = 0x80, + /// Whether the object has a name value pairs string + HasNameValues = 0x100, + /// Whether the object has a Media URL set + MediaURL = 0x200, + HasParticlesNew = 0x400 + } + + /* + protected void CreateCompressedUpdateBlock(SceneObjectPart part, ScenePresence sp, byte[] dest, ref int pos) + { + // prepare data + CompressedFlags cflags = CompressedFlags.None; + + // prim/update flags + + PrimFlags primflags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp); + // Don't send the CreateSelected flag to everyone + primflags &= ~PrimFlags.CreateSelected; + if (sp.UUID == part.OwnerID) + { + if (part.CreateSelected) + { + // Only send this flag once, then unset it + primflags |= PrimFlags.CreateSelected; + part.CreateSelected = false; + } + } + + byte state = part.Shape.State; + PCode pcode = (PCode)part.Shape.PCode; + + bool hastree = false; + if (pcode == PCode.Grass || pcode == PCode.Tree || pcode == PCode.NewTree) + { + cflags |= CompressedFlags.Tree; + hastree = true; + } + + //NameValue and state + byte[] nv = null; + if (part.ParentGroup.IsAttachment) + { + if (part.IsRoot) + nv = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID); + + int st = (int)part.ParentGroup.AttachmentPoint; + state = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; + } + + bool hastext = part.Text != null && part.Text.Length > 0; + bool hassound = part.Sound != UUID.Zero || part.SoundFlags != 0; + bool hasps = part.ParticleSystem != null && part.ParticleSystem.Length > 1; + bool hastexanim = part.TextureAnimation != null && part.TextureAnimation.Length > 0; + bool hasangvel = part.AngularVelocity.LengthSquared() > 1e-8f; + bool hasmediaurl = part.MediaUrl != null && part.MediaUrl.Length > 1; + + bool haspsnew = false; + if (hastext) + cflags |= CompressedFlags.HasText; + if (hasps) + { + if(part.ParticleSystem.Length > 86) + { + hasps= false; + cflags |= CompressedFlags.HasParticlesNew; + haspsnew = true; + } + else + cflags |= CompressedFlags.HasParticlesLegacy; + } + if (hassound) + cflags |= CompressedFlags.HasSound; + if (part.ParentID != 0) + cflags |= CompressedFlags.HasParent; + if (hastexanim) + cflags |= CompressedFlags.TextureAnimation; + if (hasangvel) + cflags |= CompressedFlags.HasAngularVelocity; + if (hasmediaurl) + cflags |= CompressedFlags.MediaURL; + if (nv != null) + cflags |= CompressedFlags.HasNameValues; + + // filter out mesh faces hack + ushort profileBegin = part.Shape.ProfileBegin; + ushort profileHollow = part.Shape.ProfileHollow; + byte profileCurve = part.Shape.ProfileCurve; + byte pathScaleY = part.Shape.PathScaleY; + + if (part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack + { + profileCurve = (byte)(part.Shape.ProfileCurve & 0x0f); + // fix old values that confused viewers + if (profileBegin == 1) + profileBegin = 9375; + if (profileHollow == 1) + profileHollow = 27500; + // fix torus hole size Y that also confuse some viewers + if (profileCurve == (byte)ProfileShape.Circle && pathScaleY < 150) + pathScaleY = 150; + } + + // first is primFlags + Utils.UIntToBytesSafepos((uint)primflags, dest, pos); pos += 4; + + // datablock len to fill later + int lenpos = pos; + pos += 2; + + // data block + part.UUID.ToBytes(dest, pos); pos += 16; + Utils.UIntToBytesSafepos(part.LocalId, dest, pos); pos += 4; + dest[pos++] = (byte)pcode; + dest[pos++] = state; + + Utils.UIntToBytesSafepos((uint)part.ParentGroup.PseudoCRC, dest, pos); pos += 4; + dest[pos++] = part.Material; + dest[pos++] = part.ClickAction; + part.Shape.Scale.ToBytes(dest, pos); pos += 12; + part.RelativePosition.ToBytes(dest, pos); pos += 12; + if(pcode == PCode.Grass) + Vector3.Zero.ToBytes(dest, pos); + else + { + Quaternion rotation = part.RotationOffset; + rotation.Normalize(); + rotation.ToBytes(dest, pos); + } + pos += 12; + + Utils.UIntToBytesSafepos((uint)cflags, dest, pos); pos += 4; + + if (hasps || haspsnew || hassound) + part.OwnerID.ToBytes(dest, pos); + else + UUID.Zero.ToBytes(dest, pos); + pos += 16; + + if (hasangvel) + { + part.AngularVelocity.ToBytes(dest, pos); pos += 12; + } + if (part.ParentID != 0) + { + Utils.UIntToBytesSafepos(part.ParentID, dest, pos); pos += 4; + } + if (hastree) + dest[pos++] = state; + if (hastext) + { + byte[] text = Util.StringToBytes256(part.Text); // must be null term + Buffer.BlockCopy(text, 0, dest, pos, text.Length); pos += text.Length; + byte[] tc = part.GetTextColor().GetBytes(false); + Buffer.BlockCopy(tc, 0, dest, pos, tc.Length); pos += tc.Length; + } + if (hasmediaurl) + { + byte[] mu = Util.StringToBytes256(part.MediaUrl); // must be null term + Buffer.BlockCopy(mu, 0, dest, pos, mu.Length); pos += mu.Length; + } + if (hasps) + { + byte[] ps = part.ParticleSystem; + Buffer.BlockCopy(ps, 0, dest, pos, ps.Length); pos += ps.Length; + } + byte[] ex = part.Shape.ExtraParams; + if (ex == null || ex.Length < 2) + dest[pos++] = 0; + else + { + Buffer.BlockCopy(ex, 0, dest, pos, ex.Length); pos += ex.Length; + } + if (hassound) + { + part.Sound.ToBytes(dest, pos); pos += 16; + Utils.FloatToBytesSafepos((float)part.SoundGain, dest, pos); pos += 4; + dest[pos++] = part.SoundFlags; + Utils.FloatToBytesSafepos((float)part.SoundRadius, dest, pos); pos += 4; + } + if (nv != null) + { + Buffer.BlockCopy(nv, 0, dest, pos, nv.Length); pos += nv.Length; + } + + dest[pos++] = part.Shape.PathCurve; + Utils.UInt16ToBytes(part.Shape.PathBegin, dest, pos); pos += 2; + Utils.UInt16ToBytes(part.Shape.PathEnd, dest, pos); pos += 2; + dest[pos++] = part.Shape.PathScaleX; + dest[pos++] = pathScaleY; + dest[pos++] = part.Shape.PathShearX; + dest[pos++] = part.Shape.PathShearY; + dest[pos++] = (byte)part.Shape.PathTwist; + dest[pos++] = (byte)part.Shape.PathTwistBegin; + dest[pos++] = (byte)part.Shape.PathRadiusOffset; + dest[pos++] = (byte)part.Shape.PathTaperX; + dest[pos++] = (byte)part.Shape.PathTaperY; + dest[pos++] = part.Shape.PathRevolutions; + dest[pos++] = (byte)part.Shape.PathSkew; + dest[pos++] = profileCurve; + Utils.UInt16ToBytes(profileBegin, dest, pos); pos += 2; + Utils.UInt16ToBytes(part.Shape.ProfileEnd, dest, pos); pos += 2; + Utils.UInt16ToBytes(profileHollow, dest, pos); pos += 2; + + byte[] te = part.Shape.TextureEntry; + if (te == null) + { + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + dest[pos++] = 0; + } + else + { + int len = te.Length & 0x7fff; + dest[pos++] = (byte)len; + dest[pos++] = (byte)(len >> 8); + dest[pos++] = 0; + dest[pos++] = 0; + Buffer.BlockCopy(te, 0, dest, pos, len); + pos += len; + } + if (hastexanim) + { + byte[] ta = part.TextureAnimation; + int len = ta.Length & 0x7fff; + dest[pos++] = (byte)len; + dest[pos++] = (byte)(len >> 8); + dest[pos++] = 0; + dest[pos++] = 0; + Buffer.BlockCopy(ta, 0, dest, pos, len); + pos += len; + } + + if (haspsnew) + { + byte[] ps = part.ParticleSystem; + Buffer.BlockCopy(ps, 0, dest, pos, ps.Length); pos += ps.Length; + } + + int totlen = pos - lenpos - 2; + dest[lenpos++] = (byte)totlen; + dest[lenpos++] = (byte)(totlen >> 8); + } + */ + + protected void CreateCompressedUpdateBlockZC(SceneObjectPart part, ScenePresence sp, LLUDPZeroEncoder zc) + { + // prepare data + CompressedFlags cflags = CompressedFlags.None; + + // prim/update flags + + PrimFlags primflags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp); + // Don't send the CreateSelected flag to everyone + primflags &= ~PrimFlags.CreateSelected; + if (sp.UUID == part.OwnerID) + { + if (part.CreateSelected) + { + // Only send this flag once, then unset it + primflags |= PrimFlags.CreateSelected; + part.CreateSelected = false; + } + } + + byte state = part.Shape.State; + PCode pcode = (PCode)part.Shape.PCode; + + // trees and grass are a lot more compact + if (pcode == PCode.Grass || pcode == PCode.Tree || pcode == PCode.NewTree) + { + // first is primFlags + zc.AddUInt((uint)primflags); + + // datablock len + zc.AddByte(113); + zc.AddZeros(1); + + // data block + zc.AddUUID(part.UUID); + zc.AddUInt(part.LocalId); + zc.AddByte((byte)pcode); + zc.AddByte(state); + + zc.AddUInt((uint)part.ParentGroup.PseudoCRC); + + zc.AddZeros(2); // material and click action + + zc.AddVector3(part.Shape.Scale); + zc.AddVector3(part.RelativePosition); + if (pcode == PCode.Grass) + zc.AddZeros(12); + else + { + Quaternion rotation = part.RotationOffset; + rotation.Normalize(); + zc.AddNormQuat(rotation); + } + + zc.AddUInt((uint)CompressedFlags.Tree); // cflags + + zc.AddZeros(16); // owner id + + zc.AddByte(state); // tree parameter + + zc.AddZeros(28); //extraparameters 1, pbs 23, texture 4 + + return; + } + + //NameValue and state + byte[] nv = null; + if (part.ParentGroup.IsAttachment) + { + if (part.IsRoot) + nv = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID); + + int st = (int)part.ParentGroup.AttachmentPoint; + state = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ; + } + + bool hastext = false; + bool hassound = false; + bool hasps = false; + bool hastexanim = false; + bool hasangvel = false; + bool hasmediaurl = false; + bool haspsnew = false; + + int BlockLengh = 111; + + byte[] extraParamBytes = part.Shape.ExtraParams; + if (extraParamBytes == null || extraParamBytes.Length < 2) + { + ++BlockLengh; + extraParamBytes = null; + } + else + BlockLengh += extraParamBytes.Length; + + byte[] hoverText = null; + byte[] hoverTextColor = null; + if (part.Text != null && part.Text.Length > 0) + { + cflags |= CompressedFlags.HasText; + hoverText = Util.StringToBytes256(part.Text); + BlockLengh += hoverText.Length; + hoverTextColor = part.GetTextColor().GetBytes(false); + BlockLengh += hoverTextColor.Length; + hastext = true; + } + + if (part.ParticleSystem != null && part.ParticleSystem.Length > 1) + { + BlockLengh += part.ParticleSystem.Length; + if (part.ParticleSystem.Length > 86) + { + hasps = false; + cflags |= CompressedFlags.HasParticlesNew; + haspsnew = true; + } + else + { + cflags |= CompressedFlags.HasParticlesLegacy; + hasps = true; + } + } + + if (part.Sound != UUID.Zero || part.SoundFlags != 0) + { + BlockLengh += 25; + cflags |= CompressedFlags.HasSound; + hassound = true; + } + + if (part.ParentID != 0) + { + BlockLengh += 4; + cflags |= CompressedFlags.HasParent; + } + + if (part.TextureAnimation != null && part.TextureAnimation.Length > 0) + { + BlockLengh += part.TextureAnimation.Length + 4; + cflags |= CompressedFlags.TextureAnimation; + hastexanim = true; + } + + if (part.AngularVelocity.LengthSquared() > 1e-8f) + { + BlockLengh += 12; + cflags |= CompressedFlags.HasAngularVelocity; + hasangvel = true; + } + + byte[] mediaURLBytes = null; + if (part.MediaUrl != null && part.MediaUrl.Length > 1) + { + mediaURLBytes = Util.StringToBytes256(part.MediaUrl); // must be null term + BlockLengh += mediaURLBytes.Length; + cflags |= CompressedFlags.MediaURL; + hasmediaurl = true; + } + + if (nv != null) + { + BlockLengh += nv.Length; + cflags |= CompressedFlags.HasNameValues; + } + + byte[] textureEntry = part.Shape.TextureEntry; + if(textureEntry != null) + BlockLengh += textureEntry.Length; + + // filter out mesh faces hack + ushort profileBegin = part.Shape.ProfileBegin; + ushort profileHollow = part.Shape.ProfileHollow; + byte profileCurve = part.Shape.ProfileCurve; + byte pathScaleY = part.Shape.PathScaleY; + + if (part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack + { + profileCurve = (byte)(part.Shape.ProfileCurve & 0x0f); + // fix old values that confused viewers + if (profileBegin == 1) + profileBegin = 9375; + if (profileHollow == 1) + profileHollow = 27500; + // fix torus hole size Y that also confuse some viewers + if (profileCurve == (byte)ProfileShape.Circle && pathScaleY < 150) + pathScaleY = 150; + } + + + // first is primFlags + zc.AddUInt((uint)primflags); + + // datablock len + zc.AddByte((byte)BlockLengh); + zc.AddByte((byte)(BlockLengh >> 8)); + + // data block + zc.AddUUID(part.UUID); + zc.AddUInt(part.LocalId); + zc.AddByte((byte)pcode); + zc.AddByte(state); + + zc.AddUInt((uint)part.ParentGroup.PseudoCRC); + + zc.AddByte(part.Material); + zc.AddByte(part.ClickAction); + zc.AddVector3(part.Shape.Scale); + zc.AddVector3(part.RelativePosition); + if (pcode == PCode.Grass) + zc.AddZeros(12); + else + { + Quaternion rotation = part.RotationOffset; + rotation.Normalize(); + zc.AddNormQuat(rotation); + } + + zc.AddUInt((uint)cflags); + + if (hasps || haspsnew || hassound) + zc.AddUUID(part.OwnerID); + else + zc.AddZeros(16); + + if (hasangvel) + { + zc.AddVector3(part.AngularVelocity); + } + if (part.ParentID != 0) + { + zc.AddUInt(part.ParentID); + } + if (hastext) + { + zc.AddBytes(hoverText, hoverText.Length); + zc.AddBytes(hoverTextColor, hoverTextColor.Length); + } + if (hasmediaurl) + { + zc.AddBytes(mediaURLBytes, mediaURLBytes.Length); + } + if (hasps) + { + byte[] ps = part.ParticleSystem; + zc.AddBytes(ps, ps.Length); + } + if (extraParamBytes == null) + zc.AddZeros(1); + else + { + zc.AddBytes(extraParamBytes, extraParamBytes.Length); + } + if (hassound) + { + zc.AddUUID(part.Sound); + zc.AddFloat((float)part.SoundGain); + zc.AddByte(part.SoundFlags); + zc.AddFloat((float)part.SoundRadius); + } + if (nv != null) + { + zc.AddBytes(nv, nv.Length); + } + + zc.AddByte(part.Shape.PathCurve); + zc.AddUInt16(part.Shape.PathBegin); + zc.AddUInt16(part.Shape.PathEnd); + zc.AddByte(part.Shape.PathScaleX); + zc.AddByte(pathScaleY); + zc.AddByte(part.Shape.PathShearX); + zc.AddByte(part.Shape.PathShearY); + zc.AddByte((byte)part.Shape.PathTwist); + zc.AddByte((byte)part.Shape.PathTwistBegin); + zc.AddByte((byte)part.Shape.PathRadiusOffset); + zc.AddByte((byte)part.Shape.PathTaperX); + zc.AddByte((byte)part.Shape.PathTaperY); + zc.AddByte(part.Shape.PathRevolutions); + zc.AddByte((byte)part.Shape.PathSkew); + zc.AddByte(profileCurve); + zc.AddUInt16(profileBegin); + zc.AddUInt16(part.Shape.ProfileEnd); + zc.AddUInt16(profileHollow); + + if (textureEntry == null) + { + zc.AddZeros(4); + } + else + { + int len = textureEntry.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddZeros(2); + zc.AddBytes(textureEntry, len); + } + if (hastexanim) + { + byte[] ta = part.TextureAnimation; + int len = ta.Length; + zc.AddByte((byte)len); + zc.AddByte((byte)(len >> 8)); + zc.AddZeros(2); + zc.AddBytes(ta, len); + } + + if (haspsnew) + { + byte[] ps = part.ParticleSystem; + zc.AddBytes(ps, ps.Length); + } } public void SendNameReply(UUID profileId, string firstname, string lastname) @@ -6871,7 +8013,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); - AddLocalPacketHandler(PacketType.ConfirmXferPacket, HandleConfirmXferPacket); + AddLocalPacketHandler(PacketType.ConfirmXferPacket, HandleConfirmXferPacket, false); AddLocalPacketHandler(PacketType.AbortXfer, HandleAbortXfer); AddLocalPacketHandler(PacketType.CreateInventoryFolder, HandleCreateInventoryFolder); AddLocalPacketHandler(PacketType.UpdateInventoryFolder, HandleUpdateInventoryFolder); @@ -7669,15 +8811,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP TrackAgentPacket TrackAgent = (TrackAgentPacket)Packet; + if(TrackAgent.AgentData.AgentID != AgentId || TrackAgent.AgentData.SessionID != SessionId) + return false; + TrackAgentUpdate TrackAgentHandler = OnTrackAgent; if (TrackAgentHandler != null) { TrackAgentHandler(this, TrackAgent.AgentData.AgentID, TrackAgent.TargetData.PreyID); - return true; } - return false; +// else +// m_courseLocationPrey = TrackAgent.TargetData.PreyID; + return true; } private bool HandlerRezObject(IClientAPI sender, Packet Pack) @@ -7828,13 +8974,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } + public uint m_viewerHandShakeFlags = 0; + private bool HandlerRegionHandshakeReply(IClientAPI sender, Packet Pack) { Action handlerRegionHandShakeReply = OnRegionHandShakeReply; - if (handlerRegionHandShakeReply != null) - { - handlerRegionHandShakeReply(this); - } + if (handlerRegionHandShakeReply == null) + return true; // silence the warning + + RegionHandshakeReplyPacket rsrpkt = (RegionHandshakeReplyPacket)Pack; + if(rsrpkt.AgentData.AgentID != m_agentId || rsrpkt.AgentData.SessionID != m_sessionId) + return false; + + if(m_supportViewerCache) + m_viewerHandShakeFlags = rsrpkt.RegionInfo.Flags; + else + m_viewerHandShakeFlags = 0; + + handlerRegionHandShakeReply(this); return true; } @@ -8078,19 +9235,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } - private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) + private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) { - m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement"); + //m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement"); Action handlerCompleteMovementToRegion = OnCompleteMovementToRegion; - if (handlerCompleteMovementToRegion != null) - { - handlerCompleteMovementToRegion(sender, true); - } - else - m_log.Debug("HandleCompleteAgentMovement NULL handler"); + if (handlerCompleteMovementToRegion == null) + return false; - handlerCompleteMovementToRegion = null; + CompleteAgentMovementPacket cmp = (CompleteAgentMovementPacket)Pack; + if(cmp.AgentData.AgentID != m_agentId || cmp.AgentData.SessionID != m_sessionId || cmp.AgentData.CircuitCode != m_circuitCode) + return false; + + handlerCompleteMovementToRegion(sender, true); return true; } @@ -8358,7 +9515,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool HandleAgentResume(IClientAPI sender, Packet Pack) { m_udpClient.IsPaused = false; - SendStartPingCheck(m_udpClient.CurrentPingSequence++); + m_udpServer.SendPing(m_udpClient); return true; } @@ -8562,6 +9719,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool HandleRequestMultipleObjects(IClientAPI sender, Packet Pack) { + ObjectRequest handlerObjectRequest = OnObjectRequest; + if (handlerObjectRequest == null) + return false; + RequestMultipleObjectsPacket incomingRequest = (RequestMultipleObjectsPacket)Pack; #region Packet Session and User Check @@ -8570,16 +9731,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; #endregion - ObjectRequest handlerObjectRequest = null; - for (int i = 0; i < incomingRequest.ObjectData.Length; i++) - { - handlerObjectRequest = OnObjectRequest; - if (handlerObjectRequest != null) - { handlerObjectRequest(incomingRequest.ObjectData[i].ID, this); - } - } return true; } @@ -9483,12 +10636,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { RequestXferPacket xferReq = (RequestXferPacket)Pack; - RequestXfer handlerRequestXfer = OnRequestXfer; - - if (handlerRequestXfer != null) - { - handlerRequestXfer(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename)); - } + OnRequestXfer?.Invoke(this, xferReq.XferID.ID, Util.FieldToString(xferReq.XferID.Filename)); return true; } @@ -9496,11 +10644,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { SendXferPacketPacket xferRec = (SendXferPacketPacket)Pack; - XferReceive handlerXferReceive = OnXferReceive; - if (handlerXferReceive != null) - { - handlerXferReceive(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data); - } + OnXferReceive?.Invoke(this, xferRec.XferID.ID, xferRec.XferID.Packet, xferRec.DataPacket.Data); return true; } @@ -9508,23 +10652,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ConfirmXferPacketPacket confirmXfer = (ConfirmXferPacketPacket)Pack; - ConfirmXfer handlerConfirmXfer = OnConfirmXfer; - if (handlerConfirmXfer != null) - { - handlerConfirmXfer(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet); - } + OnConfirmXfer?.Invoke(this, confirmXfer.XferID.ID, confirmXfer.XferID.Packet); return true; } private bool HandleAbortXfer(IClientAPI sender, Packet Pack) { AbortXferPacket abortXfer = (AbortXferPacket)Pack; - AbortXfer handlerAbortXfer = OnAbortXfer; - if (handlerAbortXfer != null) - { - handlerAbortXfer(this, abortXfer.XferID.ID); - } + OnAbortXfer?.Invoke(this, abortXfer.XferID.ID); return true; } @@ -11602,7 +12738,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) { + /* + UseCircuitCodePacket uccp = (UseCircuitCodePacket)Pack; + if(uccp.CircuitCode.ID == m_agentId && + uccp.CircuitCode.SessionID == m_sessionId && + uccp.CircuitCode.Code == m_circuitCode && + SceneAgent != null && + !((ScenePresence)SceneAgent).IsDeleted + ) + SendRegionHandshake(); // possible someone returning + */ return true; + } private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack) @@ -13996,38 +15143,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (p is ScenePresence) { -// m_log.DebugFormat( -// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}", -// p.Name, Name, Scene.Name); + UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); - // It turns out to get the agent to stop flying, you have to feed it stop flying velocities - // There's no explicit message to send the client to tell it to stop flying.. it relies on the - // velocity, collision plane and avatar height - - // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air - // when the avatar stands up - - ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = - CreateImprovedTerseBlock(p); - -// const float TIME_DILATION = 1.0f; - ushort timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);; - - ImprovedTerseObjectUpdatePacket packet - = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( - PacketType.ImprovedTerseObjectUpdate); - - packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; - packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; - - packet.ObjectData[0] = block; - - OutPacket(packet, ThrottleOutPacketType.Task, true); + //setup header and regioninfo block + Buffer.BlockCopy(terseUpdateHeader, 0, buf.Data, 0, 7); + Utils.UInt64ToBytesSafepos(m_scene.RegionInfo.RegionHandle, buf.Data, 7); + Utils.UInt16ToBytes(Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f), buf.Data, 15); + buf.Data[17] = 1; + int pos = 18; + CreateImprovedTerseBlock(p, buf.Data, ref pos, false); + buf.DataLength = pos; + m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task, null, false, true); } - - //ControllingClient.SendAvatarTerseUpdate(new SendAvatarTerseData(m_rootRegionHandle, (ushort)(m_scene.TimeDilation * ushort.MaxValue), LocalId, - // AbsolutePosition, Velocity, Vector3.Zero, m_bodyRot, new Vector4(0,0,1,AbsolutePosition.Z - 0.5f), m_uuid, null, GetUpdatePriority(ControllingClient))); } public void SendPlacesReply(UUID queryID, UUID transactionID, @@ -14275,15 +15402,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP return new HashSet(m_inPacketsToDrop); } - public void CheckViewerCaps() + public uint GetViewerCaps() { m_SupportObjectAnimations = false; + uint ret; + if(m_supportViewerCache) + ret = m_viewerHandShakeFlags; + else + ret = (m_viewerHandShakeFlags & 4) | 2; // disable probes + if (m_scene.CapsModule != null) { Caps cap = m_scene.CapsModule.GetCapsForUser(CircuitCode); - if (cap != null && (cap.Flags & Caps.CapsFlags.ObjectAnim) != 0) - m_SupportObjectAnimations = true; + if(cap != null) + { + if((cap.Flags & Caps.CapsFlags.SentSeeds) != 0) + ret |= 0x1000; + if ((cap.Flags & Caps.CapsFlags.ObjectAnim) != 0) + { + m_SupportObjectAnimations = true; + ret |= 0x2000; + } + } } + return ret; // ??? } } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 2981337b2d..4e9cf1ce39 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -148,7 +148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// milliseconds or longer will be resent /// Calculated from and using the /// guidelines in RFC 2988 - public int RTO; + public int m_RTO; /// Number of bytes received since the last acknowledgement was sent out. This is used /// to loosely follow the TCP delayed ACK algorithm in RFC 1122 (4.2.3.2) public int BytesSinceLastACK; @@ -190,12 +190,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP private byte[] m_packedThrottles; private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC - private int m_maxRTO = 60000; + private int m_maxRTO = 10000; public bool m_deliverPackets = true; private float m_burstTime; - public int m_lastStartpingTimeMS; + public double m_lastStartpingTimeMS; public int m_pingMS; public int PingTimeMS @@ -242,7 +242,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (maxRTO != 0) m_maxRTO = maxRTO; - m_burstTime = rates.BrustTime; + m_burstTime = rates.BurstTime; float m_burst = rates.ClientMaxRate * m_burstTime; // Create a token bucket throttle for this client that has the scene token bucket as a parent @@ -251,7 +251,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; - m_burst = rates.Total * rates.BrustTime; + m_burst = rates.Total * rates.BurstTime; for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { @@ -260,11 +260,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Initialize the packet outboxes, where packets sit while they are waiting for tokens m_packetOutboxes[i] = new DoubleLocklessQueue(); // Initialize the token buckets that control the throttling for each category - m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst); + //m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst); + float rate = rates.GetRate(type); + float burst = rate * rates.BurstTime; + m_throttleCategories[i] = new TokenBucket(m_throttleClient, rate , burst); } // Default the retransmission timeout to one second - RTO = m_defaultRTO; + m_RTO = m_defaultRTO; // Initialize this to a sane value to prevent early disconnects TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; @@ -443,7 +446,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP int total = resend + land + wind + cloud + task + texture + asset; - float m_burst = total * m_burstTime; + //float m_burst = total * m_burstTime; if (ThrottleDebugLevel > 0) { @@ -453,7 +456,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } TokenBucket bucket; - + /* bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; bucket.RequestedDripRate = resend; bucket.RequestedBurst = m_burst; @@ -481,6 +484,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; bucket.RequestedDripRate = texture; bucket.RequestedBurst = m_burst; + */ + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; + bucket.RequestedDripRate = resend; + bucket.RequestedBurst = resend * m_burstTime; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; + bucket.RequestedDripRate = land; + bucket.RequestedBurst = land * m_burstTime; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; + bucket.RequestedDripRate = wind; + bucket.RequestedBurst = wind * m_burstTime; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; + bucket.RequestedDripRate = cloud; + bucket.RequestedBurst = cloud * m_burstTime; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; + bucket.RequestedDripRate = asset; + bucket.RequestedBurst = asset * m_burstTime; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; + bucket.RequestedDripRate = task; + bucket.RequestedBurst = task * m_burstTime; + + bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; + bucket.RequestedDripRate = texture; + bucket.RequestedBurst = texture * m_burstTime; // Reset the packed throttles cached data m_packedThrottles = null; @@ -719,57 +750,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP } /// - /// Called when an ACK packet is received and a round-trip time for a - /// packet is calculated. This is used to calculate the smoothed - /// round-trip time, round trip time variance, and finally the - /// retransmission timeout + /// Called when we get a ping update /// - /// Round-trip time of a single packet and its + /// ping time in ms /// acknowledgement - public void UpdateRoundTrip(float r) + public void UpdateRoundTrip(int p) { - const float ALPHA = 0.125f; - const float BETA = 0.25f; - const float K = 4.0f; + p *= 5; + if( p> m_maxRTO) + p = m_maxRTO; + else if(p < m_defaultRTO) + p = m_defaultRTO; - if (RTTVAR == 0.0f) - { - // First RTT measurement - SRTT = r; - RTTVAR = r * 0.5f; - } - else - { - // Subsequence RTT measurement - RTTVAR = (1.0f - BETA) * RTTVAR + BETA * Math.Abs(SRTT - r); - SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r; - } - - int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); - - // Clamp the retransmission timeout to manageable values - rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO); - - RTO = rto; - - //if (RTO != rto) - // m_log.Debug("[LLUDPCLIENT]: Setting RTO to " + RTO + "ms from " + rto + "ms with an RTTVAR of " + - //RTTVAR + " based on new RTT of " + r + "ms"); - } - - /// - /// Exponential backoff of the retransmission timeout, per section 5.5 - /// of RFC 2988 - /// - public void BackoffRTO() - { - // Reset SRTT and RTTVAR, we assume they are bogus since things - // didn't work out and we're backing off the timeout - SRTT = 0.0f; - RTTVAR = 0.0f; - - // Double the retransmission timeout - RTO = Math.Min(RTO * 2, m_maxRTO); + m_RTO = p; } const double MIN_CALLBACK_MS = 20.0; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 2300800f57..e3139345fd 100755 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -229,11 +229,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatVerbosity.Debug)); } - public virtual bool HandlesRegion(Location x) - { - return m_udpServer.HandlesRegion(x); - } - public virtual void Start() { m_udpServer.Start(); @@ -256,7 +251,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Maximum transmission unit, or UDP packet size, for the LLUDP protocol public const int MTU = 1400; - public const int MAXPAYLOAD = 1250; + public const int MAXPAYLOAD = 1200; /// Number of forced client logouts due to no receipt of packets before timeout. public int ClientLogoutsDueToNoReceives { get; protected set; } @@ -279,11 +274,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// OnQueueEmpty event is triggered for textures public readonly int TextureSendLimit; - /// Handlers for incoming packets - //PacketEventDictionary packetEvents = new PacketEventDictionary(); - /// Incoming packets that are awaiting handling - //protected OpenMetaverse.BlockingQueue packetInbox = new OpenMetaverse.BlockingQueue(); - protected BlockingCollection packetInbox = new BlockingCollection(); /// Bandwidth throttle for this UDP server @@ -303,9 +293,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Reference to the scene this UDP server is attached to public Scene Scene { get; protected set; } - /// The X/Y coordinates of the scene this UDP server is attached to - protected Location m_location; - /// The size of the receive buffer for the UDP socket. This value /// is passed up to the operating system and used in the system networking /// stack. Use zero to leave this value as the default @@ -374,12 +361,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public int IncomingOrphanedPacketCount { get; protected set; } - /// - /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available - /// threadpool threads. - /// -// public JobEngine IpahEngine { get; protected set; } - + public bool SupportViewerObjectsCache = true; /// /// Run queue empty processing within a single persistent thread. /// @@ -444,6 +426,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_disableFacelights = config.GetBoolean("DisableFacelights", false); m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60); m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300); + SupportViewerObjectsCache = config.GetBoolean("SupportViewerObjectsCache", SupportViewerObjectsCache); } else { @@ -477,8 +460,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP Throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f); ThrottleRates = new ThrottleRates(configSource); - Random rnd = new Random(Util.EnvironmentTickCount()); - // if (usePools) // EnablePools(); } @@ -556,13 +537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } Scene = (Scene)scene; - m_location = new Location(Scene.RegionInfo.RegionHandle); -/* - IpahEngine - = new JobEngine( - string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name), - "INCOMING PACKET ASYNC HANDLING ENGINE"); -*/ + OqrEngine = new JobEngine( string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name), "OUTGOING QUEUE REFILL ENGINE"); @@ -689,11 +664,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP commands.Register(); } - public bool HandlesRegion(Location x) - { - return x == m_location; - } - public int GetTotalQueuedOutgoingPackets() { int total = 0; @@ -844,13 +814,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; bool doCopy = true; - // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. - // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting - // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here - // to accomodate for both common scenarios and provide ample room for ACK appending in both - //int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; - - //UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); UDPPacketBuffer buffer = GetNewUDPBuffer(udpClient.RemoteEndPoint); // Zerocode if needed @@ -993,7 +956,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { bool highPriority = false; - if(zerocode) + if (zerocode) buffer = ZeroEncode(buffer); if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0) @@ -1012,49 +975,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP SendPacketFinal(outgoingPacket); } + public void SendUDPPacket(LLUDPClient udpClient, UDPPacketBuffer buffer, ThrottleOutPacketType category) + { + bool highPriority = false; + + if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0) + { + category = (ThrottleOutPacketType)((int)category & 127); + highPriority = true; + } + + OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); + + // If we were not provided a method for handling unacked, use the UDPServer default method + if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) + outgoingPacket.UnackedMethod = delegate (OutgoingPacket oPacket) { ResendUnacked(oPacket); }; + + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false, highPriority)) + SendPacketFinal(outgoingPacket); + } + + static private readonly byte[] PacketAckHeader = new byte[] { + 0, + 0, 0, 0, 0, // sequence number + 0, // extra + 0xff, 0xff, 0xff, 0xfb // ID 65531 (low frequency bigendian) + }; + public void SendAcks(LLUDPClient udpClient) { + if(udpClient.PendingAcks.Count == 0) + return; + + UDPPacketBuffer buf = GetNewUDPBuffer(udpClient.RemoteEndPoint); + Buffer.BlockCopy(PacketAckHeader, 0, buf.Data, 0, 10); + byte[] data = buf.Data; + // count at position 10 + int pos = 11; + uint ack; - - if (udpClient.PendingAcks.Dequeue(out ack)) + int count = 0; + while (udpClient.PendingAcks.Dequeue(out ack)) { - List blocks = new List(); - PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); - block.ID = ack; - blocks.Add(block); + Utils.UIntToBytes(ack, data, pos); pos += 4; + ++count; - while (udpClient.PendingAcks.Dequeue(out ack)) + if (count == 255) { - block = new PacketAckPacket.PacketsBlock(); - block.ID = ack; - blocks.Add(block); + data[10] = 255; + buf.DataLength = pos; + SendUDPPacket(udpClient, buf, ThrottleOutPacketType.Unknown); + + buf = GetNewUDPBuffer(udpClient.RemoteEndPoint); + Buffer.BlockCopy(PacketAckHeader, 0, buf.Data, 0, 10); + data = buf.Data; + pos = 11; + count = 0; } - - PacketAckPacket packet = new PacketAckPacket(); - packet.Header.Reliable = false; - packet.Packets = blocks.ToArray(); - - SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null); + } + if (count > 0) + { + data[10] = (byte)count; + buf.DataLength = pos; + SendUDPPacket(udpClient, buf, ThrottleOutPacketType.Unknown); } } + static private readonly byte[] StartPingCheckHeader = new byte[] { + 0, + 0, 0, 0, 0, // sequence number + 0, // extra + 1 // ID 1 (high frequency) + }; + public void SendPing(LLUDPClient udpClient) { - StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); + UDPPacketBuffer buf = GetNewUDPBuffer(udpClient.RemoteEndPoint); + Buffer.BlockCopy(StartPingCheckHeader, 0, buf.Data, 0, 7); + byte[] data = buf.Data; - pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; - // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit - pc.PingID.OldestUnacked = 0; + data[7] = udpClient.CurrentPingSequence++; + // older seq number of our un ack packets, so viewers could clean deduplication lists TODO + //Utils.UIntToBytes(0, data, 8); + data[8] = 0; + data[9] = 0; + data[10] = 0; + data[11] = 0; - SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); - udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount(); + buf.DataLength = 12; + SendUDPPacket(udpClient, buf, ThrottleOutPacketType.Unknown); + + udpClient.m_lastStartpingTimeMS = Util.GetTimeStampMS(); } + static private readonly byte[] CompletePingCheckHeader = new byte[] { + 0, + 0, 0, 0, 0, // sequence number + 0, // extra + 2 // ID 1 (high frequency) + }; + public void CompletePing(LLUDPClient udpClient, byte pingID) { - CompletePingCheckPacket completePing = new CompletePingCheckPacket(); - completePing.PingID.PingID = pingID; - SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null); + UDPPacketBuffer buf = GetNewUDPBuffer(udpClient.RemoteEndPoint); + Buffer.BlockCopy(CompletePingCheckHeader, 0, buf.Data, 0, 7); + byte[] data = buf.Data; + + data[7] = pingID; + + buf.DataLength = 8; + SendUDPPacket(udpClient, buf, ThrottleOutPacketType.Unknown); } public void HandleUnacked(LLClientView client) @@ -1090,13 +1120,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP } // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO - List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); + List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.m_RTO); if (expiredPackets != null) { - //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); - // Exponential backoff of the retransmission timeout - udpClient.BackoffRTO(); for (int i = 0; i < expiredPackets.Count; ++i) expiredPackets[i].UnackedMethod(expiredPackets[i]); } @@ -1144,8 +1171,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP int dataLength = buffer.DataLength; - // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here - if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null) + // only append acks on plain reliable messages + if (flags == Helpers.MSG_RELIABLE && outgoingPacket.UnackedMethod == null) { // Keep appending ACKs until there is no room left in the buffer or there are // no more ACKs to append @@ -1184,7 +1211,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Stats tracking Interlocked.Increment(ref udpClient.PacketsSent); PacketsSentCount++; - SyncSend(buffer); // Keep track of when this packet was sent out (right now) @@ -1315,11 +1341,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (packet.Type == PacketType.UseCircuitCode) { // And if there is a UseCircuitCode pending, also drop it + lock (m_pendingCache) { if (m_pendingCache.Contains(endPoint)) { FreeUDPBuffer(buffer); + SendAckImmediate(endPoint, packet.Header.Sequence); // i hear you shutup return; } @@ -1328,6 +1356,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP Util.FireAndForget(HandleUseCircuitCode, new object[] { endPoint, packet }); FreeUDPBuffer(buffer); + SendAckImmediate(endPoint, packet.Header.Sequence); return; } } @@ -1482,11 +1511,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else if (packet.Type == PacketType.CompletePingCheck) { - int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS); - int c = udpClient.m_pingMS; - c = 800 * c + 200 * t; - c /= 1000; - udpClient.m_pingMS = c; + double t = Util.GetTimeStampMS() - udpClient.m_lastStartpingTimeMS; + double c = 0.8 * udpClient.m_pingMS; + c += 0.2 * t; + int p = (int)c; + udpClient.m_pingMS = p; + udpClient.UpdateRoundTrip(p); return; } @@ -1651,7 +1681,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } // Now we know we can handle more data - Thread.Sleep(200); + //Thread.Sleep(200); // Obtain the pending queue and remove it from the cache Queue queue = null; @@ -1666,8 +1696,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_pendingCache.Remove(endPoint); } - client.CheckViewerCaps(); - m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); // Reinject queued packets while (queue.Count > 0) @@ -1678,18 +1706,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP queue = null; - // Send ack straight away to let the viewer know that the connection is active. - // The client will be null if it already exists (e.g. if on a region crossing the client sends a use - // circuit code to the existing child agent. This is not particularly obvious. - SendAckImmediate(endPoint, uccp.Header.Sequence); - - // We only want to send initial data to new clients, not ones which are being converted from child to root. if (client != null) { - bool tp = (aCircuit.teleportFlags > 0); - // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from - if (!tp) - client.SceneAgent.SendInitialDataToMe(); + if(aCircuit.teleportFlags <= 0) + client.SendRegionHandshake(); } } else @@ -1705,8 +1725,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } // m_log.DebugFormat( - // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", - // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); + // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", + // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); } catch (Exception e) @@ -1720,117 +1740,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP e.StackTrace); } } -/* - protected void HandleCompleteMovementIntoRegion(object o) - { - IPEndPoint endPoint = null; - IClientAPI client = null; - - try - { - object[] array = (object[])o; - endPoint = (IPEndPoint)array[0]; - CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; - - m_log.DebugFormat( - "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, Scene.Name); - - // Determine which agent this packet came from - // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination - // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode - // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these - // packets asynchronously, we need to account for this thread proceeding more quickly than the - // UseCircuitCode thread. - int count = 40; - while (count-- > 0) - { - if (Scene.TryGetClient(endPoint, out client)) - { - if (!client.IsActive) - { - // This check exists to catch a condition where the client has been closed by another thread - // but has not yet been removed from the client manager (and possibly a new connection has - // not yet been established). - m_log.DebugFormat( - "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.", - endPoint, client.Name, Scene.Name); - } - else if (client.SceneAgent == null) - { - // This check exists to catch a condition where the new client has been added to the client - // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too - // eager, then the new ScenePresence may not have registered a listener for this messsage - // before we try to process it. - // XXX: A better long term fix may be to add the SceneAgent before the client is added to - // the client manager - m_log.DebugFormat( - "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", - endPoint, client.Name, Scene.Name); - } - else - { - break; - } - } - else - { - m_log.DebugFormat( - "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", - endPoint, Scene.Name); - } - - Thread.Sleep(200); - } - - if (client == null) - { - m_log.DebugFormat( - "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.", - endPoint, Scene.Name); - - return; - } - else if (!client.IsActive || client.SceneAgent == null) - { - // This check exists to catch a condition where the client has been closed by another thread - // but has not yet been removed from the client manager. - // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging - // purposes. - m_log.DebugFormat( - "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.", - endPoint, client.Name, Scene.Name); - - return; - } - - IncomingPacket incomingPacket1; - - // Inbox insertion - if (UsePools) - { - incomingPacket1 = m_incomingPacketPool.GetObject(); - incomingPacket1.Client = (LLClientView)client; - incomingPacket1.Packet = packet; - } - else - { - incomingPacket1 = new IncomingPacket((LLClientView)client, packet); - } - - packetInbox.Enqueue(incomingPacket1); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", - endPoint != null ? endPoint.ToString() : "n/a", - client != null ? client.Name : "unknown", - client != null ? client.AgentId.ToString() : "unknown", - e.Message, - e.StackTrace); - } - } -*/ /// /// Send an ack immediately to the given endpoint. @@ -1898,7 +1807,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (Scene.TryGetClient(agentID, out client)) { - if (client.SceneAgent != null) + if (client.SceneAgent != null && + client.CircuitCode == circuitCode && + client.SessionId == sessionID && + client.RemoteEndPoint == remoteEndPoint && + client.SceneAgent.ControllingClient.SecureSessionId == sessionInfo.LoginInfo.SecureSession) return client; Scene.CloseAgent(agentID, true); } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPZeroEncoder.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPZeroEncoder.cs index 8ed2cf12cd..0b008a9f85 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPZeroEncoder.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPZeroEncoder.cs @@ -26,6 +26,7 @@ */ using System; +using System.Text; using OpenSim.Framework; using Nini.Config; using OpenMetaverse; @@ -275,5 +276,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP v.ToBytes(m_tmp, 0); AddBytes(m_tmp, 16); } + + // maxlen <= 255 and includes null termination byte + public void AddShortString(string str, int maxlen) + { + if (String.IsNullOrEmpty(str)) + { + AddZeros(1); + return; + } + + --maxlen; // account for null term + bool NullTerm = str.EndsWith("\0"); + + byte[] data = Util.UTF8.GetBytes(str); + int len = data.Length; + if(NullTerm) + --len; + + if(len <= maxlen) + { + AddByte((byte)(len + 1)); + AddBytes(data, len); + AddZeros(1); + return; + } + + if ((data[maxlen] & 0x80) != 0) + { + while (maxlen > 0 && (data[maxlen] & 0xc0) != 0xc0) + maxlen--; + } + AddByte((byte)(maxlen + 1)); + AddBytes(data, maxlen); + AddZeros(1); + } + // maxlen <= 255 and includes null termination byte, maxchars == max len of utf8 source + public void AddShortString(string str, int maxchars, int maxlen) + { + if (String.IsNullOrEmpty(str)) + { + AddZeros(1); + return; + } + + --maxlen; // account for null term + bool NullTerm = false; + byte[] data; + + if (str.Length > maxchars) + { + data = Util.UTF8.GetBytes(str.Substring(0,maxchars)); + } + else + { + NullTerm = str.EndsWith("\0"); + data = Util.UTF8.GetBytes(str); + } + + int len = data.Length; + if (NullTerm) + --len; + + if (len <= maxlen) + { + AddByte((byte)(len + 1)); + AddBytes(data, len); + AddZeros(1); + return; + } + + if ((data[maxlen] & 0x80) != 0) + { + while (maxlen > 0 && (data[maxlen] & 0xc0) != 0xc0) + maxlen--; + } + + AddByte((byte)(maxlen + 1)); + AddBytes(data, maxlen); + AddZeros(1); + } + } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index 3277638697..707acdd7b4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs @@ -67,7 +67,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public Int64 MinimumAdaptiveThrottleRate; public int ClientMaxRate; - public float BrustTime; + public float BurstTime; /// /// Default constructor @@ -94,8 +94,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (ClientMaxRate > 1000000) ClientMaxRate = 1000000; // no more than 8Mbps - BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10); - BrustTime *= 1e-3f; + BurstTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10); + BurstTime *= 1e-3f; // Adaptive is broken // AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 1daf091521..1bf05a3256 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs @@ -45,22 +45,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP private static Int32 m_counter = 0; -// private Int32 m_identifier; - protected const float m_timeScale = 1e-3f; /// - /// This is the number of m_minimumDripRate bytes - /// allowed in a burst - /// roughtly, with this settings, the maximum time system will take - /// to recheck a bucket in ms - /// + /// minimum recovery rate, ie bandwith /// - protected const float m_quantumsPerBurst = 5; + protected const float MINDRIPRATE = 500; - /// - /// - protected const float m_minimumDripRate = 1500; + // minimum and maximim burst size, ie max number of bytes token can have + protected const float MINBURST = 1500; // can't be less than one MTU or it will block + protected const float MAXBURST = 7500; /// Time of the last drip protected double m_lastDrip; @@ -109,10 +103,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP get { return m_burst; } set { float rate = (value < 0 ? 0 : value); - if (rate < 1.5f * m_minimumDripRate) - rate = 1.5f * m_minimumDripRate; - else if (rate > m_minimumDripRate * m_quantumsPerBurst) - rate = m_minimumDripRate * m_quantumsPerBurst; + if (rate < MINBURST) + rate = MINBURST; + else if (rate > MAXBURST) + rate = MAXBURST; m_burst = rate; } @@ -122,8 +116,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { get { float rate = RequestedBurst * BurstModifier(); - if (rate < m_minimumDripRate) - rate = m_minimumDripRate; + if (rate < MINBURST) + rate = MINBURST; return (float)rate; } } @@ -159,8 +153,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP return rate; rate *= m_parent.DripRateModifier(); - if (rate < m_minimumDripRate) - rate = m_minimumDripRate; + if (rate < MINDRIPRATE) + rate = MINDRIPRATE; return (float)rate; } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs index 1f978e13c3..32a6c404d6 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs @@ -215,14 +215,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // As with other network applications, assume that an acknowledged packet is an // indication that the network can handle a little more load, speed up the transmission ackedPacket.Client.FlowThrottle.AcknowledgePackets(1); - - if (!pendingAcknowledgement.FromResend) - { - // Calculate the round-trip time for this packet and its ACK - int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount; - if (rtt > 0) - ackedPacket.Client.UpdateRoundTrip(rtt); - } } else { diff --git a/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs b/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs index 1b6401afd3..56123a53ef 100644 --- a/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs +++ b/OpenSim/Region/CoreModules/Agent/Xfer/XferModule.cs @@ -50,8 +50,8 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private object timeTickLock = new object(); - private double lastTimeTick = 0.0; - private double lastFilesExpire = 0.0; + private int lastTimeTick = 0; + private int lastFilesExpire = 0; private bool inTimeTick = false; public struct XferRequest @@ -66,15 +66,15 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer { public byte[] Data; public int refsCount; - public double timeStampMS; + public int timeStampMS; } #region INonSharedRegionModule Members public void Initialise(IConfigSource config) { - lastTimeTick = Util.GetTimeStampMS() + 30000.0; - lastFilesExpire = lastTimeTick + 180000.0; + lastTimeTick = (int)Util.GetTimeStampMS() + 30000; + lastFilesExpire = lastTimeTick + 180000; } public void AddRegion(Scene scene) @@ -121,10 +121,9 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer { if(!inTimeTick) { - double now = Util.GetTimeStampMS(); - if(now - lastTimeTick > 1750.0) + int now = (int)Util.GetTimeStampMS(); + if(now - lastTimeTick > 750) { - if(Transfers.Count == 0 && NewFiles.Count == 0) lastTimeTick = now; else @@ -163,7 +162,7 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer { lock (NewFiles) { - double now = Util.GetTimeStampMS(); + int now = (int)Util.GetTimeStampMS(); if (NewFiles.ContainsKey(fileName)) { NewFiles[fileName].refsCount++; @@ -183,18 +182,18 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer } #endregion - public void expireFiles(double now) + public void expireFiles(int now) { lock (NewFiles) { // hopefully we will not have many files so nasty code will do it - if(now - lastFilesExpire > 120000.0) + if(now - lastFilesExpire > 120000) { lastFilesExpire = now; List expires = new List(); foreach(string fname in NewFiles.Keys) { - if(NewFiles[fname].refsCount == 0 && now - NewFiles[fname].timeStampMS > 120000.0) + if(NewFiles[fname].refsCount == 0 && now - NewFiles[fname].timeStampMS > 120000) expires.Add(fname); } foreach(string fname in expires) @@ -230,7 +229,7 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer } } - public void transfersTimeTick(double now) + public void transfersTimeTick(int now) { XferDownLoad[] xfrs; lock(Transfers) @@ -241,6 +240,7 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer xfrs = new XferDownLoad[Transfers.Count]; Transfers.Values.CopyTo(xfrs,0); } + foreach(XferDownLoad xfr in xfrs) { if(xfr.checkTime(now)) @@ -272,14 +272,15 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer if (!Transfers.ContainsKey(xferID)) { byte[] fileData = NewFiles[fileName].Data; - int burstSize = remoteClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset) >> 11; - if(Transfers.Count > 1) - burstSize /= Transfers.Count; + int burstSize = remoteClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Task) >> 10; + burstSize *= remoteClient.PingTimeMS; + burstSize >>= 10; // ping is ms, 1 round trip + if(burstSize > 32) + burstSize = 32; XferDownLoad transaction = new XferDownLoad(fileName, fileData, xferID, remoteClient, burstSize); Transfers.Add(xferID, transaction); - transaction.StartSend(); // The transaction for this file is on its way @@ -320,27 +321,27 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer public class XferDownLoad { - public IClientAPI Client; + public IClientAPI remoteClient; public byte[] Data = new byte[0]; public string FileName = String.Empty; public ulong XferID = 0; public bool isDeleted = false; private object myLock = new object(); - private double lastsendTimeMS; + private int lastACKTimeMS; private int LastPacket; private int lastBytes; private int lastSentPacket; private int lastAckPacket; - private int burstSize; - private int retries = 0; + private int burstSize; // additional packets, so can be zero + private int retries; public XferDownLoad(string fileName, byte[] data, ulong xferID, IClientAPI client, int burstsz) { FileName = fileName; Data = data; XferID = xferID; - Client = client; + remoteClient = client; burstSize = burstsz; } @@ -352,7 +353,7 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer { if(!isDeleted) { - Data = new byte[0]; + Data = null; isDeleted = true; } } @@ -381,30 +382,29 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer lastBytes = 1024; LastPacket--; } - } lastAckPacket = -1; lastSentPacket = -1; + retries = 0; - double now = Util.GetTimeStampMS(); - - SendBurst(now); + SendBurst(); return; } } - private void SendBurst(double now) + private void SendBurst() { int start = lastAckPacket + 1; int end = start + burstSize; if (end > LastPacket) end = LastPacket; - while(start <= end) - SendPacket(start++ , now); + while (start <= end) + SendPacket(start++); + lastACKTimeMS = (int)Util.GetTimeStampMS() + 1000; // reset timeout with some slack for queues delays } - private void SendPacket(int pkt, double now) + private void SendPacket(int pkt) { if(pkt > LastPacket) return; @@ -422,23 +422,9 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer pktid = (uint)pkt; } - byte[] transferData; - if(pkt == 0) - { - transferData = new byte[pktsize + 4]; - Array.Copy(Utils.IntToBytes(Data.Length), 0, transferData, 0, 4); - Array.Copy(Data, 0, transferData, 4, pktsize); - } - else - { - transferData = new byte[pktsize]; - Array.Copy(Data, pkt << 10, transferData, 0, pktsize); - } - - Client.SendXferPacket(XferID, pktid, transferData, false); + remoteClient.SendXferPacket(XferID, pktid, Data, pkt << 10, pktsize, true); lastSentPacket = pkt; - lastsendTimeMS = now; } /// @@ -453,39 +439,49 @@ namespace OpenSim.Region.CoreModules.Agent.Xfer if(isDeleted) return true; - packet &= 0x7fffffff; - if(lastAckPacket < packet) + packet &= 0x7fffffff; + if (lastAckPacket < packet) lastAckPacket = (int)packet; - - if(lastAckPacket == LastPacket) + else if (lastAckPacket == LastPacket) { done(); return true; } - double now = Util.GetTimeStampMS(); - SendPacket(lastSentPacket + 1, now); + + lastACKTimeMS = (int)Util.GetTimeStampMS(); + retries = 0; + SendPacket(lastSentPacket + 1); return false; } } - public bool checkTime(double now) + public bool checkTime(int now) { - if(Monitor.TryEnter(myLock)) + if (Monitor.TryEnter(myLock)) { - if(!isDeleted) + if (!isDeleted) { - double timeMS = now - lastsendTimeMS; - if(timeMS > 60000.0) - done(); - else if(timeMS > 3500.0 && retries++ < 3) + int timeMS = now - lastACKTimeMS; + int tout = 5 * remoteClient.PingTimeMS; + if (tout < 1000) + tout = 1000; + else if(tout > 10000) + tout = 10000; + + if (timeMS > tout) { - burstSize >>= 1; - SendBurst(now); + if (++retries > 4) + done(); + else + { + burstSize = lastSentPacket - lastAckPacket; + SendBurst(); + } } } - + bool isdel = isDeleted; Monitor.Exit(myLock); - return isDeleted; + return isdel; } return false; } diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs index 5457dc3831..e63629e680 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs @@ -142,8 +142,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests // We must update the scenes in order to make the root new root agents trigger position updates in their // children. - sceneWest.Update(1); - sceneEast.Update(1); + sceneWest.Update(4); + sceneEast.Update(4); + sp1.DrawDistance += 64; + sp2.DrawDistance += 64; + sceneWest.Update(2); + sceneEast.Update(2); // Check child positions are correct. Assert.AreEqual( @@ -233,8 +237,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests // We must update the scenes in order to make the root new root agents trigger position updates in their // children. - sceneNorth.Update(1); - sceneSouth.Update(1); + sceneNorth.Update(4); + sceneSouth.Update(4); + sp1.DrawDistance += 64; + sp2.DrawDistance += 64; + sceneNorth.Update(2); + sceneSouth.Update(2); // Check child positions are correct. Assert.AreEqual( diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 772485cfeb..39bf46c619 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends private void OnMakeRootAgent(ScenePresence sp) { - if(sp.gotCrossUpdate) + if(sp.m_gotCrossUpdate) return; RecacheFriends(sp.ControllingClient); diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 9471c908cb..187df314e4 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -54,14 +54,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; - public const int DefaultMaxTransferDistance = 4095; public const bool WaitForAgentArrivedAtDestinationDefault = true; - /// - /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. - /// - public int MaxTransferDistance { get; set; } - /// /// If true then on a teleport, the source region waits for a callback from the destination region. If /// a callback fails to arrive within a set time then the user is pulled back into the source region. @@ -227,11 +221,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer WaitForAgentArrivedAtDestination = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); - MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); - } - else - { - MaxTransferDistance = DefaultMaxTransferDistance; } m_entityTransferStateMachine = new EntityTransferStateMachine(this); @@ -639,29 +628,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return true; } - /// - /// Determines whether this instance is within the max transfer distance. - /// - /// - /// - /// - /// true if this instance is within max transfer distance; otherwise, false. - /// - private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) - { - if(MaxTransferDistance == 0) - return true; - -// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); -// -// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", -// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); - - // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. - return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance - && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; - } - /// /// Wraps DoTeleportInternal() and manages the transfer state. /// @@ -722,18 +688,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RegionInfo sourceRegion = sp.Scene.RegionInfo; - if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) - { - sp.ControllingClient.SendTeleportFailed( - string.Format( - "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", - finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, - sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, - MaxTransferDistance)); - - return; - } - ulong destinationHandle = finalDestination.RegionHandle; // Let's do DNS resolution only once in this process, please! @@ -1103,6 +1057,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } } + else + { + if(!sp.IsInLocalTransit || sp.RegionViewDistance == 0) + { + // this will be closed by callback + if (agentCircuit.ChildrenCapSeeds != null) + agentCircuit.ChildrenCapSeeds.Remove(sp.RegionHandle); + } + } string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);; @@ -1175,7 +1138,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.SenderWantsToWaitForRoot = true; - //SetCallbackURL(agent, sp.Scene.RegionInfo); + if(!sp.IsInLocalTransit || sp.RegionViewDistance == 0) + SetNewCallbackURL(agent, sp.Scene.RegionInfo); // Reset the do not close flag. This must be done before the destination opens child connections (here // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible @@ -1183,11 +1147,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // in no close. sp.DoNotCloseAfterTeleport = false; + // we still need to flag this as child here + // a close from receiving region seems possible to happen before we reach sp.MakeChildAgent below + // causing the agent to be loggout out from grid incorrectly + sp.IsChildAgent = true; // Send the Update. If this returns true, we know the client has contacted the destination // via CompleteMovementIntoRegion, so we can let go. // If it returns false, something went wrong, and we need to abort. if (!UpdateAgent(reg, finalDestination, agent, sp, ctx)) { + sp.IsChildAgent = false; if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) { m_interRegionTeleportAborts.Value++; @@ -1208,7 +1177,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } - m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + //shut this up for now + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + + //m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); sp.HasMovedAway(!(OutSideViewRange || logout)); @@ -1224,25 +1196,33 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.closeAllChildAgents(); else sp.CloseChildAgents(childRegionsToClose); + } - // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone - // goes by HG hook - if (NeedsClosing(reg, OutSideViewRange)) + + // if far jump we do need to close anyways + if (NeedsClosing(reg, OutSideViewRange)) + { + int count = 60; + do { - if (!sp.Scene.IncomingPreCloseClient(sp)) - { - sp.IsInTransit = false; + Thread.Sleep(250); + if(sp.IsDeleted) return; - } + if(!sp.IsInTransit) + break; + } while (--count > 0); - // viewers and target region take extra time to process the tp - Thread.Sleep(15000); + + if (!sp.IsDeleted) + { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); + "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport {2}", sp.Name, Scene.Name, sp.IsInTransit?"timeout":""); sp.Scene.CloseAgent(sp.UUID, false); } - sp.IsInTransit = false; + return; } + // otherwise keep child + sp.IsInTransit = false; } /// @@ -1313,9 +1293,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { agent.CallbackURI = region.ServerURI + "agent/" + agent.AgentID.ToString() + "/" + region.RegionID.ToString() + "/release/"; + //m_log.DebugFormat( + // "[ENTITY TRANSFER MODULE]: Set release callback URL to {0} in {1}", + // agent.CallbackURI, region.RegionName); + } + + protected virtual void SetNewCallbackURL(AgentData agent, RegionInfo region) + { + agent.NewCallbackURI = region.ServerURI + "agent/" + agent.AgentID.ToString() + "/" + region.RegionID.ToString() + "/release/"; + m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Set release callback URL to {0} in {1}", - agent.CallbackURI, region.RegionName); + agent.NewCallbackURI, region.RegionName); } /// @@ -1590,6 +1579,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public ScenePresence CrossAsync(ScenePresence agent, bool isFlying) { + if(agent.RegionViewDistance == 0) + return agent; + Vector3 newpos; EntityTransferContext ctx = new EntityTransferContext(); string failureReason; @@ -1810,11 +1802,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer cAgent.Position = pos; cAgent.ChildrenCapSeeds = agent.KnownRegions; - childRegionsToClose = agent.GetChildAgentsToClose(neighbourRegion.RegionHandle, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); - if(cAgent.ChildrenCapSeeds != null) + if(ctx.OutboundVersion < 0.7f) { - foreach(ulong regh in childRegionsToClose) - cAgent.ChildrenCapSeeds.Remove(regh); + childRegionsToClose = agent.GetChildAgentsToClose(neighbourRegion.RegionHandle, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); + if(cAgent.ChildrenCapSeeds != null) + { + foreach(ulong regh in childRegionsToClose) + cAgent.ChildrenCapSeeds.Remove(regh); + } } if (isFlying) @@ -1879,7 +1874,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); Vector3 vel2 = Vector3.Zero; - if((agent.crossingFlags & 2) != 0) + if((agent.m_crossingFlags & 2) != 0) vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); if (m_eqModule != null) @@ -1905,10 +1900,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if(childRegionsToClose != null) agent.CloseChildAgents(childRegionsToClose); - if((agent.crossingFlags & 8) == 0) + if((agent.m_crossingFlags & 8) == 0) agent.ClearControls(); // don't let attachments delete (called in HasMovedAway) disturb taken controls on viewers - agent.HasMovedAway((agent.crossingFlags & 8) == 0); + agent.HasMovedAway((agent.m_crossingFlags & 8) == 0); agent.MakeChildAgent(neighbourRegion.RegionHandle); @@ -1957,12 +1952,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (seeds.ContainsKey(regionhandler)) seeds.Remove(regionhandler); -/* - List oldregions = new List(seeds.Keys); - if (oldregions.Contains(currentRegionHandler)) - oldregions.Remove(currentRegionHandler); -*/ if (!seeds.ContainsKey(currentRegionHandler)) seeds.Add(currentRegionHandler, sp.ControllingClient.RequestClientInfo().CapsPath); @@ -1971,6 +1961,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.BaseFolder = UUID.Zero; agent.InventoryFolder = UUID.Zero; agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, region); + agent.startfar = sp.DrawDistance; agent.child = true; agent.Appearance = new AvatarAppearance(); agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; @@ -1999,24 +1990,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.Mac = currentAgentCircuit.Mac; agent.Id0 = currentAgentCircuit.Id0; } -/* - AgentPosition agentpos = null; - if (oldregions.Count > 0) - { - agentpos = new AgentPosition(); - agentpos.AgentID = new UUID(sp.UUID.Guid); - agentpos.SessionID = sp.ControllingClient.SessionId; - agentpos.Size = sp.Appearance.AvatarSize; - agentpos.Center = sp.CameraPosition; - agentpos.Far = sp.DrawDistance; - agentpos.Position = sp.AbsolutePosition; - agentpos.Velocity = sp.Velocity; - agentpos.RegionHandle = currentRegionHandler; - agentpos.Throttles = sp.ControllingClient.GetThrottlesPacked(1); - agentpos.ChildrenCapSeeds = seeds; - } -*/ IPEndPoint external = region.ExternalEndPoint; if (external != null) { @@ -2025,20 +1999,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer InformClientOfNeighbourCompleted, d); } -/* - if(oldregions.Count >0) - { - uint neighbourx; - uint neighboury; - UUID scope = sp.Scene.RegionInfo.ScopeID; - foreach (ulong handler in oldregions) - { - Utils.LongToUInts(handler, out neighbourx, out neighboury); - GridRegion neighbour = sp.Scene.GridService.GetRegionByPosition(scope, (int)neighbourx, (int)neighboury); - sp.Scene.SimulationService.UpdateAgent(neighbour, agentpos); - } - } - */ } #endregion @@ -2048,6 +2008,44 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private delegate void InformClientOfNeighbourDelegate( ScenePresence avatar, AgentCircuitData a, GridRegion reg, IPEndPoint endPoint, bool newAgent); + List RegionsInView(Vector3 pos, RegionInfo curregion, List fullneighbours, float viewrange) + { + List ret = new List(); + if(fullneighbours.Count == 0 || viewrange == 0) + return ret; + + int curX = (int)Util.RegionToWorldLoc(curregion.RegionLocX) + (int)pos.X; + int minX = curX - (int)viewrange; + int maxX = curX + (int)viewrange; + int curY = (int)Util.RegionToWorldLoc(curregion.RegionLocY) + (int)pos.Y; + int minY = curY - (int)viewrange; + int maxY = curY + (int)viewrange; + int rtmp; + + foreach (GridRegion r in fullneighbours) + { + OpenSim.Framework.RegionFlags? regionFlags = r.RegionFlags; + if (regionFlags != null) + { + if ((regionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0) + continue; + } + + rtmp = r.RegionLocX; + if (maxX < rtmp) + continue; + if (minX > rtmp + r.RegionSizeX) + continue; + rtmp = r.RegionLocY; + if (maxY < rtmp) + continue; + if (minY > rtmp + r.RegionSizeY) + continue; + ret.Add(r); + } + return ret; + } + /// /// This informs all neighbouring regions about agent "avatar". /// and as important informs the avatar about then @@ -2055,22 +2053,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// public void EnableChildAgents(ScenePresence sp) { - // assumes that out of view range regions are disconnected by the previus region + // assumes that out of view range regions are disconnected by the previous region - List neighbours = new List(); Scene spScene = sp.Scene; - RegionInfo m_regionInfo = spScene.RegionInfo; + RegionInfo regionInfo = spScene.RegionInfo; - if (m_regionInfo != null) + if (regionInfo == null) + return; + + ulong currentRegionHandler = regionInfo.RegionHandle; + + List neighbours; + if (sp.RegionViewDistance > 0) { - neighbours = GetNeighbors(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); + List fullneighbours = GetNeighbors(sp); + neighbours = RegionsInView(sp.AbsolutePosition, regionInfo, fullneighbours, sp.RegionViewDistance); } else - { - m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?"); - } - - ulong currentRegionHandler = m_regionInfo.RegionHandle; + neighbours = new List(); LinkedList previousRegionNeighbourHandles; Dictionary seeds; @@ -2106,13 +2106,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer List cagents = new List(); List newneighbours = new List(); - bool notHG = (sp.TeleportFlags & Constants.TeleportFlags.ViaHGLogin) == 0; - foreach (GridRegion neighbour in neighbours) { ulong handler = neighbour.RegionHandle; - if (notHG && previousRegionNeighbourHandles.Contains(handler)) + if (previousRegionNeighbourHandles.Contains(handler)) { // agent already knows this region previousRegionNeighbourHandles.Remove(handler); @@ -2130,7 +2128,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.child = true; agent.Appearance = new AvatarAppearance(); agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; - + agent.startfar = sp.DrawDistance; if (currentAgentCircuit != null) { agent.ServiceURLs = currentAgentCircuit.ServiceURLs; @@ -2159,13 +2157,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer foreach (ulong handler in previousRegionNeighbourHandles) seeds.Remove(handler); - if(notHG) // does not work on HG - { - toclose = new List(previousRegionNeighbourHandles); -// sp.CloseChildAgents(toclose); - } - else - toclose = new List(); + toclose = new List(previousRegionNeighbourHandles); } else toclose = new List(); @@ -2197,7 +2189,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Util.FireAndForget(delegate { - Thread.Sleep(500); // the original delay that was at InformClientOfNeighbourAsync start int count = 0; IPEndPoint ipe; @@ -2220,10 +2211,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } count++; } - else if (notHG && !previousRegionNeighbourHandles.Contains(handler)) + else if (!previousRegionNeighbourHandles.Contains(handler)) { spScene.SimulationService.UpdateAgent(neighbour, agentpos); } + if (sp.IsDeleted) + return; } catch (Exception e) { @@ -2240,6 +2233,214 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } + public void CheckChildAgents(ScenePresence sp) + { + // assumes that out of view range regions are disconnected by the previous region + + Scene spScene = sp.Scene; + RegionInfo regionInfo = spScene.RegionInfo; + + if (regionInfo == null) + return; + + ulong currentRegionHandler = regionInfo.RegionHandle; + + List neighbours; + if (sp.RegionViewDistance > 0) + { + List fullneighbours = GetNeighbors(sp); + neighbours = RegionsInView(sp.AbsolutePosition, regionInfo, fullneighbours, sp.RegionViewDistance); + } + else + neighbours = new List(); + + LinkedList previousRegionNeighbourHandles = new LinkedList(sp.KnownRegions.Keys); + + IClientAPI spClient = sp.ControllingClient; + + AgentCircuitData currentAgentCircuit = + spScene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); + + List cagents = new List(); + List newneighbours = new List(); + + foreach (GridRegion neighbour in neighbours) + { + ulong handler = neighbour.RegionHandle; + + if (previousRegionNeighbourHandles.Contains(handler)) + { + // agent already knows this region + previousRegionNeighbourHandles.Remove(handler); + continue; + } + + if (handler == currentRegionHandler) + continue; + + // a new region to add + AgentCircuitData agent = spClient.RequestClientInfo(); + agent.BaseFolder = UUID.Zero; + agent.InventoryFolder = UUID.Zero; + agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); + agent.child = true; + agent.Appearance = new AvatarAppearance(); + agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; + agent.startfar = sp.DrawDistance; + if (currentAgentCircuit != null) + { + agent.ServiceURLs = currentAgentCircuit.ServiceURLs; + agent.IPAddress = currentAgentCircuit.IPAddress; + agent.Viewer = currentAgentCircuit.Viewer; + agent.Channel = currentAgentCircuit.Channel; + agent.Mac = currentAgentCircuit.Mac; + agent.Id0 = currentAgentCircuit.Id0; + } + + newneighbours.Add(neighbour); + agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + sp.AddNeighbourRegion(neighbour, agent.CapsPath); + + agent.ChildrenCapSeeds = null; + cagents.Add(agent); + } + + List toclose; + // previousRegionNeighbourHandles now contains regions to forget + if (previousRegionNeighbourHandles.Count > 0) + { + if (previousRegionNeighbourHandles.Contains(currentRegionHandler)) + previousRegionNeighbourHandles.Remove(currentRegionHandler); + + foreach (ulong handler in previousRegionNeighbourHandles) + sp.KnownRegions.Remove(handler); + + toclose = new List(previousRegionNeighbourHandles); + } + else + toclose = new List(); + + ICapabilitiesModule capsModule = spScene.CapsModule; + if (capsModule != null) + capsModule.SetChildrenSeed(sp.UUID, sp.KnownRegions); + + if (toclose.Count > 0) + sp.CloseChildAgents(toclose); + + if (newneighbours.Count > 0) + { + int count = 0; + IPEndPoint ipe; + + foreach (GridRegion neighbour in newneighbours) + { + try + { + ipe = neighbour.ExternalEndPoint; + if (ipe != null) + InformClientOfNeighbourAsync(sp, cagents[count], neighbour, ipe, true); + else + { + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: lost DNS resolution for neighbour {0}", neighbour.ExternalHostName); + } + count++; + if (sp.IsDeleted) + return; + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER MODULE]: Error creating child agent at {0} ({1} ({2}, {3}). {4}", + neighbour.ExternalHostName, + neighbour.RegionHandle, + neighbour.RegionLocX, + neighbour.RegionLocY, + e); + } + } + } + } + + public void CloseOldChildAgents(ScenePresence sp) + { + Scene spScene = sp.Scene; + RegionInfo regionInfo = spScene.RegionInfo; + + if (regionInfo == null) + return; + + ulong currentRegionHandler = regionInfo.RegionHandle; + + List neighbours; + if (sp.RegionViewDistance > 0) + { + List fullneighbours = GetNeighbors(sp); + neighbours = RegionsInView(sp.AbsolutePosition, regionInfo, fullneighbours, sp.RegionViewDistance); + } + else + neighbours = new List(); + + LinkedList previousRegionNeighbourHandles; + Dictionary seeds; + ICapabilitiesModule capsModule = spScene.CapsModule; + + if (capsModule != null) + { + seeds = new Dictionary(capsModule.GetChildrenSeeds(sp.UUID)); + previousRegionNeighbourHandles = new LinkedList(seeds.Keys); + } + else + { + seeds = new Dictionary(); + previousRegionNeighbourHandles = new LinkedList(); + } + + IClientAPI spClient = sp.ControllingClient; + + // This will fail if the user aborts login + try + { + if (!seeds.ContainsKey(currentRegionHandler)) + seeds.Add(currentRegionHandler, spClient.RequestClientInfo().CapsPath); + } + catch + { + return; + } + + foreach (GridRegion neighbour in neighbours) + { + ulong handler = neighbour.RegionHandle; + + if (previousRegionNeighbourHandles.Contains(handler)) + previousRegionNeighbourHandles.Remove(handler); + } + + List toclose; + // previousRegionNeighbourHandles now contains regions to forget + if (previousRegionNeighbourHandles.Count == 0) + return; + + if (previousRegionNeighbourHandles.Contains(currentRegionHandler)) + previousRegionNeighbourHandles.Remove(currentRegionHandler); + + foreach (ulong handler in previousRegionNeighbourHandles) + seeds.Remove(handler); + + toclose = new List(previousRegionNeighbourHandles); + + if (capsModule != null) + capsModule.SetChildrenSeed(sp.UUID, seeds); + + sp.KnownRegions = seeds; + sp.SetNeighbourRegionSizeInfo(neighbours); + + Util.FireAndForget(delegate + { + sp.CloseChildAgents(toclose); + }); + } + // Computes the difference between two region bases. // Returns a vector of world coordinates (meters) from base of first region to the second. // The first region is the home region of the passed scene presence. @@ -2440,6 +2641,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } + // all this code should be moved to scene replacing the now bad one there + // cache Neighbors + List Neighbors = null; + DateTime LastNeighborsTime = DateTime.MinValue; + /// /// Return the list of online regions that are considered to be neighbours to the given scene. /// @@ -2447,39 +2653,41 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// - protected List GetNeighbors(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) + protected List GetNeighbors(ScenePresence avatar) { Scene pScene = avatar.Scene; - RegionInfo m_regionInfo = pScene.RegionInfo; + + uint dd = (uint)pScene.MaxRegionViewDistance; + if(dd <= 1) + return new List(); + + if (Neighbors != null && (DateTime.UtcNow - LastNeighborsTime).TotalSeconds < 30) + { + return Neighbors; + } + + RegionInfo regionInfo = pScene.RegionInfo; List neighbours; - uint dd = (uint)avatar.RegionViewDistance; + dd--; - // until avatar movement updates client connections, we need to send at least this current region immediate neighbors - uint ddX = Math.Max(dd, Constants.RegionSize); - uint ddY = Math.Max(dd, Constants.RegionSize); + uint startX = Util.RegionToWorldLoc(regionInfo.RegionLocX); + uint endX = startX + regionInfo.RegionSizeX; + uint startY = Util.RegionToWorldLoc(regionInfo.RegionLocY); + uint endY = startY + regionInfo.RegionSizeY; - ddX--; - ddY--; + startX -= dd; + startY -= dd; + endX += dd; + endY += dd; - // reference to region edges. Should be avatar position - uint startX = Util.RegionToWorldLoc(pRegionLocX); - uint endX = startX + m_regionInfo.RegionSizeX; - uint startY = Util.RegionToWorldLoc(pRegionLocY); - uint endY = startY + m_regionInfo.RegionSizeY; - - startX -= ddX; - startY -= ddY; - endX += ddX; - endY += ddY; - - neighbours - = avatar.Scene.GridService.GetRegionRange( - m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); + neighbours = avatar.Scene.GridService.GetRegionRange( + regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1). - neighbours.RemoveAll( r => r.RegionID == m_regionInfo.RegionID ); - + neighbours.RemoveAll( r => r.RegionID == regionInfo.RegionID ); + Neighbors = neighbours; + LastNeighborsTime = DateTime.UtcNow; return neighbours; } #endregion @@ -2488,7 +2696,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public void AgentArrivedAtDestination(UUID id) { - m_entityTransferStateMachine.SetAgentArrivedAtDestination(id); + ScenePresence sp = Scene.GetScenePresence(id); + if(sp == null || sp.IsDeleted || !sp.IsInTransit) + return; + + //Scene.CloseAgent(sp.UUID, false); + sp.IsInTransit = false; + //m_entityTransferStateMachine.SetAgentArrivedAtDestination(id); } #endregion diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs index 1529fc2764..615ae787ad 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser if (sp.IsNPC) return; - if(sp.gotCrossUpdate) + if(sp.m_gotCrossUpdate) { Util.FireAndForget(delegate { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs index a7e62eb755..6f4eace92f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs @@ -50,7 +50,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence public void AddRegion(Scene scene) { scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; - scene.EventManager.OnNewClient += OnNewClient; m_PresenceService.LogoutRegionAgents(scene.RegionInfo.RegionID); @@ -61,7 +60,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence public void RemoveRegion(Scene scene) { scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; - scene.EventManager.OnNewClient -= OnNewClient; m_PresenceService.LogoutRegionAgents(scene.RegionInfo.RegionID); } @@ -71,7 +69,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence if (sp.IsNPC) return; - if(sp.gotCrossUpdate) + sp.ControllingClient.OnConnectionClosed += OnConnectionClose; + + if (sp.m_gotCrossUpdate) { Util.FireAndForget(delegate { @@ -89,11 +89,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence m_PresenceService.ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID); } - public void OnNewClient(IClientAPI client) - { - client.OnConnectionClosed += OnConnectionClose; - } - public void OnConnectionClose(IClientAPI client) { if (client != null && client.SceneAgent != null && !client.SceneAgent.IsChildAgent) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index ac28ceeac0..986a44f2dd 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -574,7 +574,7 @@ namespace OpenSim.Region.CoreModules.World.Estate Scene.RegionInfo.RegionSettings.Save(); TriggerRegionInfoChange(); sendRegionHandshakeToAll(); - sendRegionInfoPacketToAll(); +// sendRegionInfoPacketToAll(); } private void handleCommitEstateTerrainTextureRequest(IClientAPI remoteClient) @@ -1404,7 +1404,7 @@ namespace OpenSim.Region.CoreModules.World.Estate RegionInfoForEstateMenuArgs args = new RegionInfoForEstateMenuArgs(); args.billableFactor = Scene.RegionInfo.EstateSettings.BillableFactor; args.estateID = Scene.RegionInfo.EstateSettings.EstateID; - args.maxAgents = (byte)Scene.RegionInfo.RegionSettings.AgentLimit; + args.maxAgents = Scene.RegionInfo.RegionSettings.AgentLimit; args.objectBonusFactor = (float)Scene.RegionInfo.RegionSettings.ObjectBonus; args.parentEstateID = Scene.RegionInfo.EstateSettings.ParentEstateID; args.pricePerMeter = Scene.RegionInfo.EstateSettings.PricePerMeter; @@ -1419,6 +1419,8 @@ namespace OpenSim.Region.CoreModules.World.Estate args.waterHeight = (float)Scene.RegionInfo.RegionSettings.WaterHeight; args.simName = Scene.RegionInfo.RegionName; args.regionType = Scene.RegionInfo.RegionType; + args.AgentCapacity = Scene.RegionInfo.AgentCapacity; + args.ObjectsCapacity = Scene.RegionInfo.ObjectCapacity; remote_client.SendRegionInfoToEstateMenu(args); } @@ -1518,42 +1520,7 @@ namespace OpenSim.Region.CoreModules.World.Estate public void sendRegionHandshake(IClientAPI remoteClient) { - RegionHandshakeArgs args = new RegionHandshakeArgs(); - - args.isEstateManager = Scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(remoteClient.AgentId); - if (Scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero && Scene.RegionInfo.EstateSettings.EstateOwner == remoteClient.AgentId) - args.isEstateManager = true; - - args.billableFactor = Scene.RegionInfo.EstateSettings.BillableFactor; - args.terrainStartHeight0 = (float)Scene.RegionInfo.RegionSettings.Elevation1SW; - args.terrainHeightRange0 = (float)Scene.RegionInfo.RegionSettings.Elevation2SW; - args.terrainStartHeight1 = (float)Scene.RegionInfo.RegionSettings.Elevation1NW; - args.terrainHeightRange1 = (float)Scene.RegionInfo.RegionSettings.Elevation2NW; - args.terrainStartHeight2 = (float)Scene.RegionInfo.RegionSettings.Elevation1SE; - args.terrainHeightRange2 = (float)Scene.RegionInfo.RegionSettings.Elevation2SE; - args.terrainStartHeight3 = (float)Scene.RegionInfo.RegionSettings.Elevation1NE; - args.terrainHeightRange3 = (float)Scene.RegionInfo.RegionSettings.Elevation2NE; - args.simAccess = Scene.RegionInfo.AccessLevel; - args.waterHeight = (float)Scene.RegionInfo.RegionSettings.WaterHeight; - args.regionFlags = GetRegionFlags(); - args.regionName = Scene.RegionInfo.RegionName; - args.SimOwner = Scene.RegionInfo.EstateSettings.EstateOwner; - - args.terrainBase0 = UUID.Zero; - args.terrainBase1 = UUID.Zero; - args.terrainBase2 = UUID.Zero; - args.terrainBase3 = UUID.Zero; - args.terrainDetail0 = Scene.RegionInfo.RegionSettings.TerrainTexture1; - args.terrainDetail1 = Scene.RegionInfo.RegionSettings.TerrainTexture2; - args.terrainDetail2 = Scene.RegionInfo.RegionSettings.TerrainTexture3; - args.terrainDetail3 = Scene.RegionInfo.RegionSettings.TerrainTexture4; - -// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 1 {0} for region {1}", args.terrainDetail0, Scene.RegionInfo.RegionName); -// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 2 {0} for region {1}", args.terrainDetail1, Scene.RegionInfo.RegionName); -// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 3 {0} for region {1}", args.terrainDetail2, Scene.RegionInfo.RegionName); -// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 4 {0} for region {1}", args.terrainDetail3, Scene.RegionInfo.RegionName); - - remoteClient.SendRegionHandshake(Scene.RegionInfo,args); + remoteClient.SendRegionHandshake(); } public void handleEstateChangeInfo(IClientAPI remoteClient, UUID invoice, UUID senderID, UInt32 parms1, UInt32 parms2) @@ -1673,7 +1640,6 @@ namespace OpenSim.Region.CoreModules.World.Estate client.OnRegionInfoRequest += HandleRegionInfoRequest; client.OnEstateCovenantRequest += HandleEstateCovenantRequest; client.OnLandStatRequest += HandleLandStatRequest; - sendRegionHandshake(client); } @@ -1681,39 +1647,43 @@ namespace OpenSim.Region.CoreModules.World.Estate { RegionFlags flags = RegionFlags.None; - if (Scene.RegionInfo.EstateSettings.FixedSun) - flags |= RegionFlags.SunFixed; - if (Scene.RegionInfo.EstateSettings.PublicAccess) - flags |= (RegionFlags.PublicAllowed | - RegionFlags.ExternallyVisible); - if (Scene.RegionInfo.EstateSettings.AllowVoice) - flags |= RegionFlags.AllowVoice; - if (Scene.RegionInfo.EstateSettings.AllowDirectTeleport) - flags |= RegionFlags.AllowDirectTeleport; - if (Scene.RegionInfo.EstateSettings.DenyAnonymous) - flags |= RegionFlags.DenyAnonymous; - if (Scene.RegionInfo.EstateSettings.DenyIdentified) - flags |= RegionFlags.DenyIdentified; - if (Scene.RegionInfo.EstateSettings.DenyTransacted) - flags |= RegionFlags.DenyTransacted; - if (Scene.RegionInfo.EstateSettings.AbuseEmailToEstateOwner) - flags |= RegionFlags.AbuseEmailToEstateOwner; - if (Scene.RegionInfo.EstateSettings.BlockDwell) - flags |= RegionFlags.BlockDwell; - if (Scene.RegionInfo.EstateSettings.EstateSkipScripts) - flags |= RegionFlags.EstateSkipScripts; - if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport) - flags |= RegionFlags.ResetHomeOnTeleport; - if (Scene.RegionInfo.EstateSettings.TaxFree) - flags |= RegionFlags.TaxFree; if (Scene.RegionInfo.EstateSettings.AllowLandmark) flags |= RegionFlags.AllowLandmark; - if (Scene.RegionInfo.EstateSettings.AllowParcelChanges) - flags |= RegionFlags.AllowParcelChanges; if (Scene.RegionInfo.EstateSettings.AllowSetHome) flags |= RegionFlags.AllowSetHome; + if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport) + flags |= RegionFlags.ResetHomeOnTeleport; + if (Scene.RegionInfo.EstateSettings.FixedSun) + flags |= RegionFlags.SunFixed; + if (Scene.RegionInfo.EstateSettings.TaxFree) // this is now wrong means ALLOW_ACCESS_OVERRIDE + flags |= RegionFlags.TaxFree; + + if (Scene.RegionInfo.EstateSettings.PublicAccess) //?? + flags |= (RegionFlags.PublicAllowed | RegionFlags.ExternallyVisible); + + if (Scene.RegionInfo.EstateSettings.BlockDwell) + flags |= RegionFlags.BlockDwell; + if (Scene.RegionInfo.EstateSettings.AllowDirectTeleport) + flags |= RegionFlags.AllowDirectTeleport; + if (Scene.RegionInfo.EstateSettings.EstateSkipScripts) + flags |= RegionFlags.EstateSkipScripts; + + if (Scene.RegionInfo.EstateSettings.DenyAnonymous) + flags |= RegionFlags.DenyAnonymous; + if (Scene.RegionInfo.EstateSettings.DenyIdentified) // unused? + flags |= RegionFlags.DenyIdentified; + if (Scene.RegionInfo.EstateSettings.DenyTransacted) // unused? + flags |= RegionFlags.DenyTransacted; + if (Scene.RegionInfo.EstateSettings.AllowParcelChanges) + flags |= RegionFlags.AllowParcelChanges; + if (Scene.RegionInfo.EstateSettings.AbuseEmailToEstateOwner) // now is block fly + flags |= RegionFlags.AbuseEmailToEstateOwner; + if (Scene.RegionInfo.EstateSettings.AllowVoice) + flags |= RegionFlags.AllowVoice; + + if (Scene.RegionInfo.EstateSettings.DenyMinors) - flags |= (RegionFlags)(1 << 30); + flags |= RegionFlags.DenyAgeUnverified; return (uint)flags; } diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs index 993b7825c0..9e687eb0aa 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs @@ -247,11 +247,11 @@ namespace OpenSim.Region.CoreModules.World.Land m_landManagementModule.setParcelOtherCleanTime(remoteClient, localID, otherCleanTime); } } - public void sendClientInitialLandInfo(IClientAPI remoteClient) + public void sendClientInitialLandInfo(IClientAPI remoteClient, bool overlay) { if (m_landManagementModule != null) { - m_landManagementModule.sendClientInitialLandInfo(remoteClient); + m_landManagementModule.sendClientInitialLandInfo(remoteClient, overlay); } } #endregion diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 8c327d8c72..b67cad7e95 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -491,7 +491,7 @@ namespace OpenSim.Region.CoreModules.World.Land return; } - public void sendClientInitialLandInfo(IClientAPI remoteClient) + public void sendClientInitialLandInfo(IClientAPI remoteClient, bool overlay) { ScenePresence avatar; @@ -507,7 +507,8 @@ namespace OpenSim.Region.CoreModules.World.Land avatar.currentParcelUUID = over.LandData.GlobalID; over.SendLandUpdateToClient(avatar.ControllingClient); } - SendParcelOverlay(remoteClient); + if(overlay) + SendParcelOverlay(remoteClient); } public void SendLandUpdate(ScenePresence avatar, ILandObject over) @@ -998,6 +999,39 @@ namespace OpenSim.Region.CoreModules.World.Land } } + public ILandObject GetLandObjectinLandUnits(int x, int y) + { + if (m_landList.Count == 0 || m_landIDList == null) + return null; + + lock (m_landIDList) + { + try + { + return m_landList[m_landIDList[x, y]]; + } + catch (IndexOutOfRangeException) + { + return null; + } + } + } + + public int GetLandObjectIDinLandUnits(int x, int y) + { + lock (m_landIDList) + { + try + { + return m_landIDList[x, y]; + } + catch (IndexOutOfRangeException) + { + return -1; + } + } + } + // Create a 'parcel is here' bitmap for the parcel identified by the passed landID private bool[,] CreateBitmapForID(int landID) { @@ -1282,18 +1316,9 @@ namespace OpenSim.Region.CoreModules.World.Land #region Parcel Updating /// - /// 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. + /// Send the parcel overlay blocks to the client. /// /// The object representing the 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 public void SendParcelOverlay(IClientAPI remote_client) { if (remote_client.SceneAgent.PresenceType == PresenceType.Npc) @@ -1301,99 +1326,133 @@ namespace OpenSim.Region.CoreModules.World.Land const int LAND_BLOCKS_PER_PACKET = 1024; + int curID; + int southID; + byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; int byteArrayCount = 0; int sequenceID = 0; + int sx = (int)m_scene.RegionInfo.RegionSizeX / LandUnit; + byte curByte; + byte tmpByte; + // Layer data is in LandUnit (4m) chunks - for (int y = 0; y < m_scene.RegionInfo.RegionSizeY; y += LandUnit) + for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / LandUnit; ++y) { - for (int x = 0; x < m_scene.RegionInfo.RegionSizeX; x += LandUnit) + for (int x = 0; x < sx;) { - byte tempByte = 0; //This represents the byte for the current 4x4 + curID = GetLandObjectIDinLandUnits(x,y); + if(curID < 0) + continue; - ILandObject currentParcelBlock = GetLandObject(x, y); + ILandObject currentParcel = GetLandObject(curID); + if (currentParcel == null) + continue; - if (currentParcelBlock != null) + // types + if (currentParcel.LandData.OwnerID == remote_client.AgentId) { - // types - if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) - { - //Owner Flag - tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_REQUESTER; - } - else if (currentParcelBlock.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelBlock.LandData.GroupID)) - { - tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_GROUP; - } - else if (currentParcelBlock.LandData.SalePrice > 0 && - (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || - currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) - { - //Sale type - tempByte = (byte)LandChannel.LAND_TYPE_IS_FOR_SALE; - } - else if (currentParcelBlock.LandData.OwnerID == UUID.Zero) - { - //Public type - tempByte = (byte)LandChannel.LAND_TYPE_PUBLIC; // this does nothing, its zero - } - // LAND_TYPE_IS_BEING_AUCTIONED still unsuported - else - { - //Other Flag - tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_OTHER; - } + //Owner Flag + curByte = LandChannel.LAND_TYPE_OWNED_BY_REQUESTER; + } + else if (currentParcel.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcel.LandData.GroupID)) + { + curByte = LandChannel.LAND_TYPE_OWNED_BY_GROUP; + } + else if (currentParcel.LandData.SalePrice > 0 && + (currentParcel.LandData.AuthBuyerID == UUID.Zero || + currentParcel.LandData.AuthBuyerID == remote_client.AgentId)) + { + //Sale type + curByte = LandChannel.LAND_TYPE_IS_FOR_SALE; + } + else if (currentParcel.LandData.OwnerID == UUID.Zero) + { + //Public type + curByte = LandChannel.LAND_TYPE_PUBLIC; // this does nothing, its zero + } + // LAND_TYPE_IS_BEING_AUCTIONED still unsuported + else + { + //Other + curByte = LandChannel.LAND_TYPE_OWNED_BY_OTHER; + } - // now flags - // border control + // now flags + // local sound + if ((currentParcel.LandData.Flags & (uint)ParcelFlags.SoundLocal) != 0) + curByte |= (byte)LandChannel.LAND_FLAG_LOCALSOUND; - ILandObject westParcel = null; - ILandObject southParcel = null; - if (x > 0) + // hide avatars + if (!currentParcel.LandData.SeeAVs) + curByte |= (byte)LandChannel.LAND_FLAG_HIDEAVATARS; + + // border flags for current + if (y == 0) + { + curByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH; + tmpByte = curByte; + } + else + { + tmpByte = curByte; + southID = GetLandObjectIDinLandUnits(x, (y - 1)); + if (southID >= 0 && southID != curID) + tmpByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH; + } + + tmpByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST; + byteArray[byteArrayCount] = tmpByte; + byteArrayCount++; + + if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) + { + remote_client.SendLandParcelOverlay(byteArray, sequenceID); + byteArrayCount = 0; + sequenceID++; + byteArray = new byte[LAND_BLOCKS_PER_PACKET]; + } + // keep adding while on same parcel, checking south border + if (y == 0) + { + // all have south border and that is already on curByte + while (++x < sx && GetLandObjectIDinLandUnits(x, y) == curID) { - westParcel = GetLandObject((x - 1), y); + byteArray[byteArrayCount] = curByte; + byteArrayCount++; + if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) + { + remote_client.SendLandParcelOverlay(byteArray, sequenceID); + byteArrayCount = 0; + sequenceID++; + byteArray = new byte[LAND_BLOCKS_PER_PACKET]; + } } - if (y > 0) + } + else + { + while (++x < sx && GetLandObjectIDinLandUnits(x, y) == curID) { - southParcel = GetLandObject(x, (y - 1)); - } + // need to check south one by one + southID = GetLandObjectIDinLandUnits(x, (y - 1)); + if (southID >= 0 && southID != curID) + { + tmpByte = curByte; + tmpByte |= LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH; + byteArray[byteArrayCount] = tmpByte; + } + else + byteArray[byteArrayCount] = curByte; - if (x == 0) - { - tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST; - } - else if (westParcel != null && westParcel != currentParcelBlock) - { - tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST; - } - - if (y == 0) - { - tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH; - } - else if (southParcel != null && southParcel != currentParcelBlock) - { - tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH; - } - - // local sound - if ((currentParcelBlock.LandData.Flags & (uint)ParcelFlags.SoundLocal) != 0) - tempByte |= (byte)LandChannel.LAND_FLAG_LOCALSOUND; - - // hide avatars - if (!currentParcelBlock.LandData.SeeAVs) - tempByte |= (byte)LandChannel.LAND_FLAG_HIDEAVATARS; - - - byteArray[byteArrayCount] = tempByte; - byteArrayCount++; - if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) - { - remote_client.SendLandParcelOverlay(byteArray, sequenceID); - byteArrayCount = 0; - sequenceID++; - byteArray = new byte[LAND_BLOCKS_PER_PACKET]; + byteArrayCount++; + if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) + { + remote_client.SendLandParcelOverlay(byteArray, sequenceID); + byteArrayCount = 0; + sequenceID++; + byteArray = new byte[LAND_BLOCKS_PER_PACKET]; + } } } } diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 26500ab3e7..094b0f523b 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -1841,7 +1841,7 @@ namespace OpenSim.Region.CoreModules.World.Land UUID lgid = LandData.GlobalID; m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) { - if(sp.IsNPC || sp.IsLoggingIn || sp.IsDeleted || sp.currentParcelUUID != lgid) + if(sp.IsNPC || sp.IsDeleted || sp.currentParcelUUID != lgid) return; cur += (now - sp.ParcelDwellTickMS); sp.ParcelDwellTickMS = now; diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs index f5aa40a856..66a7df162f 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs @@ -219,9 +219,13 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap lock (media) me = media[face]; - // TODO: Really need a proper copy constructor down in libopenmetaverse if (me != null) - me = MediaEntry.FromOSD(me.GetOSD()); + { + Primitive.TextureEntry te = part.Shape.Textures; + Primitive.TextureEntryFace teFace = te.GetFace((uint)face); + if (teFace != null && teFace.MediaFlags) + me = MediaEntry.FromOSD(me.GetOSD()); + } } // m_log.DebugFormat("[MOAP]: GetMediaEntry for {0} face {1} found {2}", part.Name, face, me); @@ -336,15 +340,40 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap return string.Empty; } - if (null == part.Shape.Media) + if (part.Shape.Media == null) return string.Empty; - ObjectMediaResponse resp = new ObjectMediaResponse(); + MediaEntry[] currentML = part.Shape.Media.ToArray(); + int nentries = currentML.Length; + int nsides = part.GetNumberOfSides(); + if(nentries > nsides) + nentries = nsides; + + Primitive.TextureEntry te = part.Shape.Textures; + bool isnull = true; + + for(int face = 0; face < nentries; ++face) + { + Primitive.TextureEntryFace teFace = te.GetFace((uint)face); + if(!teFace.MediaFlags) + currentML[face] = null; + else + isnull = false; + } + + if(isnull) + { + //remove the damm thing + part.Shape.Media = null; + part.MediaUrl = null; + return string.Empty; + } + + ObjectMediaResponse resp = new ObjectMediaResponse(); resp.PrimID = primId; - lock (part.Shape.Media) - resp.FaceMedia = part.Shape.Media.ToArray(); + resp.FaceMedia = currentML; resp.Version = part.MediaUrl; diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index 99cf121368..f9275730c7 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs @@ -790,7 +790,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap try { using (Bitmap img = (Bitmap)m_imgDecoder.DecodeToImage(asset)) - ret = new warp_Texture(img); + ret = new warp_Texture(img, 8); // reduce textures size to 256x256 } catch (Exception e) { diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index da54c543dd..15294c360e 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -406,16 +406,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap WorkManager.StartThread( process, - string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName), - ThreadPriority.BelowNormal, - true, - false); + string.Format("MapItemRequestThread ({0})", m_scene.RegionInfo.RegionName)); WorkManager.StartThread( MapBlockSendThread, - string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName), - ThreadPriority.BelowNormal, - true, - false); + string.Format("MapBlockSendThread ({0})", m_scene.RegionInfo.RegionName)); } /// @@ -482,7 +476,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap // viewers only ask for green dots to each region now // except at login with regionhandle 0 // possible on some other rare ocasions - // use previus hack of sending all items with the green dots + // use previous hack of sending all items with the green dots bool adultRegion; if (regionhandle == 0) @@ -1189,6 +1183,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap return; GetAndSendBlocksInternal(req.client, req.minX, req.minY, req.maxX, req.maxY, req.flags); + Watchdog.UpdateThread(); } thisRunData.Clear(); diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs index 1b690bad3f..937756448b 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs @@ -90,6 +90,8 @@ namespace OpenSim.Region.Framework.Interfaces void AgentArrivedAtDestination(UUID agent); void EnableChildAgents(ScenePresence agent); + void CheckChildAgents(ScenePresence agent); + void CloseOldChildAgents(ScenePresence agent); void EnableChildAgent(ScenePresence agent, GridRegion region); diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 0c080d22df..299509100f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -153,10 +153,23 @@ namespace OpenSim.Region.Framework.Scenes /// public void RequestPrim(uint primLocalID, IClientAPI remoteClient) { - SceneObjectGroup sog = GetGroupByPrim(primLocalID); + SceneObjectPart part = GetSceneObjectPart(primLocalID); + if (part != null) + { + SceneObjectGroup sog = part.ParentGroup; + if(!sog.IsDeleted) + { + PrimUpdateFlags update = PrimUpdateFlags.FullUpdate; + if (sog.RootPart.Shape.MeshFlagEntry) + update = PrimUpdateFlags.FullUpdatewithAnim; + part.SendUpdate(remoteClient, update); + } + } - if (sog != null) - sog.SendFullAnimUpdateToClient(remoteClient); + //SceneObjectGroup sog = GetGroupByPrim(primLocalID); + + //if (sog != null) + //sog.SendFullAnimUpdateToClient(remoteClient); } /// diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 7668a87511..073d11f206 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -170,8 +170,6 @@ namespace OpenSim.Region.Framework.Scenes } private bool m_scripts_enabled; - public SynchronizeSceneHandler SynchronizeScene; - public bool ClampNegativeZ { get { return m_clampNegativeZ; } @@ -277,6 +275,12 @@ namespace OpenSim.Region.Framework.Scenes get { return m_maxRegionViewDistance; } } + protected float m_minRegionViewDistance = 96f; + public float MinRegionViewDistance + { + get { return m_minRegionViewDistance; } + } + private List m_AllowedViewers = new List(); private List m_BannedViewers = new List(); @@ -922,6 +926,7 @@ namespace OpenSim.Region.Framework.Scenes m_defaultDrawDistance = startupConfig.GetFloat("DefaultDrawDistance", m_defaultDrawDistance); m_maxDrawDistance = startupConfig.GetFloat("MaxDrawDistance", m_maxDrawDistance); m_maxRegionViewDistance = startupConfig.GetFloat("MaxRegionsViewDistance", m_maxRegionViewDistance); + m_minRegionViewDistance = startupConfig.GetFloat("MinRegionsViewDistance", m_minRegionViewDistance); // old versions compatibility LegacySitOffsets = startupConfig.GetBoolean("LegacySitOffsets", LegacySitOffsets); @@ -932,6 +937,11 @@ namespace OpenSim.Region.Framework.Scenes if (m_maxRegionViewDistance > m_maxDrawDistance) m_maxRegionViewDistance = m_maxDrawDistance; + if(m_minRegionViewDistance < 96f) + m_minRegionViewDistance = 96f; + if(m_minRegionViewDistance > m_maxRegionViewDistance) + m_minRegionViewDistance = m_maxRegionViewDistance; + UseBackup = startupConfig.GetBoolean("UseSceneBackup", UseBackup); if (!UseBackup) m_log.InfoFormat("[SCENE]: Backup has been disabled for {0}", RegionInfo.RegionName); @@ -1006,11 +1016,9 @@ namespace OpenSim.Region.Framework.Scenes m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete); m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); - m_dontPersistBefore = - startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE); + m_dontPersistBefore = startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE); m_dontPersistBefore *= 10000000; - m_persistAfter = - startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE); + m_persistAfter = startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE); m_persistAfter *= 10000000; m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); @@ -1290,7 +1298,6 @@ namespace OpenSim.Region.Framework.Scenes { if (RegionInfo.RegionHandle != otherRegion.RegionHandle) { - if (isNeighborRegion(otherRegion)) { // Let the grid service module know, so this can be cached @@ -1300,9 +1307,6 @@ namespace OpenSim.Region.Framework.Scenes { ForEachRootScenePresence(delegate(ScenePresence agent) { - //agent.ControllingClient.new - //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo()); - List old = new List(); old.Add(otherRegion.RegionHandle); agent.DropOldNeighbours(old); @@ -1328,7 +1332,7 @@ namespace OpenSim.Region.Framework.Scenes public bool isNeighborRegion(GridRegion otherRegion) { - int tmp = otherRegion.RegionLocX - (int)RegionInfo.WorldLocX; ; + int tmp = otherRegion.RegionLocX - (int)RegionInfo.WorldLocX; if (tmp < -otherRegion.RegionSizeX && tmp > RegionInfo.RegionSizeX) return false; @@ -1695,9 +1699,6 @@ namespace OpenSim.Region.Framework.Scenes { if (PhysicsEnabled) physicsFPS = m_sceneGraph.UpdatePhysics(FrameTime); - - if (SynchronizeScene != null) - SynchronizeScene(this); } tmpMS2 = Util.GetTimeStampMS(); @@ -1775,30 +1776,6 @@ namespace OpenSim.Region.Framework.Scenes // Region ready should always be set Ready = true; - - - IConfig restartConfig = m_config.Configs["RestartModule"]; - if (restartConfig != null) - { - string markerPath = restartConfig.GetString("MarkerPath", String.Empty); - - if (markerPath != String.Empty) - { - string path = Path.Combine(markerPath, RegionInfo.RegionID.ToString() + ".ready"); - try - { - string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); - FileStream fs = File.Create(path); - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - Byte[] buf = enc.GetBytes(pidstring); - fs.Write(buf, 0, buf.Length); - fs.Close(); - } - catch (Exception) - { - } - } - } } else { @@ -4818,6 +4795,20 @@ Label_GroupsDone: return true; } + + /// + /// Tries to teleport agent within region. + /// + /// + /// + /// + /// + public void RequestLocalTeleport(ScenePresence sp, Vector3 position, Vector3 vel, + Vector3 lookat, int flags) + { + sp.LocalTeleport(position, vel, lookat, flags); + } + /// /// Tries to teleport agent to another region. /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 7d5bbbf0a0..c0bafc55ff 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -119,6 +119,21 @@ namespace OpenSim.Region.Framework.Scenes // private PrimCountTaintedDelegate handlerPrimCountTainted = null; + public bool IsViewerCachable + { + get + { + // needs more exclusion ? + return(Backup && !IsTemporary && !inTransit && !IsSelected && !UsesPhysics && !IsAttachmentCheckFull() && + !RootPart.Shape.MeshFlagEntry && // animations are not sent correctly for now + RootPart.KeyframeMotion == null && + (DateTime.UtcNow.Ticks - timeLastChanged > 36000000000) && //36000000000 is one hour + RootPart.Velocity.LengthSquared() < 1e8f && // should not be needed + RootPart.Acceleration.LengthSquared() < 1e4f // should not be needed + ); + } + } + /// /// Signal whether the non-inventory attributes of any prims in the group have changed /// since the group's last persistent backup @@ -128,7 +143,8 @@ namespace OpenSim.Region.Framework.Scenes private long timeLastChanged = 0; private long m_maxPersistTime = 0; private long m_minPersistTime = 0; -// private Random m_rand; + + public int PseudoCRC; /// /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage @@ -145,40 +161,26 @@ namespace OpenSim.Region.Framework.Scenes { if (value) { - if (Backup) - { m_scene.SceneGraph.FireChangeBackup(this); - } + + PseudoCRC = (int)(DateTime.UtcNow.Ticks); ; timeLastChanged = DateTime.UtcNow.Ticks; if (!m_hasGroupChanged) - timeFirstChanged = DateTime.UtcNow.Ticks; + timeFirstChanged = timeLastChanged; if (m_rootPart != null && m_scene != null) { -/* - if (m_rand == null) - { - byte[] val = new byte[16]; - m_rootPart.UUID.ToBytes(val, 0); - m_rand = new Random(BitConverter.ToInt32(val, 0)); - } - */ if (m_scene.GetRootAgentCount() == 0) { //If the region is empty, this change has been made by an automated process //and thus we delay the persist time by a random amount between 1.5 and 2.5. -// float factor = 1.5f + (float)(m_rand.NextDouble()); float factor = 2.0f; - m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor); - m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor); + m_maxPersistTime = (long)(m_scene.m_persistAfter * factor); + m_minPersistTime = (long)(m_scene.m_dontPersistBefore * factor); } else { - //If the region is not empty, we want to obey the minimum and maximum persist times - //but add a random factor so we stagger the object persistance a little -// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5 -// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0 m_maxPersistTime = m_scene.m_persistAfter; m_minPersistTime = m_scene.m_dontPersistBefore; } @@ -768,9 +770,9 @@ namespace OpenSim.Region.Framework.Scenes } if(av.IsNPC) - av.crossingFlags = 0; + av.m_crossingFlags = 0; else - av.crossingFlags = cflags; + av.m_crossingFlags = cflags; av.PrevSitOffset = av.OffsetPosition; av.ParentID = 0; @@ -819,7 +821,7 @@ namespace OpenSim.Region.Framework.Scenes if(entityTransfer.CrossAgentCreateFarChild(av,destination, newpos, ctx)) crossedfar = true; else - av.crossingFlags = 0; + av.m_crossingFlags = 0; } if(crossedfar) @@ -832,7 +834,7 @@ namespace OpenSim.Region.Framework.Scenes av.IsInTransit = true; m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val); - if(av.crossingFlags > 0) + if(av.m_crossingFlags > 0) entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, false, ctx); if (av.IsChildAgent) @@ -847,7 +849,7 @@ namespace OpenSim.Region.Framework.Scenes av.ParentPart = null; // In any case av.IsInTransit = false; - av.crossingFlags = 0; + av.m_crossingFlags = 0; m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname); } else @@ -863,7 +865,7 @@ namespace OpenSim.Region.Framework.Scenes oldp.X = Util.Clamp(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f); oldp.Y = Util.Clamp(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f); av.AbsolutePosition = oldp; - av.crossingFlags = 0; + av.m_crossingFlags = 0; av.sitAnimation = "SIT"; av.IsInTransit = false; if(av.Animator!= null) @@ -924,7 +926,7 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence av = avinfo.av; av.ParentUUID = UUID.Zero; av.ParentID = avinfo.ParentID; - av.crossingFlags = 0; + av.m_crossingFlags = 0; } } avsToCross.Clear(); @@ -1330,6 +1332,7 @@ namespace OpenSim.Region.Framework.Scenes public SceneObjectGroup() { m_lastCollisionSoundMS = Util.GetTimeStampMS() + 1000.0; + PseudoCRC = (int)(DateTime.UtcNow.Ticks); } /// @@ -2441,6 +2444,21 @@ namespace OpenSim.Region.Framework.Scenes } } + public void SendUpdateProbes(IClientAPI remoteClient) + { + PrimUpdateFlags update = PrimUpdateFlags.UpdateProbe; + + RootPart.SendUpdate(remoteClient, update); + + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part != RootPart) + part.SendUpdate(remoteClient, update); + } + } + #region Copying /// @@ -2516,6 +2534,7 @@ namespace OpenSim.Region.Framework.Scenes } dupe.InvalidatePartsLinkMaps(); + dupe.PseudoCRC = (int)(DateTime.UtcNow.Ticks); m_dupeInProgress = false; return dupe; } @@ -2769,6 +2788,7 @@ namespace OpenSim.Region.Framework.Scenes } } + PseudoCRC = (int)(DateTime.UtcNow.Ticks); rpart.ScheduleFullUpdate(); } @@ -2808,6 +2828,7 @@ namespace OpenSim.Region.Framework.Scenes part.ResetIDs(part.LinkNum); // Don't change link nums m_parts.Add(part.UUID, part); } + PseudoCRC = (int)(DateTime.UtcNow.Ticks); } } @@ -3117,7 +3138,6 @@ namespace OpenSim.Region.Framework.Scenes } } - // 'linkPart' == the root of the group being linked into this group SceneObjectPart linkPart = objectGroup.m_rootPart; @@ -3160,7 +3180,6 @@ namespace OpenSim.Region.Framework.Scenes axPos *= Quaternion.Conjugate(parentRot); linkPart.OffsetPosition = axPos; - // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. // Now that we know this SOG has at least two SOPs in it, the new root // SOP becomes the first in the linkset. @@ -3193,8 +3212,7 @@ namespace OpenSim.Region.Framework.Scenes linkPart.CreateSelected = true; - // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now - linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); + linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive || RootPart.VolumeDetectActive, true); // If the added SOP is physical, also tell the physics engine about the link relationship. if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 312ce26e4a..5e2204e5fc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -312,7 +312,6 @@ namespace OpenSim.Region.Framework.Scenes private Quaternion m_sitTargetOrientation = Quaternion.Identity; private Vector3 m_sitTargetPosition; private string m_sitAnimation = "SIT"; - private bool m_occupied; // KF if any av is sitting on this prim private string m_text = String.Empty; private string m_touchName = String.Empty; private UndoRedoState m_UndoRedo = null; @@ -1001,7 +1000,7 @@ namespace OpenSim.Region.Framework.Scenes get { PhysicsActor actor = PhysActor; - if (actor != null) + if (actor != null && actor.IsPhysical) { m_acceleration = actor.Acceleration; } @@ -1038,8 +1037,8 @@ namespace OpenSim.Region.Framework.Scenes { get { - if (m_text.Length > 256) // yes > 254 - return m_text.Substring(0, 256); + if (m_text.Length > 254) + return m_text.Substring(0, 254); return m_text; } set { m_text = value; } @@ -1179,9 +1178,10 @@ namespace OpenSim.Region.Framework.Scenes set { + string old = m_mediaUrl; m_mediaUrl = value; - if (ParentGroup != null) + if (ParentGroup != null && old != m_mediaUrl) ParentGroup.HasGroupChanged = true; } } @@ -1385,13 +1385,6 @@ namespace OpenSim.Region.Framework.Scenes } } - [XmlIgnore] - public bool IsOccupied // KF If an av is sittingon this prim - { - get { return m_occupied; } - set { m_occupied = value; } - } - /// /// ID of the avatar that is sat on us if we have a sit target. If there is no such avatar then is UUID.Zero /// @@ -2338,10 +2331,7 @@ namespace OpenSim.Region.Framework.Scenes { ParentGroup.Scene.RemovePhysicalPrim(1); - Velocity = new Vector3(0, 0, 0); - Acceleration = new Vector3(0, 0, 0); - AngularVelocity = new Vector3(0, 0, 0); - APIDActive = false; + Stop(); if (pa.Phantom && !VolumeDetectActive) { @@ -2475,13 +2465,10 @@ namespace OpenSim.Region.Framework.Scenes public uint GetEffectiveObjectFlags() { - // Commenting this section of code out since it doesn't actually do anything, as enums are handled by - // value rather than reference -// PrimFlags f = _flags; -// if (m_parentGroup == null || m_parentGroup.RootPart == this) -// f &= ~(PrimFlags.Touch | PrimFlags.Money); - - return (uint)Flags | (uint)LocalFlags; + uint eff = (uint)Flags | (uint)LocalFlags; + if(m_inventory == null || m_inventory.Count == 0) + eff |= (uint)PrimFlags.InventoryEmpty; + return eff; } // some of this lines need be moved to other place later @@ -3896,15 +3883,15 @@ namespace OpenSim.Region.Framework.Scenes { if (Shape.SculptEntry && !ignoreSculpt) return PrimType.SCULPT; - - if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.Square) + ProfileShape ps = (ProfileShape)(Shape.ProfileCurve & 0x07); + if (ps == ProfileShape.Square) { if (Shape.PathCurve == (byte)Extrusion.Straight) return PrimType.BOX; else if (Shape.PathCurve == (byte)Extrusion.Curve1) return PrimType.TUBE; } - else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) + else if (ps == ProfileShape.Circle) { if (Shape.PathCurve == (byte)Extrusion.Straight || Shape.PathCurve == (byte)Extrusion.Flexible) return PrimType.CYLINDER; @@ -3912,12 +3899,12 @@ namespace OpenSim.Region.Framework.Scenes else if (Shape.PathCurve == (byte)Extrusion.Curve1) return PrimType.TORUS; } - else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) + else if (ps == ProfileShape.HalfCircle) { if (Shape.PathCurve == (byte)Extrusion.Curve1 || Shape.PathCurve == (byte)Extrusion.Curve2) return PrimType.SPHERE; } - else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) + else if (ps == ProfileShape.EquilateralTriangle) { if (Shape.PathCurve == (byte)Extrusion.Straight || Shape.PathCurve == (byte)Extrusion.Flexible) return PrimType.PRISM; @@ -4004,9 +3991,10 @@ namespace OpenSim.Region.Framework.Scenes /// public void SetText(string text) { - Text = text; + string oldtext = m_text; + m_text = text; - if (ParentGroup != null) + if (ParentGroup != null && oldtext != text) { ParentGroup.HasGroupChanged = true; ScheduleFullUpdate(); @@ -4021,11 +4009,18 @@ namespace OpenSim.Region.Framework.Scenes /// public void SetText(string text, Vector3 color, double alpha) { + Color oldcolor = Color; + string oldtext = m_text; Color = Color.FromArgb((int) (alpha*0xff), (int) (color.X*0xff), (int) (color.Y*0xff), (int) (color.Z*0xff)); - SetText(text); + m_text = text; + if(ParentGroup != null && (oldcolor != Color || oldtext != m_text)) + { + ParentGroup.HasGroupChanged = true; + ScheduleFullUpdate(); + } } public void StoreUndoState(ObjectChangeType change) @@ -4722,14 +4717,13 @@ namespace OpenSim.Region.Framework.Scenes if ((SetPhantom && !UsePhysics && !SetVD) || ParentGroup.IsAttachment || PhysicsShapeType == (byte)PhysShapeType.none || (Shape.PathCurve == (byte)Extrusion.Flexible)) { + Stop(); if (pa != null) { if(wasUsingPhysics) ParentGroup.Scene.RemovePhysicalPrim(1); RemoveFromPhysics(); } - - Stop(); } else @@ -5130,7 +5124,13 @@ namespace OpenSim.Region.Framework.Scenes if (changeFlags == 0) return; - m_shape.TextureEntry = newTex.GetBytes(9); + // we do need better compacter do just the trivial case + if(nsides == 1 && newTex.FaceTextures[0] != null) + { + newTex.DefaultTexture = newTex.GetFace(0); + newTex.FaceTextures[0] = null; + } + m_shape.TextureEntry = newTex.GetBytes(nsides); TriggerScriptChangedEvent(changeFlags); ParentGroup.HasGroupChanged = true; ScheduleUpdate(PrimUpdateFlags.Textures); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 1c5d23d9b4..f569d21af5 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -99,6 +99,8 @@ namespace OpenSim.Region.Framework.Scenes public bool IsViewerUIGod { get; set; } public bool IsGod { get; set; } + private bool m_gotRegionHandShake = false; + private PresenceType m_presenceType; public PresenceType PresenceType { @@ -163,6 +165,7 @@ namespace OpenSim.Region.Framework.Scenes public static readonly float MOVEMENT = .25f; public static readonly float SIGNIFICANT_MOVEMENT = 16.0f; public static readonly float CHILDUPDATES_MOVEMENT = 100.0f; + public static readonly float CHILDAGENTSCHECK_MOVEMENT = 1024f; // 32m public static readonly float CHILDUPDATES_TIME = 2000f; // min time between child updates (ms) private UUID m_previusParcelUUID = UUID.Zero; @@ -288,7 +291,7 @@ namespace OpenSim.Region.Framework.Scenes private Quaternion m_lastRotation; private Vector3 m_lastVelocity; private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f); - private bool SentInitialData = false; + private int NeedInitialData = -1; private int m_userFlags; public int UserFlags @@ -339,8 +342,10 @@ namespace OpenSim.Region.Framework.Scenes private int m_lastChildUpdatesTime; private int m_lastChildAgentUpdateGodLevel; private float m_lastChildAgentUpdateDrawDistance; + private float m_lastRegionsDrawDistance; private Vector3 m_lastChildAgentUpdatePosition; -// private Vector3 m_lastChildAgentUpdateCamPosition; + private Vector3 m_lastChildAgentCheckPosition; + // private Vector3 m_lastChildAgentUpdateCamPosition; private Vector3 m_lastCameraRayCastCam; private Vector3 m_lastCameraRayCastPos; @@ -457,9 +462,10 @@ namespace OpenSim.Region.Framework.Scenes #region For teleports and crossings callbacks /// - /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address. + /// the destination simulator sends ReleaseAgent to this address, for very long range tps, HG. /// - private string m_callbackURI; + private string m_callbackURI; // to remove with v1 support + private string m_newCallbackURI; /// /// Records the region from which this presence originated, if not from login. @@ -595,9 +601,9 @@ namespace OpenSim.Region.Framework.Scenes public string Firstname { get; private set; } public string Lastname { get; private set; } - public bool haveGroupInformation; - public bool gotCrossUpdate; - public byte crossingFlags; + public bool m_haveGroupInformation; + public bool m_gotCrossUpdate; + public byte m_crossingFlags; public string Grouptitle { @@ -624,7 +630,7 @@ namespace OpenSim.Region.Framework.Scenes { get { - return Util.Clamp(m_drawDistance, 32f, m_scene.MaxRegionViewDistance); + return Util.Clamp(m_drawDistance + 64f, m_scene.MinRegionViewDistance, m_scene.MaxRegionViewDistance); } } @@ -880,7 +886,6 @@ namespace OpenSim.Region.Framework.Scenes } public bool IsChildAgent { get; set; } - public bool IsLoggingIn { get; set; } /// /// If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero. @@ -1073,12 +1078,18 @@ namespace OpenSim.Region.Framework.Scenes AttachmentsSyncLock = new Object(); AllowMovement = true; IsChildAgent = true; - IsLoggingIn = false; m_sendCoarseLocationsMethod = SendCoarseLocationsDefault; Animator = new ScenePresenceAnimator(this); Overrides = new MovementAnimationOverrides(); PresenceType = type; - DrawDistance = world.DefaultDrawDistance; + m_drawDistance = client.StartFar; + if(m_drawDistance > 32) + { + if(m_drawDistance > world.MaxDrawDistance) + m_drawDistance = world.MaxDrawDistance; + } + else + m_drawDistance = world.DefaultDrawDistance; RegionHandle = world.RegionInfo.RegionHandle; ControllingClient = client; Firstname = ControllingClient.FirstName; @@ -1212,7 +1223,9 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.OnForceReleaseControls += HandleForceReleaseControls; ControllingClient.OnAutoPilotGo += MoveToTargetHandle; ControllingClient.OnUpdateThrottles += RaiseUpdateThrottles; -// ControllingClient.OnAgentFOV += HandleAgentFOV; + ControllingClient.OnRegionHandShakeReply += RegionHandShakeReply; + + // ControllingClient.OnAgentFOV += HandleAgentFOV; // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange); // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement); @@ -1232,7 +1245,9 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.OnForceReleaseControls -= HandleForceReleaseControls; ControllingClient.OnAutoPilotGo -= MoveToTargetHandle; ControllingClient.OnUpdateThrottles -= RaiseUpdateThrottles; -// ControllingClient.OnAgentFOV += HandleAgentFOV; + ControllingClient.OnRegionHandShakeReply -= RegionHandShakeReply; + + // ControllingClient.OnAgentFOV += HandleAgentFOV; } private void SetDirectionVectors() @@ -1302,13 +1317,12 @@ namespace OpenSim.Region.Framework.Scenes ParentPart = null; PrevSitOffset = Vector3.Zero; HandleForceReleaseControls(ControllingClient, UUID); // needs testing - IsLoggingIn = false; } else { part.AddSittingAvatar(this); // if not actually on the target invalidate it - if(gotCrossUpdate && (crossingFlags & 0x04) == 0) + if(m_gotCrossUpdate && (m_crossingFlags & 0x04) == 0) part.SitTargetAvatar = UUID.Zero; ParentID = part.LocalId; @@ -1326,10 +1340,6 @@ namespace OpenSim.Region.Framework.Scenes } ParentUUID = UUID.Zero; } - else - { - IsLoggingIn = false; - } IsChildAgent = false; } @@ -1594,9 +1604,9 @@ namespace OpenSim.Region.Framework.Scenes public void MakeChildAgent(ulong newRegionHandle) { m_updateAgentReceivedAfterTransferEvent.Reset(); - haveGroupInformation = false; - gotCrossUpdate = false; - crossingFlags = 0; + m_haveGroupInformation = false; + m_gotCrossUpdate = false; + m_crossingFlags = 0; m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; RegionHandle = newRegionHandle; @@ -1641,10 +1651,17 @@ namespace OpenSim.Region.Framework.Scenes m_previusParcelUUID = UUID.Zero; m_currentParcelHide = false; m_currentParcelUUID = UUID.Zero; - // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into - + CollisionPlane = Vector4.UnitW; + // we need to kill this on agents that do not see the new region + m_scene.ForEachRootScenePresence(delegate(ScenePresence p) + { + if (!p.knowsNeighbourRegion(newRegionHandle)) + { + SendKillTo(p); + } + }); m_scene.EventManager.TriggerOnMakeChildAgent(this); } @@ -1671,10 +1688,6 @@ namespace OpenSim.Region.Framework.Scenes // } } - /// - /// Do not call this directly. Call Scene.RequestTeleportLocation() instead. - /// - /// public void Teleport(Vector3 pos) { TeleportWithMomentum(pos, Vector3.Zero); @@ -1719,37 +1732,95 @@ namespace OpenSim.Region.Framework.Scenes SendTerseUpdateToAllClients(); } - public void avnLocalTeleport(Vector3 newpos, Vector3? newvel, bool rotateToVelXY) + public void LocalTeleport(Vector3 newpos, Vector3 newvel, Vector3 newlookat, int flags) { - if(!CheckLocalTPLandingPoint(ref newpos)) - return; - - AbsolutePosition = newpos; - - if (newvel.HasValue) + if (newpos.X <= 0) { - if ((Vector3)newvel == Vector3.Zero) - { - if (PhysicsActor != null) - PhysicsActor.SetMomentum(Vector3.Zero); - m_velocity = Vector3.Zero; - } - else - { - if (PhysicsActor != null) - PhysicsActor.SetMomentum((Vector3)newvel); - m_velocity = (Vector3)newvel; - - if (rotateToVelXY) - { - Vector3 lookAt = (Vector3)newvel; - lookAt.Z = 0; - lookAt.Normalize(); - ControllingClient.SendLocalTeleport(newpos, lookAt, (uint)TeleportFlags.ViaLocation); - return; - } - } + newpos.X = 0.1f; + if (newvel.X < 0) + newvel.X = 0; } + else if (newpos.X >= Scene.RegionInfo.RegionSizeX) + { + newpos.X = Scene.RegionInfo.RegionSizeX - 0.1f; + if (newvel.X > 0) + newvel.X = 0; + } + + if (newpos.Y <= 0) + { + newpos.Y = 0.1f; + if (newvel.Y < 0) + newvel.Y = 0; + } + else if (newpos.Y >= Scene.RegionInfo.RegionSizeY) + { + newpos.Y = Scene.RegionInfo.RegionSizeY - 0.1f; + if (newvel.Y > 0) + newvel.Y = 0; + } + + string reason; + if (!m_scene.TestLandRestrictions(UUID, out reason, ref newpos.X, ref newpos.Y)) + return ; + + if (IsSatOnObject) + StandUp(); + + float localHalfAVHeight = 0.8f; + if (Appearance != null) + localHalfAVHeight = Appearance.AvatarHeight * 0.5f; + + float posZLimit = (float)Scene.Heightmap[(int)newpos.X, (int)newpos.Y]; + posZLimit += localHalfAVHeight + 0.1f; + if (newpos.Z < posZLimit) + newpos.Z = posZLimit; + + if((flags & 0x1e) != 0) + { + if ((flags & 8) != 0) + Flying = true; + else if ((flags & 16) != 0) + Flying = false; + + uint tpflags = (uint)TeleportFlags.ViaLocation; + if(Flying) + tpflags |= (uint)TeleportFlags.IsFlying; + + Vector3 lookat = Lookat; + + if ((flags & 2) != 0) + { + newlookat.Z = 0; + newlookat.Normalize(); + if (Math.Abs(newlookat.X) > 0.001 || Math.Abs(newlookat.Y) > 0.001) + lookat = newlookat; + } + else if((flags & 4) != 0) + { + if((flags & 1) != 0) + newlookat = newvel; + else + newlookat = m_velocity; + newlookat.Z = 0; + newlookat.Normalize(); + if (Math.Abs(newlookat.X) > 0.001 || Math.Abs(newlookat.Y) > 0.001) + lookat = newlookat; + } + + AbsolutePosition = newpos; + ControllingClient.SendLocalTeleport(newpos, lookat, tpflags); + } + else + AbsolutePosition = newpos; + + if ((flags & 1) != 0) + { + if (PhysicsActor != null) + PhysicsActor.SetMomentum(newvel); + m_velocity = newvel; + } + SendTerseUpdateToAllClients(); } @@ -2126,277 +2197,233 @@ namespace OpenSim.Region.Framework.Scenes return; } + if(IsChildAgent) + { + return; // how? + } //m_log.DebugFormat("[CompleteMovement] MakeRootAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - if(!haveGroupInformation && !IsChildAgent && !IsNPC) + if (!IsNPC) { - IGroupsModule gm = m_scene.RequestModuleInterface(); - if (gm != null) - Grouptitle = gm.GetGroupTitle(m_uuid); - - //m_log.DebugFormat("[CompleteMovement] Missing Grouptitle: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - - InventoryFolderBase cof = m_scene.InventoryService.GetFolderForType(client.AgentId, (FolderType)46); - if (cof == null) - COF = UUID.Zero; - else - COF = cof.ID; - - m_log.DebugFormat("[CompleteMovement]: Missing COF for {0} is {1}", client.AgentId, COF); - } - - if (!string.IsNullOrEmpty(m_callbackURI)) - { - // We cannot sleep here since this would hold up the inbound packet processing thread, as - // CompleteMovement() is executed synchronously. However, it might be better to delay the release - // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete - // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this - // region as the current region, meaning that a close sent before then will fail the teleport. - // System.Threading.Thread.Sleep(2000); - - m_log.DebugFormat( - "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", - client.Name, client.AgentId, m_callbackURI); - - UUID originID; - - lock (m_originRegionIDAccessLock) - originID = m_originRegionID; - - Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI); - m_callbackURI = null; - //m_log.DebugFormat("[CompleteMovement] ReleaseAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - } -// else -// { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", -// client.Name, client.AgentId, m_scene.RegionInfo.RegionName); -// } - - - // Tell the client that we're totally ready - ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); - //m_log.DebugFormat("[CompleteMovement] MoveAgentIntoRegion: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - - bool isHGTP = (m_teleportFlags & TeleportFlags.ViaHGLogin) != 0; - - int delayctnr = Util.EnvironmentTickCount(); - - if (!IsChildAgent) - { - if( ParentPart != null && !IsNPC && (crossingFlags & 0x08) != 0) + if (!m_haveGroupInformation) { - ParentPart.ParentGroup.SendFullAnimUpdateToClient(ControllingClient); + IGroupsModule gm = m_scene.RequestModuleInterface(); + if (gm != null) + Grouptitle = gm.GetGroupTitle(m_uuid); + + //m_log.DebugFormat("[CompleteMovement] Missing Grouptitle: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + InventoryFolderBase cof = m_scene.InventoryService.GetFolderForType(client.AgentId, (FolderType)46); + if (cof == null) + COF = UUID.Zero; + else + COF = cof.ID; + + m_log.DebugFormat("[CompleteMovement]: Missing COF for {0} is {1}", client.AgentId, COF); } - - // verify baked textures and cache - bool cachedbaked = false; - - if (IsNPC) - cachedbaked = true; - else - { - if (m_scene.AvatarFactory != null && !isHGTP) - cachedbaked = m_scene.AvatarFactory.ValidateBakedTextureCache(this); - - // not sure we need this - if (!cachedbaked) - { - if (m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(UUID); - } - } - //m_log.DebugFormat("[CompleteMovement] Baked check: {0}ms", Util.EnvironmentTickCountSubtract(ts)); } - if(m_teleportFlags > 0) - { - gotCrossUpdate = false; // sanity check - if(Util.EnvironmentTickCountSubtract(delayctnr)< 500) - Thread.Sleep(500); // let viewers catch us - } + if (m_teleportFlags > 0) + m_gotCrossUpdate = false; // sanity check - if(!gotCrossUpdate) + if (!m_gotCrossUpdate) RotateToLookAt(look); - // HG - if(isHGTP) - { -// ControllingClient.SendNameReply(m_uuid, Firstname, Lastname); - m_log.DebugFormat("[CompleteMovement] HG"); - } - m_previusParcelHide = false; m_previusParcelUUID = UUID.Zero; m_currentParcelHide = false; m_currentParcelUUID = UUID.Zero; ParcelDwellTickMS = Util.GetTimeStampMS(); + m_inTransit = false; + + // Tell the client that we're ready to send rest + if (!m_gotCrossUpdate) + { + m_gotRegionHandShake = false; // allow it if not a crossing + ControllingClient.SendRegionHandshake(); + } + + ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); + + bool isHGTP = (m_teleportFlags & TeleportFlags.ViaHGLogin) != 0; + if(!IsNPC) { - GodController.SyncViewerState(); - - // start sending terrain patchs - if (!gotCrossUpdate) - Scene.SendLayerData(ControllingClient); + if( ParentPart != null && (m_crossingFlags & 0x08) != 0) + { + ParentPart.ParentGroup.SendFullAnimUpdateToClient(ControllingClient); + } + + // verify baked textures and cache + if (m_scene.AvatarFactory != null && !isHGTP) + { + if (!m_scene.AvatarFactory.ValidateBakedTextureCache(this)) + m_scene.AvatarFactory.QueueAppearanceSave(UUID); + } } - // send initial land overlay and parcel - ILandChannel landch = m_scene.LandChannel; - if (landch != null) - landch.sendClientInitialLandInfo(client); - if (!IsChildAgent) + if(isHGTP) { - List allpresences = m_scene.GetScenePresences(); +// ControllingClient.SendNameReply(m_uuid, Firstname, Lastname); + m_log.DebugFormat("[CompleteMovement] HG"); + } - // send avatar object to all presences including us, so they cross it into region - // then hide if necessary + if (!IsNPC) + { + GodController.SyncViewerState(); - SendInitialAvatarDataToAllAgents(allpresences); + // start sending terrain patchs + if (!m_gotCrossUpdate) + Scene.SendLayerData(ControllingClient); - // send this look + // send initial land overlay and parcel + ILandChannel landch = m_scene.LandChannel; + if (landch != null) + landch.sendClientInitialLandInfo(client, !m_gotCrossUpdate); + } + + List allpresences = m_scene.GetScenePresences(); + + // send avatar object to all presences including us, so they cross it into region + // then hide if necessary + SendInitialAvatarDataToAllAgents(allpresences); + + // send this look + if (!IsNPC) SendAppearanceToAgent(this); - // send this animations + // send this animations - UUID[] animIDs = null; - int[] animseqs = null; - UUID[] animsobjs = null; + UUID[] animIDs = null; + int[] animseqs = null; + UUID[] animsobjs = null; - if (Animator != null) - Animator.GetArrays(out animIDs, out animseqs, out animsobjs); + if (Animator != null) + Animator.GetArrays(out animIDs, out animseqs, out animsobjs); - bool haveAnims = (animIDs != null && animseqs != null && animsobjs != null); + bool haveAnims = (animIDs != null && animseqs != null && animsobjs != null); - if (haveAnims) - SendAnimPackToAgent(this, animIDs, animseqs, animsobjs); + if (!IsNPC && haveAnims) + SendAnimPackToAgent(this, animIDs, animseqs, animsobjs); - // we should be able to receive updates, etc - // so release them - m_inTransit = false; + // send look and animations to others + // if not cached we send greys + // uncomented if will wait till avatar does baking + //if (cachedbaked) - // send look and animations to others - // if not cached we send greys - // uncomented if will wait till avatar does baking - //if (cachedbaked) + { + foreach (ScenePresence p in allpresences) { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + SendAppearanceToAgentNF(p); + if (haveAnims) + SendAnimPackToAgentNF(p, animIDs, animseqs, animsobjs); + } + } + + // attachments + if (IsNPC || IsRealLogin(m_teleportFlags)) + { + if (Scene.AttachmentsModule != null) + { + if(IsNPC) + { + Util.FireAndForget(x => + { + Scene.AttachmentsModule.RezAttachments(this); + }); + } + else + Scene.AttachmentsModule.RezAttachments(this); + } + } + else + { + if (m_attachments.Count > 0) + { + foreach (SceneObjectGroup sog in m_attachments) + { + sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); + sog.ResumeScripts(); + } + foreach (ScenePresence p in allpresences) { if (p == this) + { + SendAttachmentsToAgentNF(this); continue; + } if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) continue; - SendAppearanceToAgentNF(p); - if (haveAnims) - SendAnimPackToAgentNF(p, animIDs, animseqs, animsobjs); - } - } // greys if - - //m_log.DebugFormat("[CompleteMovement] ValidateAndSendAppearanceAndAgentData: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - - // attachments - if (IsNPC || IsRealLogin(m_teleportFlags)) - { - if (Scene.AttachmentsModule != null) - // Util.FireAndForget( - // o => - // { - - if (!IsNPC) - Scene.AttachmentsModule.RezAttachments(this); - else - Util.FireAndForget(x => - { - Scene.AttachmentsModule.RezAttachments(this); - }); - - // }); - } - else - { - if (m_attachments.Count > 0) - { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); - - foreach (SceneObjectGroup sog in m_attachments) - { - sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); - sog.ResumeScripts(); - } - - foreach (ScenePresence p in allpresences) - { - if (p == this) - { - SendAttachmentsToAgentNF(this); - continue; - } - - if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) - continue; - - SendAttachmentsToAgentNF(p); - } + SendAttachmentsToAgentNF(p); } } + } - //m_log.DebugFormat("[CompleteMovement] attachments: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - if (openChildAgents) + if (!IsNPC) + { + if(m_gotCrossUpdate) { + SendOtherAgentsAvatarFullToMe(); + // Create child agents in neighbouring regions IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); if (m_agentTransfer != null) { m_agentTransfer.EnableChildAgents(this); } + + m_lastChildUpdatesTime = Util.EnvironmentTickCount() + 10000; + m_lastChildAgentUpdatePosition = AbsolutePosition; + m_lastChildAgentCheckPosition = m_lastChildAgentUpdatePosition; + m_lastChildAgentUpdateDrawDistance = DrawDistance; + m_lastRegionsDrawDistance = RegionViewDistance; + + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_childUpdatesBusy = false; // allow them + } - m_lastChildUpdatesTime = Util.EnvironmentTickCount() + 10000; - m_lastChildAgentUpdatePosition = AbsolutePosition; - m_lastChildAgentUpdateDrawDistance = DrawDistance; + // send the rest of the world + //if (m_teleportFlags > 0 || m_currentParcelHide) + //SendInitialDataToMe(); + //SendOtherAgentsAvatarFullToMe(); - m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; - m_childUpdatesBusy = false; // allow them - } + // priority uses avatar position only + // m_reprioritizationLastPosition = AbsolutePosition; + // m_reprioritizationLastDrawDistance = DrawDistance; + // m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it + // m_reprioritizationBusy = false; - //m_log.DebugFormat("[CompleteMovement] openChildAgents: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - - // send the rest of the world - if (m_teleportFlags > 0 && !IsNPC || m_currentParcelHide) - SendInitialDataToMe(); - - // priority uses avatar position only -// m_reprioritizationLastPosition = AbsolutePosition; -// m_reprioritizationLastDrawDistance = DrawDistance; -// m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it -// m_reprioritizationBusy = false; - - //m_log.DebugFormat("[CompleteMovement] SendInitialDataToMe: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - - if (!IsChildAgent && openChildAgents) - { - IFriendsModule friendsModule = m_scene.RequestModuleInterface(); - if (friendsModule != null) + if (openChildAgents) { - if(gotCrossUpdate) - friendsModule.IsNowRoot(this); - else - friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + IFriendsModule friendsModule = m_scene.RequestModuleInterface(); + if (friendsModule != null) + { + if(m_gotCrossUpdate) + friendsModule.IsNowRoot(this); + else + friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + } + //m_log.DebugFormat("[CompleteMovement] friendsModule: {0}ms", Util.EnvironmentTickCountSubtract(ts)); } - //m_log.DebugFormat("[CompleteMovement] friendsModule: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - } } finally { - haveGroupInformation = false; - gotCrossUpdate = false; - crossingFlags = 0; + m_haveGroupInformation = false; + m_gotCrossUpdate = false; + m_crossingFlags = 0; m_inTransit = false; } @@ -3108,10 +3135,14 @@ namespace OpenSim.Region.Framework.Scenes Vector2 regionSize; regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY); - if (pos.X < 0 || pos.X >= regionSize.X - || pos.Y < 0 || pos.Y >= regionSize.Y - || pos.Z < 0) - return; + if (pos.X < 0.5f) + pos.X = 0.5f; + else if (pos.X > regionSize.X - 0.5f) + pos.X = regionSize.X - 0.5f; + if (pos.Y < 0.5f) + pos.Y = 0.5f; + else if (pos.Y > regionSize.Y - 0.5f) + pos.Y = regionSize.Y - 0.5f; float terrainHeight; Scene targetScene = m_scene; @@ -3709,10 +3740,7 @@ namespace OpenSim.Region.Framework.Scenes if (IsChildAgent) return; -// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. sitAnimation = "SIT_GROUND_CONSTRAINED"; -// Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); -// TriggerScenePresenceUpdated(); SitGround = true; RemoveFromPhysicalScene(); @@ -3813,14 +3841,6 @@ namespace OpenSim.Region.Framework.Scenes direc.Z = 0; } - // m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); -/* - lock(m_forceToApplyLock) - { - m_forceToApply = direc; - m_forceToApplyValid = true; - } -*/ TargetVelocity = direc; Animator.UpdateMovementAnimations(); } @@ -3837,15 +3857,21 @@ namespace OpenSim.Region.Framework.Scenes public override void Update() { - if(IsChildAgent || IsDeleted) + if (IsDeleted) + return; + + if (NeedInitialData > 0) + { + SendInitialData(); + return; + } + + if (IsChildAgent || IsInTransit) return; CheckForBorderCrossing(); - if (IsInTransit || IsLoggingIn) - return; - - if(m_movingToTarget) + if (m_movingToTarget) { m_delayedStop = -1; Vector3 control = Vector3.Zero; @@ -4020,29 +4046,95 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations); } - public void SendInitialDataToMe() + public void RegionHandShakeReply (IClientAPI client) { - // Send all scene object to the new client - SentInitialData = true; + if(IsNPC) + return; + + lock (m_completeMovementLock) + { + if(m_gotRegionHandShake) + return; + m_gotRegionHandShake = true; + NeedInitialData = 1; + } + } + + private void SendInitialData() + { + uint flags = ControllingClient.GetViewerCaps(); + if((flags & 0x1000) == 0) // wait for seeds sending + return; + +// lock (m_completeMovementLock) + { + if(NeedInitialData < 0) + return; + + // give some extra time to make sure viewers did process seeds + if(++NeedInitialData < 4) // needs fix if update rate changes on heartbeat + return; + } + + NeedInitialData = -1; + + bool selfappearance = (flags & 4) != 0; + + // this should enqueued on the client processing job to save threads Util.FireAndForget(delegate { - // we created a new ScenePresence (a new child agent) in a fresh region. - // Request info about all the (root) agents in this region - // Note: This won't send data *to* other clients in that region (children don't send) + if(!IsChildAgent) + { + // close v1 sender region obsolete + if (!string.IsNullOrEmpty(m_callbackURI)) + { + m_log.DebugFormat( + "[SCENE PRESENCE({0})]: Releasing {1} {2} with old callback to {3}", + Scene.RegionInfo.RegionName, Name, UUID, m_callbackURI); + + UUID originID; + + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + + Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI); + m_callbackURI = null; + } + // v0.7 close HG sender region + else if (!string.IsNullOrEmpty(m_newCallbackURI)) + { + m_log.DebugFormat( + "[SCENE PRESENCE({0})]: Releasing {1} {2} with callback to {3}", + Scene.RegionInfo.RegionName, Name, UUID, m_newCallbackURI); + + UUID originID; + + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + + Scene.SimulationService.ReleaseAgent(originID, UUID, m_newCallbackURI); + m_newCallbackURI = null; + } + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + { + m_agentTransfer.CloseOldChildAgents(this); + } + } + + m_log.DebugFormat("[SCENE PRESENCE({0})]: SendInitialData for {1}", Scene.RegionInfo.RegionName, UUID); if (m_teleportFlags <= 0) { Scene.SendLayerData(ControllingClient); ILandChannel landch = m_scene.LandChannel; if (landch != null) - { - landch.sendClientInitialLandInfo(ControllingClient); - } + landch.sendClientInitialLandInfo(ControllingClient, true); } SendOtherAgentsAvatarFullToMe(); - if(m_scene.ObjectsCullingByDistance) + if (m_scene.ObjectsCullingByDistance) { m_reprioritizationBusy = true; m_reprioritizationLastPosition = AbsolutePosition; @@ -4051,23 +4143,63 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.ReprioritizeUpdates(); m_reprioritizationLastTime = Util.EnvironmentTickCount(); m_reprioritizationBusy = false; - return; } - - EntityBase[] entities = Scene.Entities.GetEntities(); - foreach (EntityBase e in entities) + else { - if (e != null && e is SceneObjectGroup && !((SceneObjectGroup)e).IsAttachment) - ((SceneObjectGroup)e).SendFullAnimUpdateToClient(ControllingClient); + //bool cacheCulling = (flags & 1) != 0; + bool cacheEmpty = (flags & 2) != 0;; + + EntityBase[] entities = Scene.Entities.GetEntities(); + if(cacheEmpty) + { + foreach (EntityBase e in entities) + { + if (e != null && e is SceneObjectGroup && !((SceneObjectGroup)e).IsAttachment) + ((SceneObjectGroup)e).SendFullAnimUpdateToClient(ControllingClient); + } + } + else + { + foreach (EntityBase e in entities) + { + if (e != null && e is SceneObjectGroup && !((SceneObjectGroup)e).IsAttachment) + { + SceneObjectGroup grp = e as SceneObjectGroup; + if(grp.IsViewerCachable) + grp.SendUpdateProbes(ControllingClient); + else + grp.SendFullAnimUpdateToClient(ControllingClient); + } + } + } + + m_reprioritizationLastPosition = AbsolutePosition; + m_reprioritizationLastDrawDistance = DrawDistance; + m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it + + m_reprioritizationBusy = false; } - m_reprioritizationLastPosition = AbsolutePosition; - m_reprioritizationLastDrawDistance = DrawDistance; - m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it + if (!IsChildAgent) + { + // Create child agents in neighbouring regions + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + { + m_agentTransfer.EnableChildAgents(this); + } - m_reprioritizationBusy = false; + m_lastChildUpdatesTime = Util.EnvironmentTickCount() + 10000; + m_lastChildAgentUpdatePosition = AbsolutePosition; + m_lastChildAgentCheckPosition = m_lastChildAgentUpdatePosition; + m_lastChildAgentUpdateDrawDistance = DrawDistance; + m_lastRegionsDrawDistance = RegionViewDistance; + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_childUpdatesBusy = false; // allow them + } }); + } /// @@ -4131,8 +4263,17 @@ namespace OpenSim.Region.Framework.Scenes { m_lastSize = Appearance.AvatarSize; int count = 0; + SceneObjectPart sitroot = null; + if (ParentID != 0 && ParentPart != null) // we need to send the sitting root prim + { + sitroot = ParentPart.ParentGroup.RootPart; + } foreach (ScenePresence p in presences) { + if (sitroot != null) // we need to send the sitting root prim + { + p.ControllingClient.SendEntityFullUpdateImmediate(ParentPart.ParentGroup.RootPart); + } p.ControllingClient.SendEntityFullUpdateImmediate(this); if (p != this && ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) // either just kill the object @@ -4146,6 +4287,10 @@ namespace OpenSim.Region.Framework.Scenes public void SendInitialAvatarDataToAgent(ScenePresence p) { + if(ParentID != 0 && ParentPart != null) // we need to send the sitting root prim + { + p.ControllingClient.SendEntityFullUpdateImmediate(ParentPart.ParentGroup.RootPart); + } p.ControllingClient.SendEntityFullUpdateImmediate(this); if (p != this && ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) // either just kill the object @@ -4273,12 +4418,6 @@ namespace OpenSim.Region.Framework.Scenes if(IsDeleted || !ControllingClient.IsActive) return; - if(!SentInitialData) - { - SendInitialDataToMe(); - return; - } - if(m_reprioritizationBusy) return; @@ -4339,62 +4478,91 @@ namespace OpenSim.Region.Framework.Scenes m_scene.EventManager.TriggerSignificantClientMovement(this); } + if(IsNPC) + return; + // updates priority recalc checkRePrioritization(); - if(m_childUpdatesBusy) + if(m_childUpdatesBusy || RegionViewDistance == 0) return; - //possible KnownRegionHandles always contains current region and this check is not needed - int minhandles = KnownRegionHandles.Contains(RegionHandle) ? 1 : 0; - if(KnownRegionHandles.Count > minhandles) + int tdiff = Util.EnvironmentTickCountSubtract(m_lastChildUpdatesTime); + if (tdiff < CHILDUPDATES_TIME) + return; + + bool viewchanged = Math.Abs(RegionViewDistance - m_lastRegionsDrawDistance) > 32.0f; + + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + float dx = pos.X - m_lastChildAgentCheckPosition.X; + float dy = pos.Y - m_lastChildAgentCheckPosition.Y; + if ((m_agentTransfer != null) && (viewchanged || ((dx * dx + dy * dy) > CHILDAGENTSCHECK_MOVEMENT))) { - int tdiff = Util.EnvironmentTickCountSubtract(m_lastChildUpdatesTime); - if(tdiff < CHILDUPDATES_TIME) - return; + m_childUpdatesBusy = true; + m_lastChildAgentCheckPosition = pos; + m_lastChildAgentUpdatePosition = pos; + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_lastChildAgentUpdateDrawDistance = DrawDistance; + m_lastRegionsDrawDistance = RegionViewDistance; + // m_lastChildAgentUpdateCamPosition = CameraPosition; - bool doUpdate = false; - if(m_lastChildAgentUpdateGodLevel != GodController.ViwerUIGodLevel) - doUpdate = true; - - if(!doUpdate && Math.Abs(DrawDistance - m_lastChildAgentUpdateDrawDistance) > 32.0f) - doUpdate = true; - - if(!doUpdate) + Util.FireAndForget( + o => + { + m_agentTransfer.EnableChildAgents(this); + m_lastChildUpdatesTime = Util.EnvironmentTickCount(); + m_childUpdatesBusy = false; + }, null, "ScenePresence.CheckChildAgents"); + } + else + { + //possible KnownRegionHandles always contains current region and this check is not needed + int minhandles = KnownRegionHandles.Contains(RegionHandle) ? 1 : 0; + if(KnownRegionHandles.Count > minhandles) { - diff = pos - m_lastChildAgentUpdatePosition; - if (diff.LengthSquared() > CHILDUPDATES_MOVEMENT) + bool doUpdate = false; + if (m_lastChildAgentUpdateGodLevel != GodController.ViwerUIGodLevel) doUpdate = true; - } - if(doUpdate) - { - m_childUpdatesBusy = true; - m_lastChildAgentUpdatePosition = pos; - m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; - m_lastChildAgentUpdateDrawDistance = DrawDistance; -// m_lastChildAgentUpdateCamPosition = CameraPosition; + if (Math.Abs(DrawDistance - m_lastChildAgentUpdateDrawDistance) > 32.0f) + doUpdate = true; - AgentPosition agentpos = new AgentPosition(); - agentpos.AgentID = new UUID(UUID.Guid); - agentpos.SessionID = ControllingClient.SessionId; - agentpos.Size = Appearance.AvatarSize; - agentpos.Center = CameraPosition; - agentpos.Far = DrawDistance; - agentpos.Position = AbsolutePosition; - agentpos.Velocity = Velocity; - agentpos.RegionHandle = RegionHandle; - agentpos.GodData = GodController.State(); - agentpos.Throttles = ControllingClient.GetThrottlesPacked(1); + if(!doUpdate) + { + diff = pos - m_lastChildAgentUpdatePosition; + if (diff.LengthSquared() > CHILDUPDATES_MOVEMENT) + doUpdate = true; + } - // Let's get this out of the update loop - Util.FireAndForget( - o => - { - m_scene.SendOutChildAgentUpdates(agentpos, this); - m_lastChildUpdatesTime = Util.EnvironmentTickCount(); - m_childUpdatesBusy = false; - }, null, "ScenePresence.SendOutChildAgentUpdates"); + if (doUpdate) + { + m_childUpdatesBusy = true; + m_lastChildAgentUpdatePosition = pos; + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_lastChildAgentUpdateDrawDistance = DrawDistance; + // m_lastChildAgentUpdateCamPosition = CameraPosition; + + AgentPosition agentpos = new AgentPosition(); + agentpos.AgentID = new UUID(UUID.Guid); + agentpos.SessionID = ControllingClient.SessionId; + agentpos.Size = Appearance.AvatarSize; + agentpos.Center = CameraPosition; + agentpos.Far = DrawDistance; + agentpos.Position = AbsolutePosition; + agentpos.Velocity = Velocity; + agentpos.RegionHandle = RegionHandle; + agentpos.GodData = GodController.State(); + agentpos.Throttles = ControllingClient.GetThrottlesPacked(1); + + // Let's get this out of the update loop + Util.FireAndForget( + o => + { + m_scene.SendOutChildAgentUpdates(agentpos, this); + m_lastChildUpdatesTime = Util.EnvironmentTickCount(); + m_childUpdatesBusy = false; + }, null, "ScenePresence.SendOutChildAgentUpdates"); + } } } } @@ -4547,12 +4715,15 @@ namespace OpenSim.Region.Framework.Scenes byebyeRegions.Add(handle); else if(handle == curRegionHandle) { + continue; + /* RegionInfo curreg = m_scene.RegionInfo; if (Util.IsOutsideView(255, curreg.RegionLocX, newRegionX, curreg.RegionLocY, newRegionY, (int)curreg.RegionSizeX, (int)curreg.RegionSizeX, newRegionSizeX, newRegionSizeY)) { byebyeRegions.Add(handle); } + */ } else { @@ -4732,6 +4903,7 @@ namespace OpenSim.Region.Framework.Scenes public void CopyTo(AgentData cAgent, bool isCrossUpdate) { cAgent.CallbackURI = m_callbackURI; + cAgent.NewCallbackURI = m_newCallbackURI; cAgent.AgentID = UUID; cAgent.RegionID = Scene.RegionInfo.RegionID; @@ -4792,7 +4964,7 @@ namespace OpenSim.Region.Framework.Scenes if(isCrossUpdate) { - cAgent.CrossingFlags = crossingFlags; + cAgent.CrossingFlags = m_crossingFlags; cAgent.CrossingFlags |= 1; cAgent.CrossExtraFlags = 0; if((LastCommands & ScriptControlled.CONTROL_LBUTTON) != 0) @@ -4818,9 +4990,10 @@ namespace OpenSim.Region.Framework.Scenes private void CopyFrom(AgentData cAgent) { m_callbackURI = cAgent.CallbackURI; -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", -// Name, m_scene.RegionInfo.RegionName, m_callbackURI); + m_newCallbackURI = cAgent.NewCallbackURI; + // m_log.DebugFormat( + // "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", + // Name, m_scene.RegionInfo.RegionName, m_callbackURI); GodController.SetState(cAgent.GodData); @@ -4928,9 +5101,9 @@ namespace OpenSim.Region.Framework.Scenes if (cAgent.MotionState != 0) Animator.currentControlState = (ScenePresenceAnimator.motionControlStates) cAgent.MotionState; - crossingFlags = cAgent.CrossingFlags; - gotCrossUpdate = (crossingFlags != 0); - if(gotCrossUpdate) + m_crossingFlags = cAgent.CrossingFlags; + m_gotCrossUpdate = (m_crossingFlags != 0); + if(m_gotCrossUpdate) { LastCommands &= ~(ScriptControlled.CONTROL_LBUTTON | ScriptControlled.CONTROL_ML_LBUTTON); if((cAgent.CrossExtraFlags & 1) != 0) @@ -4940,11 +5113,11 @@ namespace OpenSim.Region.Framework.Scenes MouseDown = (cAgent.CrossExtraFlags & 3) != 0; } - haveGroupInformation = false; + m_haveGroupInformation = false; // using this as protocol detection don't want to mess with the numbers for now if(cAgent.ActiveGroupTitle != null) { - haveGroupInformation = true; + m_haveGroupInformation = true; COF = cAgent.agentCOF; if(ControllingClient.IsGroupMember(cAgent.ActiveGroupID)) { @@ -6624,7 +6797,7 @@ namespace OpenSim.Region.Framework.Scenes if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) continue; - // only those on previus parcel need receive kills + // only those on previous parcel need receive kills if (previusParcelID == p.currentParcelUUID) { if(!p.IsViewerUIGod) @@ -6756,7 +6929,13 @@ namespace OpenSim.Region.Framework.Scenes } else { - GodController.HasMovedAway(); + lock (m_completeMovementLock) + { + GodController.HasMovedAway(); + NeedInitialData = -1; + m_gotRegionHandShake = false; + } + List allpresences = m_scene.GetScenePresences(); foreach (ScenePresence p in allpresences) { diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs index bc440fc144..50b0cb5571 100755 --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs @@ -556,7 +556,7 @@ namespace OpenSim.Region.Framework.Scenes sb[27].StatID = (uint)Stats.PhysicsLodTasks; sb[27].StatValue = 0; - sb[28].StatID = (uint)Stats.ScriptEps; // we actuall have this, but not messing array order AGAIN + sb[28].StatID = (uint)Stats.ScriptEps; // we actually have this, but not messing array order AGAIN sb[28].StatValue = (float)Math.Round(m_scriptEventsPerSecond * updateTimeFactor); sb[29].StatID = (uint)Stats.SimAIStepTimeMS; diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs index abf8c488c5..7c3eab1e56 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectCrossingTests.cs @@ -155,11 +155,15 @@ namespace OpenSim.Region.Framework.Scenes.Tests sp1SceneA.AbsolutePosition = so1StartPos; sp1SceneA.HandleAgentRequestSit(sp1SceneA.ControllingClient, sp1SceneA.UUID, so1.UUID, Vector3.Zero); + sceneA.Update(4); + sceneB.Update(4); // Cross sceneA.SceneGraph.UpdatePrimGroupPosition( so1.LocalId, new Vector3(so1StartPos.X, so1StartPos.Y - 20, so1StartPos.Z), sp1SceneA.ControllingClient); // crossing is async + sceneA.Update(4); + sceneB.Update(4); Thread.Sleep(500); SceneObjectGroup so1PostCross; @@ -171,6 +175,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestClient sceneBTc = ((TestClient)sp1SceneBPostCross.ControllingClient); sceneBTc.CompleteMovement(); + sceneA.Update(4); + sceneB.Update(4); + Assert.IsFalse(sp1SceneBPostCross.IsChildAgent, "sp1SceneAPostCross.IsChildAgent unexpectedly true"); Assert.IsTrue(sp1SceneBPostCross.IsSatOnObject); @@ -188,6 +195,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests sceneB.SceneGraph.UpdatePrimGroupPosition( so1PostCross.LocalId, new Vector3(so1PostCrossPos.X, so1PostCrossPos.Y + 20, so1PostCrossPos.Z), sp1SceneBPostCross.ControllingClient); + sceneA.Update(4); + sceneB.Update(4); // crossing is async Thread.Sleep(500); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 94e6b99c3b..676d7eb981 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -212,6 +212,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); sp.AbsolutePosition = new Vector3(30, 31, 32); + sceneA.Update(4); + sceneB.Update(4); + List destinationTestClients = new List(); EntityTransferHelpers.SetupSendRegionTeleportTriggersDestinationClientCreateAndCompleteMovement( (TestClient)sp.ControllingClient, destinationTestClients); @@ -224,11 +227,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests (uint)TeleportFlags.ViaLocation); // Assert.That(sceneA.GetScenePresence(userId), Is.Null); + sceneA.Update(4); + sceneB.Update(4); ScenePresence sceneBSp = sceneB.GetScenePresence(userId); Assert.That(sceneBSp, Is.Not.Null); Assert.That(sceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); - Assert.That(sceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + Assert.That(sceneBSp.AbsolutePosition.X, Is.EqualTo(teleportPosition.X)); + Assert.That(sceneBSp.AbsolutePosition.Y, Is.EqualTo(teleportPosition.Y)); //Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); //Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); @@ -239,7 +245,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera // position instead). -// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); } /// @@ -310,7 +316,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests ScenePresence sceneASp = sceneA.GetScenePresence(userId); Assert.That(sceneASp, Is.Not.Null); Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); - Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition)); + Assert.That(sceneASp.AbsolutePosition.X, Is.EqualTo(preTeleportPosition.X)); + Assert.That(sceneASp.AbsolutePosition.Y, Is.EqualTo(preTeleportPosition.Y)); Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); @@ -369,6 +376,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); sp.AbsolutePosition = preTeleportPosition; + sceneA.Update(4); + sceneB.Update(4); + // Make sceneB refuse CreateAgent sceneB.LoginsEnabled = false; @@ -379,14 +389,18 @@ namespace OpenSim.Region.Framework.Scenes.Tests teleportLookAt, (uint)TeleportFlags.ViaLocation); -// ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); + // ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); + + sceneA.Update(4); + sceneB.Update(4); Assert.That(sceneB.GetScenePresence(userId), Is.Null); ScenePresence sceneASp = sceneA.GetScenePresence(userId); Assert.That(sceneASp, Is.Not.Null); Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); - Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition)); + Assert.That(sceneASp.AbsolutePosition.X, Is.EqualTo(preTeleportPosition.X)); + Assert.That(sceneASp.AbsolutePosition.Y, Is.EqualTo(preTeleportPosition.Y)); Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); @@ -458,6 +472,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); sp.AbsolutePosition = preTeleportPosition; + sceneA.Update(4); + sceneB.Update(4); + sceneA.RequestTeleportLocation( sp.ControllingClient, sceneB.RegionInfo.RegionHandle, @@ -468,13 +485,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate // communication with the destination region. But this is a very non-obvious way of doing it - really we // should be forced to expicitly set this up. + sceneA.Update(4); + sceneB.Update(4); Assert.That(sceneB.GetScenePresence(userId), Is.Null); ScenePresence sceneASp = sceneA.GetScenePresence(userId); Assert.That(sceneASp, Is.Not.Null); Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); - Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition)); + Assert.That(sceneASp.AbsolutePosition.X, Is.EqualTo(preTeleportPosition.X)); + Assert.That(sceneASp.AbsolutePosition.Y, Is.EqualTo(preTeleportPosition.Y)); Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); @@ -614,6 +634,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); + sceneA.Update(4); + sceneB.Update(4); + Assert.That(beforeSceneASp, Is.Not.Null); Assert.That(beforeSceneASp.IsChildAgent, Is.False); @@ -638,6 +661,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests teleportLookAt, (uint)TeleportFlags.ViaLocation); + sceneA.Update(4); + sceneB.Update(4); + ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); Assert.That(afterSceneASp, Is.Not.Null); Assert.That(afterSceneASp.IsChildAgent, Is.True); @@ -646,7 +672,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(afterSceneBSp, Is.Not.Null); Assert.That(afterSceneBSp.IsChildAgent, Is.False); Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); - Assert.That(afterSceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + Assert.That(afterSceneBSp.AbsolutePosition.X, Is.EqualTo(teleportPosition.X)); + Assert.That(afterSceneBSp.AbsolutePosition.Y, Is.EqualTo(teleportPosition.Y)); Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(1)); diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 0fc724b379..e27bbc3f74 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -524,6 +524,8 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server set { } } + public float StartFar { get; set; } + public bool TryGet(out T iface) { iface = default(T); @@ -932,7 +934,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone(),appearance.AvatarSize, new WearableCacheItem[0]); } - public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) + public void SendRegionHandshake() { m_log.Info("[IRCd ClientStack] Completing Handshake to Region"); @@ -943,7 +945,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server if (OnCompleteMovementToRegion != null) { - OnCompleteMovementToRegion(this, true); + OnCompleteMovementToRegion(this, false); } } @@ -967,11 +969,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendStartPingCheck(byte seq) - { - - } - public void SendKillObject(List localID) { @@ -1160,7 +1157,8 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory) + public void SendXferPacket(ulong xferID, uint packet, + byte[] XferData, int XferDataOffset, int XferDatapktLen, bool isTaskInventory) { } @@ -1778,7 +1776,10 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server return 0; } - public void CheckViewerCaps() { } + public uint GetViewerCaps() + { + return 0; + } } } diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs index 65d50bb9a0..4b81838094 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs @@ -278,7 +278,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // There might be some problem with the thread we're generating this on but not // doing the update at this time causes problems (Mantis #7920 and #7915) // TODO: move sending this update to a later time in the rootification of the client. - if(!sp.haveGroupInformation) + if(!sp.m_haveGroupInformation) SendAgentGroupDataUpdate(sp.ControllingClient, false); } diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs index 822439fb5e..2aea7f9cb2 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsModule.cs @@ -133,7 +133,7 @@ namespace OpenSim.Region.OptionalModules.Materials if(m_changed.Count == 0) return; - if(forcedBackup) + if (forcedBackup) { toStore = new List(m_changed.Keys); m_changed.Clear(); @@ -154,16 +154,29 @@ namespace OpenSim.Region.OptionalModules.Materials m_changed.Remove(fm); } } + } if(toStore.Count > 0) - Util.FireAndForget(delegate + { + if (forcedBackup) { - foreach(FaceMaterial fm in toStore) + foreach (FaceMaterial fm in toStore) { AssetBase a = MakeAsset(fm, false); m_scene.AssetService.Store(a); } - }); + } + else + { + Util.FireAndForget(delegate + { + foreach (FaceMaterial fm in toStore) + { + AssetBase a = MakeAsset(fm, false); + m_scene.AssetService.Store(a); + } + }); + } } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 9c130618fc..d3eb25f671 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -562,6 +562,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC set { } } + public float StartFar { get; set; } + public virtual UUID AgentId { get { return m_uuid; } @@ -668,10 +670,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendStartPingCheck(byte seq) - { - } - public virtual void SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData, List Data) { } @@ -870,9 +868,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory) + public virtual void SendXferPacket(ulong xferID, uint packet, + byte[] XferData, int XferDataOffset, int XferDatapktLen, bool isTaskInventory) { } + public virtual void SendAbortXferPacket(ulong xferID) { @@ -928,7 +928,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) + public virtual void SendRegionHandshake() { if (OnRegionHandShakeReply != null) { @@ -1388,7 +1388,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC return 0; } - public void CheckViewerCaps() { } + public uint GetViewerCaps() + { + return 0; + } } } diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs index 0d4b6b96f2..de39d0ed07 100644 --- a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs +++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs @@ -597,28 +597,22 @@ namespace OpenSim.Region.PhysicsModule.Meshing { OSD decodedOsd = null; - using (MemoryStream inMs = new MemoryStream(meshBytes)) + using (MemoryStream outMs = new MemoryStream()) { - using (MemoryStream outMs = new MemoryStream()) + using (MemoryStream inMs = new MemoryStream(meshBytes)) { using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress)) { - byte[] readBuffer = new byte[2048]; + byte[] readBuffer = new byte[8192]; inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header int readLen = 0; while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0) outMs.Write(readBuffer, 0, readLen); - - outMs.Flush(); - - outMs.Seek(0, SeekOrigin.Begin); - - byte[] decompressedBuf = outMs.GetBuffer(); - - decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); } } + outMs.Seek(0, SeekOrigin.Begin); + decodedOsd = OSDParser.DeserializeLLSDBinary(outMs); } return decodedOsd; } diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs b/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs index 7ad5e3ddb1..b86be0f7b8 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODECharacter.cs @@ -1603,7 +1603,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde } else { - Vector3 a = _velocity; // previus velocity + Vector3 a = _velocity; // previous velocity SetSmooth(ref _velocity,ref vel,2); a = (_velocity - a) * invtimeStep; SetSmooth(ref _acceleration,ref a,2); @@ -1921,6 +1921,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde _position = newPos; m_freemove = false; + _zeroFlag = false; m_pidControllerActive = true; } @@ -1976,8 +1977,8 @@ namespace OpenSim.Region.PhysicsModule.ubOde private void changeTargetVelocity(Vector3 newVel) { - m_pidControllerActive = true; - m_freemove = false; + //m_pidControllerActive = true; + //m_freemove = false; _target_velocity = newVel; if (Body != IntPtr.Zero) SafeNativeMethods.BodyEnable(Body); diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs index 6950f2dc2a..84495963ab 100644 --- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs +++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs @@ -425,31 +425,24 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing return false; // no mesh data in asset OSD decodedMeshOsd = new OSD(); - byte[] meshBytes = new byte[physSize]; - System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); - try { - using (MemoryStream inMs = new MemoryStream(meshBytes)) + using (MemoryStream outMs = new MemoryStream(4 * physSize)) { - using (MemoryStream outMs = new MemoryStream()) + using (MemoryStream inMs = new MemoryStream(primShape.SculptData, physOffset, physSize)) { using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress)) { - byte[] readBuffer = new byte[2048]; + byte[] readBuffer = new byte[8192]; inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header int readLen = 0; while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0) outMs.Write(readBuffer, 0, readLen); - - outMs.Seek(0, SeekOrigin.Begin); - - byte[] decompressedBuf = outMs.GetBuffer(); - - decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); } } + outMs.Seek(0, SeekOrigin.Begin); + decodedMeshOsd = OSDParser.DeserializeLLSDBinary(outMs); } } catch (Exception e) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index ab3562f35b..5d72858fe2 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2403,6 +2403,70 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScriptSleep(m_sleepMsOnSetLinkTexture); } + protected void SetTextureParams(SceneObjectPart part, string texture, double scaleU, double ScaleV, + double offsetU, double offsetV, double rotation, int face) + { + if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + + UUID textureID = new UUID(); + bool dotexture = true; + if(String.IsNullOrEmpty(texture) || texture == ScriptBaseClass.NULL_KEY) + dotexture = false; + else + { + textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture); + if (textureID == UUID.Zero) + { + if (!UUID.TryParse(texture, out textureID)) + dotexture = false; + } + } + + Primitive.TextureEntry tex = part.Shape.Textures; + int nsides = GetNumberOfSides(part); + + if (face >= 0 && face < nsides) + { + Primitive.TextureEntryFace texface = tex.CreateFace((uint)face); + if (dotexture) + texface.TextureID = textureID; + texface.RepeatU = (float)scaleU; + texface.RepeatV = (float)ScaleV; + texface.OffsetU = (float)offsetU; + texface.OffsetV = (float)offsetV; + texface.Rotation = (float)rotation; + tex.FaceTextures[face] = texface; + part.UpdateTextureEntry(tex); + return; + } + else if (face == ScriptBaseClass.ALL_SIDES) + { + for (uint i = 0; i < nsides; i++) + { + if (tex.FaceTextures[i] != null) + { + if (dotexture) + tex.FaceTextures[i].TextureID = textureID; + tex.FaceTextures[i].RepeatU = (float)scaleU; + tex.FaceTextures[i].RepeatV = (float)ScaleV; + tex.FaceTextures[i].OffsetU = (float)offsetU; + tex.FaceTextures[i].OffsetV = (float)offsetV; + tex.FaceTextures[i].Rotation = (float)rotation; + } + } + if (dotexture) + tex.DefaultTexture.TextureID = textureID; + tex.DefaultTexture.RepeatU = (float)scaleU; + tex.DefaultTexture.RepeatV = (float)ScaleV; + tex.DefaultTexture.OffsetU = (float)offsetU; + tex.DefaultTexture.OffsetV = (float)offsetV; + tex.DefaultTexture.Rotation = (float)rotation; + part.UpdateTextureEntry(tex); + return; + } + } + protected void SetTexture(SceneObjectPart part, string texture, int face) { if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) @@ -3830,6 +3894,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_item.PermsGranter != m_host.OwnerID) return; + SceneObjectGroup grp = m_host.ParentGroup; + if (grp == null || grp.IsDeleted || grp.IsAttachment) + return; + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0) AttachToAvatar(attachmentPoint); } @@ -7991,13 +8059,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llSetTouchText(string text) { m_host.AddScriptLPS(1); - m_host.TouchName = text; + if(text.Length <= 9) + m_host.TouchName = text; + else + m_host.TouchName = text.Substring(0, 9); } public void llSetSitText(string text) { m_host.AddScriptLPS(1); - m_host.SitName = text; + if (text.Length <= 9) + m_host.SitName = text; + else + m_host.SitName = text.Substring(0, 9); } public void llSetCameraEyeOffset(LSL_Vector offset) @@ -9722,11 +9796,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_List(); } - SetTexture(part, tex, face); - ScaleTexture(part, repeats.x, repeats.y, face); - OffsetTexture(part, offsets.x, offsets.y, face); - RotateTexture(part, rotation, face); - + SetTextureParams(part, tex, repeats.x, repeats.y, offsets.x, offsets.y, rotation, face); break; case ScriptBaseClass.PRIM_COLOR: @@ -10360,17 +10430,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } string mapname = rules.Data[idx++].ToString(); - - UUID mapID = ScriptUtils.GetAssetIdFromItemName(m_host, mapname, (int)AssetType.Texture); - if (mapID == UUID.Zero) + UUID mapID = UUID.Zero; + if (!string.IsNullOrEmpty(mapname)) { - if (!UUID.TryParse(mapname, out mapID)) + mapID = ScriptUtils.GetAssetIdFromItemName(m_host, mapname, (int)AssetType.Texture); + if (mapID == UUID.Zero) { - Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1)); - return new LSL_List(); + if (!UUID.TryParse(mapname, out mapID)) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } } } - LSL_Vector mnrepeat; try { @@ -10427,17 +10499,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } string smapname = rules.Data[idx++].ToString(); - - UUID smapID = ScriptUtils.GetAssetIdFromItemName(m_host, smapname, (int)AssetType.Texture); - if (smapID == UUID.Zero) + UUID smapID = UUID.Zero; + if(!string.IsNullOrEmpty(smapname)) { - if (!UUID.TryParse(smapname, out smapID)) + smapID = ScriptUtils.GetAssetIdFromItemName(m_host, smapname, (int)AssetType.Texture); + if (smapID == UUID.Zero) { - Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1)); - return new LSL_List(); + if (!UUID.TryParse(smapname, out smapID)) + { + Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1)); + return new LSL_List(); + } } } - LSL_Vector msrepeat; try { @@ -10653,24 +10727,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api FaceMaterial mat = null; UUID oldid = texface.MaterialID; - if(oldid != UUID.Zero) - mat = m_materialsModule.GetMaterialCopy(oldid); + if(mapID != UUID.Zero) + { + if(oldid != UUID.Zero) + mat = m_materialsModule.GetMaterialCopy(oldid); - if(mat == null) - mat = new FaceMaterial(); + if(mat == null) + mat = new FaceMaterial(); - mat.NormalMapID = mapID; - mat.NormalOffsetX = offsetX; - mat.NormalOffsetY = offsetY; - mat.NormalRepeatX = repeatX; - mat.NormalRepeatY = repeatY; - mat.NormalRotation = rot; + mat.NormalMapID = mapID; + mat.NormalOffsetX = offsetX; + mat.NormalOffsetY = offsetY; + mat.NormalRepeatX = repeatX; + mat.NormalRepeatY = repeatY; + mat.NormalRotation = rot; - UUID id = m_materialsModule.AddNewMaterial(mat); - if(oldid == id) + mapID = m_materialsModule.AddNewMaterial(mat); + } + if(oldid == mapID) return false; - texface.MaterialID = id; + texface.MaterialID = mapID; part.Shape.TextureEntry = tex.GetBytes(9); m_materialsModule.RemoveMaterial(oldid); return true; @@ -10715,29 +10792,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api FaceMaterial mat = null; UUID oldid = texface.MaterialID; - if(oldid != UUID.Zero) - mat = m_materialsModule.GetMaterialCopy(oldid); + if (mapID != UUID.Zero) + { + if (oldid != UUID.Zero) + mat = m_materialsModule.GetMaterialCopy(oldid); - if(mat == null) - mat = new FaceMaterial(); + if (mat == null) + mat = new FaceMaterial(); - mat.SpecularMapID = mapID; - mat.SpecularOffsetX = offsetX; - mat.SpecularOffsetY = offsetY; - mat.SpecularRepeatX = repeatX; - mat.SpecularRepeatY = repeatY; - mat.SpecularRotation = rot; - mat.SpecularLightColorR = colorR; - mat.SpecularLightColorG = colorG; - mat.SpecularLightColorB = colorB; - mat.SpecularLightExponent = gloss; - mat.EnvironmentIntensity = env; + mat.SpecularMapID = mapID; + mat.SpecularOffsetX = offsetX; + mat.SpecularOffsetY = offsetY; + mat.SpecularRepeatX = repeatX; + mat.SpecularRepeatY = repeatY; + mat.SpecularRotation = rot; + mat.SpecularLightColorR = colorR; + mat.SpecularLightColorG = colorG; + mat.SpecularLightColorB = colorB; + mat.SpecularLightExponent = gloss; + mat.EnvironmentIntensity = env; - UUID id = m_materialsModule.AddNewMaterial(mat); - if(oldid == id) + mapID = m_materialsModule.AddNewMaterial(mat); + } + + if(oldid == mapID) return false; - texface.MaterialID = id; + texface.MaterialID = mapID; part.Shape.TextureEntry = tex.GetBytes(9); m_materialsModule.RemoveMaterial(oldid); return true; @@ -14111,15 +14192,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; - if (land.OwnerID == m_host.OwnerID) + if (land.OwnerID == m_host.OwnerID && land.ParcelAccessList.Count > 0) { + var todelete = new List(); foreach (LandAccessEntry entry in land.ParcelAccessList) { if (entry.Flags == AccessList.Ban) - { - land.ParcelAccessList.Remove(entry); - } + todelete.Add(entry); } + foreach (LandAccessEntry entry in todelete) + land.ParcelAccessList.Remove(entry); } ScriptSleep(m_sleepMsOnResetLandBanList); } @@ -14128,15 +14210,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; - if (land.OwnerID == m_host.OwnerID) + if (land.OwnerID == m_host.OwnerID && land.ParcelAccessList.Count > 0) { + var todelete = new List(); foreach (LandAccessEntry entry in land.ParcelAccessList) { if (entry.Flags == AccessList.Access) - { - land.ParcelAccessList.Remove(entry); - } + todelete.Add(entry); } + foreach (LandAccessEntry entry in todelete) + land.ParcelAccessList.Remove(entry); } ScriptSleep(m_sleepMsOnResetLandPassList); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index dabd399b0a..7d3c832d1e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -145,6 +145,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IUrlModule m_UrlModule = null; protected ISoundModule m_SoundModule = null; internal IConfig m_osslconfig; + internal TimeZoneInfo PSTTimeZone = null; public void Initialize( IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item) @@ -201,7 +202,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api default: break; } - } + + try + { + PSTTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); + } + catch + { + PSTTimeZone = null; + } + if(PSTTimeZone == null) + { + try + { + PSTTimeZone = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles"); + } + catch + { + PSTTimeZone = null; + } + } + } public override Object InitializeLifetimeService() { @@ -903,6 +924,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } // Teleport functions + public void osLocalTeleportAgent(LSL_Key agent, LSL_Types.Vector3 position, LSL_Types.Vector3 velocity, LSL_Types.Vector3 lookat, LSL_Integer flags) + { + UUID agentId; + if (!UUID.TryParse(agent, out agentId)) + return; + + ScenePresence presence = World.GetScenePresence(agentId); + if (presence == null || presence.IsDeleted || presence.IsInTransit) + return; + + Vector3 pos = presence.AbsolutePosition; + if (!checkAllowAgentTPbyLandOwner(agentId, pos)) + return; + + World.RequestLocalTeleport(presence, position, velocity, lookat, flags); + } + public void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat) { // High because there is no security check. High griefer potential @@ -3780,7 +3818,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules) { - CheckThreatLevel(ThreatLevel.High, "osGetPrimitiveParams"); + CheckThreatLevel(); InitLSL(); return m_LSL_Api.GetPrimitiveParamsEx(prim, rules); @@ -3788,7 +3826,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osSetPrimitiveParams(LSL_Key prim, LSL_List rules) { - CheckThreatLevel(ThreatLevel.High, "osSetPrimitiveParams"); + CheckThreatLevel(); InitLSL(); m_LSL_Api.SetPrimitiveParamsEx(prim, rules, "osSetPrimitiveParams"); @@ -3797,15 +3835,40 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// /// Set parameters for light projection in host prim /// - public void osSetProjectionParams(bool projection, LSL_Key texture, double fov, double focus, double amb) + public void osSetProjectionParams(LSL_Integer projection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb) { - osSetProjectionParams(UUID.Zero.ToString(), projection, texture, fov, focus, amb); + SetProjectionParams(m_host, projection, texture, fov, focus, amb); + } + + /// + /// Set parameters for light projection of a linkset prim + /// + public void osSetProjectionParams(LSL_Integer linknum, LSL_Integer projection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb) + { + if (linknum == ScriptBaseClass.LINK_THIS || linknum == m_host.LinkNum) + { + SetProjectionParams(m_host, projection, texture, fov, focus, amb); + return; + } + + if (linknum < 0 || linknum > m_host.ParentGroup.PrimCount) + return; + + if(linknum < 2 && m_host.LinkNum < 2) + { + SetProjectionParams(m_host, projection, texture, fov, focus, amb); + return; + } + + SceneObjectPart obj = m_host.ParentGroup.GetLinkNumPart(linknum); + if(obj != null) + SetProjectionParams(obj, projection, texture, fov, focus, amb); } /// /// Set parameters for light projection with uuid of target prim /// - public void osSetProjectionParams(LSL_Key prim, bool projection, LSL_Key texture, double fov, double focus, double amb) + public void osSetProjectionParams(LSL_Key prim, LSL_Integer llprojection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb) { CheckThreatLevel(ThreatLevel.High, "osSetProjectionParams"); @@ -3820,7 +3883,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (obj == null) return; } + SetProjectionParams(obj, llprojection, texture, fov, focus, amb); + } + private void SetProjectionParams(SceneObjectPart obj, LSL_Integer llprojection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb) + { + bool projection = llprojection != 0; obj.Shape.ProjectionEntry = projection; obj.Shape.ProjectionTextureUUID = new UUID(texture); obj.Shape.ProjectionFOV = (float)fov; @@ -5441,5 +5509,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return String.Empty; return detectedParams.Key.ToString(); } + + // returns PST or PDT wall clock + public LSL_Float osGetPSTWallclock() + { + m_host.AddScriptLPS(1); + if(PSTTimeZone == null) + return DateTime.Now.TimeOfDay.TotalSeconds; + + DateTime time = TimeZoneInfo.ConvertTime(DateTime.UtcNow, PSTTimeZone); + return time.TimeOfDay.TotalSeconds; + } } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 49b3f74e8c..194df36fec 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -150,6 +150,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces string osGetAgentIP(string agent); // Teleport commands + void osLocalTeleportAgent(LSL_Key agent, LSL_Types.Vector3 position, LSL_Types.Vector3 velocity, LSL_Types.Vector3 lookat, LSL_Integer flags); void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); void osTeleportAgent(string agent, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); @@ -393,8 +394,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osForceOtherSit(string avatar, string target); LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules); void osSetPrimitiveParams(LSL_Key prim, LSL_List rules); - void osSetProjectionParams(bool projection, LSL_Key texture, double fov, double focus, double amb); - void osSetProjectionParams(LSL_Key prim, bool projection, LSL_Key texture, double fov, double focus, double amb); + void osSetProjectionParams(LSL_Integer projection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb); + void osSetProjectionParams(LSL_Key prim, LSL_Integer projection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb); + void osSetProjectionParams(LSL_Integer linknumber, LSL_Integer projection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb); LSL_List osGetAvatarList(); LSL_List osGetNPCList(); @@ -549,5 +551,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String osGetInventoryName(LSL_Key itemId); LSL_String osGetInventoryDesc(LSL_String itemNameOrId); LSL_Key osGetLastChangedEventKey(); + LSL_Float osGetPSTWallclock(); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 8b70128e71..fa0e25c5f6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -35,7 +35,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public partial class ScriptBaseClass { // SCRIPTS CONSTANTS - public static readonly LSLInteger OS_APIVERSION = 3; + public static readonly LSLInteger OS_APIVERSION = 4; public static readonly LSLInteger TRUE = 1; public static readonly LSLInteger FALSE = 0; @@ -189,6 +189,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int VEHICLE_RANGE_BLOCK = 45; public const int VEHICLE_ROLL_FRAME = 46; public const int VEHICLE_FLAG_NO_DEFLECTION_UP = 1; + public const int VEHICLE_FLAG_NO_FLY_UP = 1; //legacy public const int VEHICLE_FLAG_LIMIT_ROLL_ONLY = 2; public const int VEHICLE_FLAG_HOVER_WATER_ONLY = 4; public const int VEHICLE_FLAG_HOVER_TERRAIN_ONLY = 8; @@ -898,6 +899,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase //ApiDesc osTeleportObject flag: the rotation is the final rotation, otherwise is a added rotation public const int OSTPOBJ_SETROT = 0x4; + //ApiDesc osLocalTeleportAgent no flags + public const int OS_LTPAG_NONE = 0x0; + //ApiDesc osLocalTeleportAgent use velocity + public const int OS_LTPAG_USEVEL = 0x1; + //ApiDesc osLocalTeleportAgent use lookat + public const int OS_LTPAG_USELOOKAT = 0x2; + //ApiDesc osLocalTeleportAgent align lookat to velocity + public const int OS_LTPAG_ALGNLV = 0x4; + //ApiDesc osLocalTeleportAgent force fly + public const int OS_LTPAG_FORCEFLY = 0x8; + //ApiDesc osLocalTeleportAgent force no fly + public const int OS_LTPAG_FORCENOFLY = 0x16; + // Constants for Windlight public const int WL_WATER_COLOR = 0; public const int WL_WATER_FOG_DENSITY_EXPONENT = 1; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index fb491e4923..88ea9d5660 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -247,6 +247,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase // Teleport Functions + public void osLocalTeleportAgent(LSL_Key agent, vector position, vector velocity, vector lookat, LSL_Integer flags) + { + m_OSSL_Functions.osLocalTeleportAgent(agent, position, velocity, lookat, flags); + } + public void osTeleportAgent(string agent, string regionName, vector position, vector lookat) { m_OSSL_Functions.osTeleportAgent(agent, regionName, position, lookat); @@ -1035,16 +1040,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osSetPrimitiveParams(prim, rules); } - public void osSetProjectionParams(bool projection, LSL_Key texture, double fov, double focus, double amb) + public void osSetProjectionParams(LSL_Integer projection, LSL_Key texture, double fov, double focus, double amb) { m_OSSL_Functions.osSetProjectionParams(projection, texture, fov, focus, amb); } - public void osSetProjectionParams(LSL_Key prim, bool projection, LSL_Key texture, double fov, double focus, double amb) + public void osSetProjectionParams(LSL_Key prim, LSL_Integer projection, LSL_Key texture, double fov, double focus, double amb) { m_OSSL_Functions.osSetProjectionParams(prim, projection, texture, fov, focus, amb); } + public void osSetProjectionParams(LSL_Integer linknumber, LSL_Integer projection, LSL_Key texture, LSL_Float fov, LSL_Float focus, LSL_Float amb) + { + m_OSSL_Functions.osSetProjectionParams(linknumber, projection, texture, fov, focus, amb); + } + public LSL_List osGetAvatarList() { return m_OSSL_Functions.osGetAvatarList(); @@ -1381,5 +1391,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osGetLastChangedEventKey(); } + + public LSL_Float osGetPSTWallclock() + { + return m_OSSL_Functions.osGetPSTWallclock(); + } + } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCodeGen.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCodeGen.cs index 5f00f867c8..27fde5b22c 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCodeGen.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCodeGen.cs @@ -69,7 +69,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine public static readonly string OBJECT_CODE_MAGIC = "YObjectCode"; // reserve positive version values for original xmr - public static int COMPILED_VERSION_VALUE = -1; // decremented when compiler or object file changes + public static int COMPILED_VERSION_VALUE = -2; // decremented when compiler or object file changes public static readonly int CALL_FRAME_MEMUSE = 64; public static readonly int STRING_LEN_TO_MEMUSE = 2; @@ -197,7 +197,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine public CallLabel openCallLabel = null; // only one call label can be open at a time // - the call label is open from the time of CallPre() until corresponding CallPost() // - so no non-trivial pushes/pops etc allowed between a CallPre() and a CallPost() - + public List HeapLocals = new List(); private ScriptMyILGen _ilGen; public ScriptMyILGen ilGen { @@ -1258,6 +1258,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine // resume at the correct spot. actCallLabels.Clear(); allCallLabels.Clear(); + HeapLocals.Clear(); openCallLabel = null; // Alloc stack space for local vars. @@ -1398,19 +1399,17 @@ namespace OpenSim.Region.ScriptEngine.Yengine _ilGen = collector.WriteOutAll(); collector = null; - // Output code to restore stack frame from stream. - // It jumps back to the call labels within the function body. List activeTemps = null; - if(!isTrivial) + if (!isTrivial) { - // Build list of locals and temps active at all the call labels. + // Build list of locals and temps active at all the call labels. activeTemps = new List(); - foreach(CallLabel cl in allCallLabels) - { - foreach(ScriptMyLocal lcl in cl.callLabel.whereAmI.localsReadBeforeWritten) + foreach (CallLabel cl in allCallLabels) { - if(!activeTemps.Contains(lcl)) + foreach(ScriptMyLocal lcl in cl.callLabel.whereAmI.localsReadBeforeWritten) { + if(!activeTemps.Contains(lcl)) + { activeTemps.Add(lcl); } } @@ -1452,11 +1451,34 @@ namespace OpenSim.Region.ScriptEngine.Yengine } // Output the 'real' return opcode. + // push return value ilGen.MarkLabel(retLabel); - if(!(curDeclFunc.retType is TokenTypeVoid)) + if (!(curDeclFunc.retType is TokenTypeVoid)) { ilGen.Emit(curDeclFunc, OpCodes.Ldloc, retValue); } + + // pseudo free memory usage + foreach (ScriptMyLocal sml in HeapLocals) + { + Type t = sml.type; + if (t == typeof(HeapTrackerList)) + { + ilGen.Emit(curDeclFunc, OpCodes.Ldloc, sml); + HeapTrackerList.GenFree(curDeclFunc, ilGen); + } + else if (t == typeof(HeapTrackerString)) + { + ilGen.Emit(curDeclFunc, OpCodes.Ldloc, sml); + HeapTrackerString.GenFree(curDeclFunc, ilGen); + } + else if (t == typeof(HeapTrackerObject)) + { + ilGen.Emit(curDeclFunc, OpCodes.Ldloc, sml); + HeapTrackerObject.GenFree(curDeclFunc, ilGen); + } + } + ilGen.Emit(curDeclFunc, OpCodes.Ret); retLabel = null; retValue = null; @@ -1675,11 +1697,11 @@ namespace OpenSim.Region.ScriptEngine.Yengine if(u != t) { if(t == typeof(HeapTrackerList)) - HeapTrackerList.GenPop(curDeclFunc, ilGen); + HeapTrackerList.GenRestore(curDeclFunc, ilGen); if(t == typeof(HeapTrackerObject)) - HeapTrackerObject.GenPop(curDeclFunc, ilGen); + HeapTrackerObject.GenRestore(curDeclFunc, ilGen); if(t == typeof(HeapTrackerString)) - HeapTrackerString.GenPop(curDeclFunc, ilGen); + HeapTrackerString.GenRestore(curDeclFunc, ilGen); } else { diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCollector.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCollector.cs index 75eae53627..e92f429bdd 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCollector.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCollector.cs @@ -2611,10 +2611,10 @@ namespace OpenSim.Region.ScriptEngine.Yengine // everything required by any blocks it can branch to. do { - this.resolvedSomething = false; - this.resolveSequence++; - this.ResolveBlock((GraphNodeBlock)firstLin); - } while(this.resolvedSomething); + resolvedSomething = false; + resolveSequence++; + ResolveBlock((GraphNodeBlock)firstLin); + } while(resolvedSomething); // Repeat the cutting loops as long as we keep finding stuff. bool didSomething; @@ -2939,7 +2939,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine return; // So we don't recurse forever on a backward branch. - currentBlock.hasBeenResolved = this.resolveSequence; + currentBlock.hasBeenResolved = resolveSequence; // Assume we haven't written any locals yet. List localsWrittenSoFar = new List(); @@ -2975,7 +2975,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine !currentBlock.localsReadBeforeWritten.Contains(readByNextBlock)) { currentBlock.localsReadBeforeWritten.Add(readByNextBlock); - this.resolvedSomething = true; + resolvedSomething = true; } } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs index 675ab9ae25..486d822cb1 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompValu.cs @@ -1483,7 +1483,8 @@ namespace OpenSim.Region.ScriptEngine.Yengine { if(type.ToHeapTrackerType() != null) { - this.localBuilder = scg.ilGen.DeclareLocal(type.ToHeapTrackerType(), name); + localBuilder = scg.ilGen.DeclareLocal(type.ToHeapTrackerType(), name); + scg.HeapLocals.Add(localBuilder); scg.PushXMRInst(); scg.ilGen.Emit(type, OpCodes.Newobj, type.GetHeapTrackerCtor()); scg.ilGen.Emit(type, OpCodes.Stloc, localBuilder); @@ -1547,6 +1548,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine scg.ilGen.Emit(errorAt, OpCodes.Ldloc, localBuilder); scg.ilGen.Emit(errorAt, OpCodes.Ldloc, htpop); type.CallHeapTrackerPopMeth(errorAt, scg.ilGen); + scg.HeapLocals.Add(htpop); } else { diff --git a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompile.cs b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompile.cs index f37efd48d1..8e15402eeb 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompile.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/MMRScriptCompile.cs @@ -130,7 +130,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine // Since we just wrote the .xmrobj file, maybe save disassembly. if (m_Engine.m_ScriptDebugSaveIL) { - string asmFileName = GetScriptFileName (m_ScriptObjCodeKey + ".yasm"); + string asmFileName = GetScriptILFileName(m_ScriptObjCodeKey + ".yasm"); // m_log.Debug ("[YEngine]: MMRScriptCompileSaveILGen: saving to " + asmFileName); asmFileWriter = File.CreateText (asmFileName); } diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRArray.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRArray.cs index 3d0525b7a4..930a8d6ca9 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRArray.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRArray.cs @@ -125,7 +125,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine // Save new value in array, replacing one of same key if there. // null means remove the value, ie, script did array[key] = undef. - if(value != null) + if (value != null) { dnary[key] = value; } @@ -285,10 +285,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine public void RecvArrayObj(RecvArrayObjDelegate recvObj) { heapUse = inst.UpdateHeapUse(heapUse, EMPTYHEAP); - - // Cause any enumeration to refill the array from the sorted dictionary. - // Since it is a sorted dictionary, any enumerations will be in the same - // order as on the sending side. + // Cause any enumeration to refill the array from the sorted dictionary. + // Since it is a sorted dictionary, any enumerations will be in the same + // order as on the sending side. arrayValid = 0; enumrValid = false; diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs index 6acc293869..e1f8c4c329 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMREngine.cs @@ -1535,15 +1535,38 @@ namespace OpenSim.Region.ScriptEngine.Yengine */ public void QueueToStart(XMRInstance inst) { - if(inst.m_IState != XMRInstState.ONSTARTQ) + if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state"); - lock(m_StartQueue) + lock (m_StartQueue) m_StartQueue.InsertTail(inst); WakeUpOne(); } + public void QueueToYield(XMRInstance inst) + { + if (inst.m_IState != XMRInstState.ONYIELDQ) + throw new Exception("bad state"); + + lock (m_YieldQueue) + m_YieldQueue.InsertTail(inst); + + WakeUpOne(); + } + + public void RemoveFromSleep(XMRInstance inst) + { + lock (m_SleepQueue) + { + if (inst.m_IState != XMRInstState.ONSLEEPQ) + return; + + m_SleepQueue.Remove(inst); + inst.m_IState = XMRInstState.REMDFROMSLPQ; + } + } + /** * @brief A script may be sleeping, in which case we wake it. */ diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRHeapTracker.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRHeapTracker.cs index 33eb8bf5e0..8b6734926d 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRHeapTracker.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRHeapTracker.cs @@ -58,11 +58,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine if(inst == null) throw new ArgumentNullException("inst"); instance = inst; - } - - ~HeapTrackerBase() - { - usage = instance.UpdateHeapUse(usage, 0); + usage = 0; } } @@ -73,24 +69,33 @@ namespace OpenSim.Region.ScriptEngine.Yengine { private static FieldInfo listValueField = typeof(HeapTrackerList).GetField("value"); private static MethodInfo listSaveMethod = typeof(HeapTrackerList).GetMethod("Save"); + private static MethodInfo listRestoreMethod = typeof(HeapTrackerList).GetMethod("Restore"); + private static MethodInfo listFreeMethod = typeof(HeapTrackerList).GetMethod("Free"); public LSL_List value; - public HeapTrackerList(XMRInstAbstract inst) : base(inst) { } + public HeapTrackerList(XMRInstAbstract inst) : base(inst) {} - // generate CIL code to pop the value from the CIL stack + // generate CIL code to pop the value ie store in value // input: // 'this' pointer already pushed on CIL stack - // new value pushed on CIL stack + // new value // output: - // 'this' pointer popped from stack - // new value popped from CIL stack - // heap usage updated public static void GenPop(Token errorAt, ScriptMyILGen ilGen) { ilGen.Emit(errorAt, OpCodes.Call, listSaveMethod); } + public static void GenRestore(Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit(errorAt, OpCodes.Call, listRestoreMethod); + } + + public static void GenFree(Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit(errorAt, OpCodes.Call, listFreeMethod); + } + // generate CIL code to push the value on the CIL stack // input: // 'this' pointer already pushed on CIL stack @@ -106,23 +111,32 @@ namespace OpenSim.Region.ScriptEngine.Yengine public void Save(LSL_List lis) { - int newuse = Size(lis); - usage = instance.UpdateHeapUse(usage, newuse); + if (lis == null) + usage = instance.UpdateHeapUse(usage, 0); + else + usage = instance.UpdateHeapUse(usage, Size(lis)); value = lis; } + public void Restore(LSL_List lis) + { + value = lis; + if (lis != null) + usage = Size(lis); + else + usage = 0; + } + + public void Free() + { + usage = instance.UpdateHeapUse(usage, 0); + value = null; + instance = null; + } + //private static int counter = 5; public static int Size(LSL_List lis) { - // VS2017 in debug mode seems to have a problem running this statement quickly: - //SLOW: return (!typeof(LSL_List).IsValueType && (lis == null)) ? 0 : lis.Size; - - //FAST: return 33; - //SLOW: return (lis == null) ? 0 : 99; - //FAST: return ++ counter; - - // VS2017 in debug mode seems content to run this quickly though: - try { return lis.Size; @@ -141,6 +155,8 @@ namespace OpenSim.Region.ScriptEngine.Yengine { private static FieldInfo objectValueField = typeof(HeapTrackerObject).GetField("value"); private static MethodInfo objectSaveMethod = typeof(HeapTrackerObject).GetMethod("Save"); + private static MethodInfo objectRestoreMethod = typeof(HeapTrackerObject).GetMethod("Restore"); + private static MethodInfo objectFreeMethod = typeof(HeapTrackerObject).GetMethod("Free"); public const int HT_CHAR = 2; public const int HT_DELE = 8; @@ -168,6 +184,16 @@ namespace OpenSim.Region.ScriptEngine.Yengine ilGen.Emit(errorAt, OpCodes.Call, objectSaveMethod); } + public static void GenRestore(Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit(errorAt, OpCodes.Call, objectRestoreMethod); + } + + public static void GenFree(Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit(errorAt, OpCodes.Call, objectFreeMethod); + } + // generate CIL code to push the value on the CIL stack // input: // 'this' pointer already pushed on CIL stack @@ -188,6 +214,19 @@ namespace OpenSim.Region.ScriptEngine.Yengine value = obj; } + public void Restore(object obj) + { + value = obj; + usage = Size(obj); + } + + public void Free() + { + usage = instance.UpdateHeapUse(usage, 0); + value = null; + instance = null; + } + // public so it can be used by XMRArray public static int Size(object obj) { @@ -204,8 +243,8 @@ namespace OpenSim.Region.ScriptEngine.Yengine return HT_SING; if(obj is int) return HT_INT; - if(obj is LSL_Float) - return HT_SFLT; + if(obj is LSL_Float) // lsl floats are stupid doubles + return HT_DOUB; if(obj is LSL_Integer) return HT_INT; if(obj is LSL_List) @@ -252,7 +291,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine public class HeapTrackerString: HeapTrackerBase { private static FieldInfo stringValueField = typeof(HeapTrackerString).GetField("value"); + private static MethodInfo stringRestoreMethod = typeof(HeapTrackerString).GetMethod("Restore"); private static MethodInfo stringSaveMethod = typeof(HeapTrackerString).GetMethod("Save"); + private static MethodInfo stringFreeMethod = typeof(HeapTrackerString).GetMethod("Free"); public string value; @@ -271,6 +312,16 @@ namespace OpenSim.Region.ScriptEngine.Yengine ilGen.Emit(errorAt, OpCodes.Call, stringSaveMethod); } + public static void GenRestore(Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit(errorAt, OpCodes.Call, stringRestoreMethod); + } + + public static void GenFree(Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit(errorAt, OpCodes.Call, stringFreeMethod); + } + // generate CIL code to push the value on the CIL stack // input: // 'this' pointer already pushed on CIL stack @@ -291,6 +342,19 @@ namespace OpenSim.Region.ScriptEngine.Yengine value = str; } + public void Restore(string str) + { + value = str; + usage = Size(str); + } + + public void Free() + { + usage = instance.UpdateHeapUse(usage, 0); + value = null; + instance = null; + } + public static int Size(string str) { return (str == null) ? 0 : str.Length * HeapTrackerObject.HT_CHAR; diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstAbstract.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstAbstract.cs index a440cf3a6e..dec775fab5 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstAbstract.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstAbstract.cs @@ -60,7 +60,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine public Delegate[][] iarSDTIntfObjs; private XMRInstAbstract instance; - private int heapUse; + private int arraysHeapUse; private static readonly XMR_Array[] noArrays = new XMR_Array[0]; private static readonly char[] noChars = new char[0]; @@ -81,20 +81,49 @@ namespace OpenSim.Region.ScriptEngine.Yengine ~XMRInstArrays() { - heapUse = instance.UpdateHeapUse(heapUse, 0); + arraysHeapUse = instance.UpdateHeapUse(arraysHeapUse, 0); } - public void AllocVarArrays(XMRInstArSizes ars) + public void Clear() + { + int newheapUse = 0; + if(iarArrays != null) + { + foreach(XMR_Array xa in iarArrays) + xa.__pub_clear(); + } + if(iarChars != null) + iarChars = new char[iarChars.Length]; + if (iarLists != null) + iarLists = new LSL_List[iarLists.Length]; + if (iarObjects != null) + iarObjects = new object[iarObjects.Length]; + if(iarStrings != null) + iarStrings = new string[iarStrings.Length]; + if (iarFloats != null) + newheapUse += iarFloats.Length * HeapTrackerObject.HT_DOUB; + if (iarIntegers != null) + newheapUse += iarIntegers.Length * HeapTrackerObject.HT_INT; + if (iarRotations != null) + newheapUse += iarRotations.Length * HeapTrackerObject.HT_ROT; + if (iarVectors != null) + newheapUse += iarVectors.Length * HeapTrackerObject.HT_VEC; + + arraysHeapUse = instance.UpdateHeapUse(0, newheapUse); + } + + public void AllocVarArrays(XMRInstArSizes ars) { ClearOldArrays(); + int newuse = arraysHeapUse + + ars.iasChars* HeapTrackerObject.HT_CHAR + + ars.iasFloats * HeapTrackerObject.HT_SFLT + + ars.iasIntegers * HeapTrackerObject.HT_INT + + ars.iasRotations * HeapTrackerObject.HT_ROT + + ars.iasVectors * HeapTrackerObject.HT_VEC + + ars.iasSDTIntfObjs * HeapTrackerObject.HT_DELE; - heapUse = instance.UpdateHeapUse(heapUse, - ars.iasChars * HeapTrackerObject.HT_CHAR + - ars.iasFloats * HeapTrackerObject.HT_SFLT + - ars.iasIntegers * HeapTrackerObject.HT_INT + - ars.iasRotations * HeapTrackerObject.HT_ROT + - ars.iasVectors * HeapTrackerObject.HT_VEC + - ars.iasSDTIntfObjs * HeapTrackerObject.HT_DELE); + arraysHeapUse = instance.UpdateHeapUse(arraysHeapUse, newuse); iarArrays = (ars.iasArrays > 0) ? new XMR_Array[ars.iasArrays] : noArrays; iarChars = (ars.iasChars > 0) ? new char[ars.iasChars] : noChars; @@ -114,9 +143,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine */ public void PopList(int index, LSL_List lis) { - LSL_List old = iarLists[index]; - int newheapuse = heapUse + HeapTrackerList.Size(lis) - HeapTrackerList.Size(old); - heapUse = instance.UpdateHeapUse(heapUse, newheapuse); + int delta = HeapTrackerObject.Size(lis) - HeapTrackerObject.Size(iarLists[index]); + instance.UpdateHeapUse(0, delta); + Interlocked.Add(ref arraysHeapUse, delta); iarLists[index] = lis; } @@ -125,9 +154,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine */ public void PopObject(int index, object obj) { - object old = iarObjects[index]; - int newheapuse = heapUse + HeapTrackerObject.Size(obj) - HeapTrackerObject.Size(old); - heapUse = instance.UpdateHeapUse(heapUse, newheapuse); + int delta = HeapTrackerObject.Size(obj) - HeapTrackerObject.Size(iarObjects[index]); + instance.UpdateHeapUse(0, delta); + Interlocked.Add(ref arraysHeapUse, delta); iarObjects[index] = obj; } @@ -136,9 +165,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine */ public void PopString(int index, string str) { - string old = iarStrings[index]; - int newheapuse = heapUse + HeapTrackerString.Size(str) - HeapTrackerString.Size(old); - heapUse = instance.UpdateHeapUse(heapUse, newheapuse); + int delta = HeapTrackerString.Size(str) - HeapTrackerString.Size(iarStrings[index]); + instance.UpdateHeapUse(0, delta); + Interlocked.Add(ref arraysHeapUse, delta); iarStrings[index] = str; } @@ -181,11 +210,11 @@ namespace OpenSim.Region.ScriptEngine.Yengine iarSDTClObjs = (XMRSDTypeClObj[])recver(); Delegate[][] dels = (Delegate[][])recver(); - int newheapuse = heapUse; + int newheapuse = arraysHeapUse; // value types simply are the size of the value * number of values newheapuse += chrs.Length * HeapTrackerObject.HT_CHAR; - newheapuse += flts.Length * HeapTrackerObject.HT_SFLT; + newheapuse += flts.Length * HeapTrackerObject.HT_DOUB; newheapuse += ints.Length * HeapTrackerObject.HT_INT; newheapuse += rots.Length * HeapTrackerObject.HT_ROT; newheapuse += vecs.Length * HeapTrackerObject.HT_VEC; @@ -204,7 +233,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine // others (XMR_Array, XMRSDTypeClObj) keep track of their own heap usage // update script heap usage, throwing an exception before finalizing changes - heapUse = instance.UpdateHeapUse(heapUse, newheapuse); + arraysHeapUse = instance.UpdateHeapUse(arraysHeapUse, newheapuse); iarChars = chrs; iarFloats = flts; @@ -219,7 +248,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine private void ClearOldArrays() { - int newheapuse = heapUse; + int newheapuse = arraysHeapUse; iarArrays = null; if(iarChars != null) @@ -272,7 +301,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine iarSDTIntfObjs = null; } - heapUse = instance.UpdateHeapUse(heapUse, newheapuse); + arraysHeapUse = instance.UpdateHeapUse(arraysHeapUse, newheapuse); } } @@ -424,31 +453,13 @@ namespace OpenSim.Region.ScriptEngine.Yengine \**************************************************/ protected int heapLimit; - private int heapUsed; + protected int heapUsed; public virtual int UpdateHeapUse(int olduse, int newuse) { - if(newuse <= olduse) - Interlocked.Add(ref heapUsed, newuse - olduse); - else - { - int newtotal, oldtotal; - do - { - oldtotal = Interlocked.Add(ref heapUsed, 0); - newtotal = oldtotal + newuse - olduse; - if(newtotal > heapLimit) - { - // System.GC.Collect (); - // System.GC.WaitForPendingFinalizers (); - oldtotal = Interlocked.Add(ref heapUsed, 0); - newtotal = oldtotal + newuse - olduse; - if(newtotal > heapLimit) - throw new OutOfHeapException(oldtotal, newtotal, heapLimit); - } - } while(Interlocked.CompareExchange(ref heapUsed, newtotal, oldtotal) != oldtotal); - } - + int newtotal = Interlocked.Add(ref heapUsed, newuse - olduse); + if(newtotal > heapLimit) + throw new OutOfHeapException(newtotal + olduse - newuse, newtotal, heapLimit); return newuse; } diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs index 7fc97e9c1a..7ef1b9f08e 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs @@ -218,7 +218,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine // do not do llResetScript on entry if(eventCode == ScriptEventCode.state_entry && stateCode == 0) return; - ClearQueueExceptLinkMessages(); + // do clear the events queue on reset + ClearQueue(); + //ClearQueueExceptLinkMessages(); throw new ScriptResetException(); } @@ -583,6 +585,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine * Tell outer layers to cancel any event triggers, like llListen(), * then tell outer layers which events the new state has handlers for. * We also clear the event queue as per http://wiki.secondlife.com/wiki/State + * old scripts may want linked messages, but that is not as SL does now */ public override void StateChange() { @@ -595,7 +598,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine // Tell whoever cares which event handlers the new state has. m_Part.SetScriptEvents(m_ItemID, GetStateEventFlags(stateCode)); - // Clear out any old events from the queue. + // keep link messages + //ClearQueueExceptLinkMessages(); + // or Clear out all old events from the queue. lock(m_QueueLock) { m_EventQueue.Clear(); diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs index 12feb7b428..e97c71e85f 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstMisc.cs @@ -236,6 +236,13 @@ namespace OpenSim.Region.ScriptEngine.Yengine return GetScriptFileName(m_ScriptBasePath, filename); } + public string GetScriptILFileName(string filename) + { + string path = Path.Combine(m_ScriptBasePath, "DebugIL"); + Directory.CreateDirectory(path); + return Path.Combine(path, filename); + } + public static string GetScriptFileName(string scriptBasePath, string filename) { // Get old path, ie, all files lumped in a single huge directory. @@ -363,8 +370,33 @@ namespace OpenSim.Region.ScriptEngine.Yengine lock(m_QueueLock) { m_Running = value; - if(!value) + if(value) { + if (m_IState == XMRInstState.SUSPENDED && m_SuspendCount == 0) + { + if(eventCode != ScriptEventCode.None) + { + m_IState = XMRInstState.ONYIELDQ; + m_Engine.QueueToYield(this); + } + else if ((m_EventQueue != null) && (m_EventQueue.First != null)) + { + m_IState = XMRInstState.ONSTARTQ; + m_Engine.QueueToStart(this); + } + else + m_IState = XMRInstState.IDLE; + } + else if(m_SuspendCount != 0) + m_IState = XMRInstState.IDLE; + } + else + { + if(m_IState == XMRInstState.ONSLEEPQ) + { + m_Engine.RemoveFromSleep(this); + m_IState = XMRInstState.SUSPENDED; + } EmptyEventQueues(); } } diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs index 1b735e33de..987e22caca 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstRun.cs @@ -80,10 +80,21 @@ namespace OpenSim.Region.ScriptEngine.Yengine !m_HaveEventHandlers[(int)evc]) // don't bother if we don't have such a handler in any state return; - // Not running means we ignore any incoming events. - // But queue if still constructing because m_Running is not yet valid. + // Not running means we ignore any incoming events. + // But queue if still constructing because m_Running is not yet valid. + if(!m_Running && !construct) + { + if(m_IState == XMRInstState.SUSPENDED) + { + if(evc == ScriptEventCode.state_entry && m_EventQueue.Count == 0) + { + LinkedListNode llns = new LinkedListNode(evt); + m_EventQueue.AddFirst(llns); + } + } return; + } if(m_minEventDelay != 0) { @@ -250,13 +261,13 @@ namespace OpenSim.Region.ScriptEngine.Yengine return XMRInstState.SUSPENDED; } - // Make sure we aren't being migrated in or out and prevent that - // whilst we are in here. If migration has it locked, don't call - // back right away, delay a bit so we don't get in infinite loop. + // Make sure we aren't being migrated in or out and prevent that + // whilst we are in here. If migration has it locked, don't call + // back right away, delay a bit so we don't get in infinite loop. m_RunOnePhase = "lock m_RunLock"; if(!Monitor.TryEnter(m_RunLock)) { - m_SleepUntil = now.AddMilliseconds(3); + m_SleepUntil = now.AddMilliseconds(15); m_RunOnePhase = "return was locked"; return XMRInstState.ONSLEEPQ; } @@ -273,6 +284,12 @@ namespace OpenSim.Region.ScriptEngine.Yengine return XMRInstState.DISPOSED; } + if(!m_Running) + { + m_RunOnePhase = "return is not running"; + return XMRInstState.SUSPENDED; + } + // Do some more of the last event if it didn't finish. if(this.eventCode != ScriptEventCode.None) { @@ -325,10 +342,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine if(m_EventQueue.First != null) { evt = m_EventQueue.First.Value; - if(m_DetachQuantum > 0) + evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName); + if (m_DetachQuantum > 0) { - evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), - evt.EventName); if(evc != ScriptEventCode.attach) { // This is the case where the attach event @@ -343,8 +359,6 @@ namespace OpenSim.Region.ScriptEngine.Yengine } } m_EventQueue.RemoveFirst(); - evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), - evt.EventName); if((int)evc >= 0) m_EventCounts[(int)evc]--; } @@ -730,11 +744,14 @@ namespace OpenSim.Region.ScriptEngine.Yengine case XMRInstState.DISPOSED: return; - // Some other thread is already resetting it, let it finish. + // Some other thread is already resetting it, let it finish. case XMRInstState.RESETTING: return; + case XMRInstState.SUSPENDED: + break; + default: throw new Exception("bad state"); } @@ -744,17 +761,21 @@ namespace OpenSim.Region.ScriptEngine.Yengine { CheckRunLockInvariants(true); - // No other thread should have transitioned it from RESETTING. - if(m_IState != XMRInstState.RESETTING) - throw new Exception("bad state"); + // No other thread should have transitioned it from RESETTING. + if (m_IState != XMRInstState.SUSPENDED) + { + if (m_IState != XMRInstState.RESETTING) + throw new Exception("bad state"); - // Mark it idle now so it can get queued to process new stuff. - m_IState = XMRInstState.IDLE; + m_IState = XMRInstState.IDLE; + } - // Reset everything and queue up default's start_entry() event. + // Reset everything and queue up default's start_entry() event. ClearQueue(); ResetLocked("external Reset"); + // Mark it idle now so it can get queued to process new stuff. + CheckRunLockInvariants(true); } } @@ -820,6 +841,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine m_SleepUntil = DateTime.MinValue; // not doing llSleep() m_ResetCount++; // has been reset once more + heapUsed = 0; + glblVars.Clear(); + // Tell next call to 'default state_entry()' to reset all global // vars to their initial values. doGblInit = true; @@ -827,7 +851,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine // Throw away all its stack frames. // If the script is resetting itself, there shouldn't be any stack frames. // If the script is being reset by something else, we throw them away cuz we want to start from the beginning of an event handler. - stackFrames = null; + stackFrames = null; // Set script to 'default' state and queue call to its // 'state_entry()' event handler. @@ -937,7 +961,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine lock(m_QueueLock) { m_Suspended = false; - if((m_EventQueue != null) && + m_DetachQuantum = 0; + m_DetachReady.Set(); + if ((m_EventQueue != null) && (m_EventQueue.First != null) && (m_IState == XMRInstState.IDLE)) { diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs index 08c7e80c92..f68fd51cd1 100644 --- a/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs +++ b/OpenSim/Region/ScriptEngine/YEngine/XMRScriptThread.cs @@ -166,7 +166,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine if(inst == null) break; - if(inst.m_IState != XMRInstState.ONSTARTQ) + if (inst.m_IState == XMRInstState.SUSPENDED) + continue; + if (inst.m_IState != XMRInstState.ONSTARTQ) throw new Exception("bad state"); RunInstance(inst, tid); if(m_SuspendScriptThreadFlag || m_Exiting) @@ -187,7 +189,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine if(inst != null) { - if(inst.m_IState != XMRInstState.ONYIELDQ) + if (inst.m_IState == XMRInstState.SUSPENDED) + continue; + if (inst.m_IState != XMRInstState.ONYIELDQ) throw new Exception("bad state"); RunInstance(inst, tid); continue; diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index 900327a792..422a8bce18 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -250,6 +250,8 @@ namespace OpenSim.Server.Base } } + MainServer.Stop(); + MemoryWatchdog.Enabled = false; Watchdog.Enabled = false; WorkManager.Stop(); diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index b636a7b269..b12ea62efc 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -510,7 +510,7 @@ namespace OpenSim.Services.Connectors try { newID = SynchronousRestObjectRequester. - MakeRequest("POST", uri, asset, 100000, m_Auth); + MakeRequest("POST", uri, asset, 10000, m_Auth); } catch { diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 4fd1fe54e3..e15ac8c47b 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -99,15 +99,8 @@ namespace OpenSim.Services.Connectors.Simulation } public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, EntityTransferContext ctx, out string reason) - { - string tmp = String.Empty; - return CreateAgent(source, destination, aCircuit, flags, ctx, out tmp, out reason); - } - - public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, EntityTransferContext ctx, out string myipaddress, out string reason) { reason = String.Empty; - myipaddress = String.Empty; if (destination == null) { @@ -134,7 +127,6 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); - myipaddress = data["your_ip"].AsString(); return success; } @@ -149,7 +141,6 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); - myipaddress = data["your_ip"].AsString(); m_log.WarnFormat( "[REMOTE SIMULATION CONNECTOR]: Remote simulator {0} did not accept compressed transfer, suggest updating it.", destination.RegionName); return success; diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 6f2cdd5e99..bfa97a157c 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -73,6 +73,7 @@ namespace OpenSim.Services.HypergridService protected static FriendsSimConnector m_FriendsSimConnector; // grid protected static string m_GridName; + protected static string m_MyExternalIP = ""; protected static int m_LevelOutsideContacts; protected static bool m_ShowDetails; @@ -147,9 +148,20 @@ namespace OpenSim.Services.HypergridService } } - if (!m_GridName.EndsWith("/")) - m_GridName = m_GridName + "/"; - + if (!string.IsNullOrEmpty(m_GridName)) + { + m_GridName = m_GridName.ToLowerInvariant(); + if (!m_GridName.EndsWith("/")) + m_GridName = m_GridName + "/"; + Uri gateURI; + if(!Uri.TryCreate(m_GridName, UriKind.Absolute, out gateURI)) + throw new Exception(String.Format("[UserAgentService] could not parse gatekeeper uri")); + string host = gateURI.DnsSafeHost; + IPAddress ip = Util.GetHostFromDNS(host); + if(ip == null) + throw new Exception(String.Format("[UserAgentService] failed to resolve gatekeeper host")); + m_MyExternalIP = ip.ToString(); + } // Finally some cleanup m_Database.DeleteOld(); @@ -189,7 +201,6 @@ namespace OpenSim.Services.HypergridService } } - public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt) { position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY; @@ -222,7 +233,7 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}", agentCircuit.firstname, agentCircuit.lastname, (fromLogin ? agentCircuit.IPAddress : "stored IP"), gatekeeper.ServerURI); - string gridName = gatekeeper.ServerURI; + string gridName = gatekeeper.ServerURI.ToLowerInvariant(); UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, agentCircuit.AgentID); if (account == null) @@ -269,8 +280,13 @@ namespace OpenSim.Services.HypergridService TravelingAgentInfo old = null; TravelingAgentInfo travel = CreateTravelInfo(agentCircuit, region, fromLogin, out old); + if(!fromLogin && old != null && !string.IsNullOrEmpty(old.ClientIPAddress)) + { + m_log.DebugFormat("[USER AGENT SERVICE]: stored IP = {0}. Old circuit IP: {1}", old.ClientIPAddress, agentCircuit.IPAddress); + agentCircuit.IPAddress = old.ClientIPAddress; + } + bool success = false; - string myExternalIP = string.Empty; m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}, desired region: {2}", m_GridName, gridName, region.RegionID); @@ -282,7 +298,7 @@ namespace OpenSim.Services.HypergridService { //TODO: Should there not be a call to QueryAccess here? EntityTransferContext ctx = new EntityTransferContext(); - success = m_GatekeeperConnector.CreateAgent(source, region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, ctx, out myExternalIP, out reason); + success = m_GatekeeperConnector.CreateAgent(source, region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, ctx, out reason); } if (!success) @@ -300,14 +316,6 @@ namespace OpenSim.Services.HypergridService // Everything is ok - if (!fromLogin) - { - // Update the perceived IP Address of our grid - m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); - } - - travel.MyIpAddress = myExternalIP; - StoreTravelInfo(travel); return true; @@ -384,10 +392,12 @@ namespace OpenSim.Services.HypergridService TravelingAgentInfo travel = new TravelingAgentInfo(hgt); - bool result = travel.ClientIPAddress == reportedIP || travel.MyIpAddress == reportedIP; // NATed + bool result = travel.ClientIPAddress == reportedIP; + if(!result && !string.IsNullOrEmpty(m_MyExternalIP)) + result = reportedIP == m_MyExternalIP; // NATed - m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}", - reportedIP, travel.ClientIPAddress, travel.MyIpAddress, result); + m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {2}; result is {3}", + reportedIP, travel.ClientIPAddress, m_MyExternalIP, result); return result; } @@ -704,7 +714,6 @@ namespace OpenSim.Services.HypergridService hgt.Data["GridExternalName"] = travel.GridExternalName; hgt.Data["ServiceToken"] = travel.ServiceToken; hgt.Data["ClientIPAddress"] = travel.ClientIPAddress; - hgt.Data["MyIPAddress"] = travel.MyIpAddress; m_Database.Store(hgt); } @@ -719,7 +728,6 @@ namespace OpenSim.Services.HypergridService public string GridExternalName = string.Empty; public string ServiceToken = string.Empty; public string ClientIPAddress = string.Empty; // as seen from this user agent service - public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper public TravelingAgentInfo(HGTravelingData t) { @@ -730,7 +738,6 @@ namespace OpenSim.Services.HypergridService GridExternalName = t.Data["GridExternalName"]; ServiceToken = t.Data["ServiceToken"]; ClientIPAddress = t.Data["ClientIPAddress"]; - MyIpAddress = t.Data["MyIPAddress"]; } } @@ -743,7 +750,6 @@ namespace OpenSim.Services.HypergridService GridExternalName = old.GridExternalName; ServiceToken = old.ServiceToken; ClientIPAddress = old.ClientIPAddress; - MyIpAddress = old.MyIpAddress; } } } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index de9ab98779..fd14291241 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -369,6 +369,8 @@ namespace OpenSim.Tests.Common set { } } + public float StartFar { get; set; } + public virtual UUID AgentId { get { return m_agentId; } @@ -576,10 +578,6 @@ namespace OpenSim.Tests.Common { } - public virtual void SendStartPingCheck(byte seq) - { - } - public virtual void SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData, List Data) { } @@ -821,7 +819,8 @@ namespace OpenSim.Tests.Common { } - public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory) + public virtual void SendXferPacket(ulong xferID, uint packet, + byte[] XferData, int XferDataOffset, int XferDatapktLen, bool isTaskInventory) { } @@ -880,7 +879,7 @@ namespace OpenSim.Tests.Common { } - public virtual void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) + public virtual void SendRegionHandshake() { if (OnRegionHandShakeReply != null) { @@ -1402,7 +1401,10 @@ namespace OpenSim.Tests.Common { } - public void CheckViewerCaps() { } + public uint GetViewerCaps() + { + return 0x1000; + } } } diff --git a/OpenSim/Tests/Common/Mock/TestLandChannel.cs b/OpenSim/Tests/Common/Mock/TestLandChannel.cs index cb16f55edd..b5227aa5df 100644 --- a/OpenSim/Tests/Common/Mock/TestLandChannel.cs +++ b/OpenSim/Tests/Common/Mock/TestLandChannel.cs @@ -119,6 +119,6 @@ namespace OpenSim.Tests.Common public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) {} public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) {} - public void sendClientInitialLandInfo(IClientAPI remoteClient) { } + public void sendClientInitialLandInfo(IClientAPI remoteClient, bool overlay) { } } } \ No newline at end of file diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 8b77ee9033..7db75063a8 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -927,14 +927,10 @@ [YEngine] ;; experimental engine - ;; ONLY SUPORTS ONE REGION PER INSTANCE at this point ;; implements non preemptive microthreading, so fixing problems like llSleep or long events handlers ;; but those will suffer from timeslicing, so will be slower. - ;; compiles LSL directly to IL, so only suports LSL scripting (no C# etc) - ;; shares the Xengine APIs like LSL, OSSL, etc. - ;; DANGER, do not use with HG, don't leave regions running alone with it. - ;; TPs or crossings to/from Xengine will full recompile scripts losing state. - ;; attachment scripts may misbehave, cars will stop on crossings, etc. + ;; warning: scripts state is lost on TP or cross to Xengine regions (cars stop, etc) + ;; ignore its extensions (subset of original XMRengine), those are still undefined. Enabled = false ScriptStackSize = 256 ScriptHeapSize = 256 diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index cede84d25b..1332ce81b2 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -164,15 +164,10 @@ ; limit the maximum view range ( no effect still (does limit MaxRegionsViewDistance) ) ;MaxDrawDistance = 512 - ; the maximum distance to tell a viewer to connect to a neighbour region, so it can be seen - ; (it is limited by MaxDrawDistance above) - ; less than 256 shows immediate neighbours; 256 to 511 also second imediate neighbours etc - ; more than 511m can cause viewers problems specially in case of dense regions. - ; curretly this distance is from current region borders. - ; Warning: if relevant regions have different setting you may notice strange - ; effects due to that asymmetry - ; ***** + ; Other regions visibility depends on avatar position and view range + ; the view range considered is limited the maximum and minimum distances: ;MaxRegionsViewDistance = 255 + ;MinRegionsViewDistance = 96 ; If you have only one region in an instance, or to avoid the many bugs ; that you can trigger in modules by restarting a region, set this to @@ -454,7 +449,7 @@ ; warp3D rendering height limits for prims (relative to rez position not bounding box) ; prims above RenderMaxHeight are excluded - ; valid values: 100 t0 4086 + ; valid values: 100 to 4086 ;RenderMaxHeight = 4086 ; prims below RenderMinHeight are excluded @@ -690,23 +685,6 @@ [ClientStack.LindenUDP] - ; The client socket receive buffer size determines how many - ; incoming requests we can process; the default on .NET is 8192 - ; which is about 2 4k-sized UDP datagrams. On mono this is - ; whatever the underlying operating system has as default; for - ; example, ubuntu 8.04 or SLES11 have about 111k, which is about - ; 27 4k-sized UDP datagrams (on linux platforms you can [as root] - ; do "sysctl net.core.rmem_default" to find out what your system - ; uses a default socket receive buffer size. - ; - ; client_socket_rcvbuf_size allows you to specify the receive - ; buffer size LLUDPServer should use. NOTE: this will be limited - ; by the system's settings for the maximum client receive buffer - ; size (on linux systems you can set that with "sysctl -w - ; net.core.rmem_max=X") - ; - ;client_socket_rcvbuf_size = 8388608 - ; Maximum outbound bytes per second for a single scene. This can be used to ; throttle total outbound UDP traffic for a simulator. The default value is ; 0, meaning no throttling at the scene level. The example given here is @@ -731,8 +709,8 @@ ; Adaptive throttling attempts to limit network overload when multiple ; clients login by starting each connection more slowly. Disabled by ; default - ; - enable_adaptive_throttles = false + ; currently disabled + ;enable_adaptive_throttles = false ; Per-client bytes per second rates for the various throttle categories. ; These are default values that will be overridden by clients. These @@ -748,7 +726,7 @@ ;asset_default = 10500 ; TextureSendLimit determines how many packets will be put on - ; the outgoing queue each cycle. Like the settings above, this + ; the lludp outgoing queue each cycle. Like the settings above, this ; is a balance between responsiveness to priority updates and ; total throughput. Higher numbers will give a better ; throughput at the cost of reduced responsiveness to client @@ -776,6 +754,11 @@ ; ;PausedAckTimeout = 300 + ; Support viewers object cache, default true + ; users may need to reduce viewer bandwitdh if some prims or terrain parts fail to rez. + ; change to false if you need to use old viewers that do not support this feature + ; + ; SupportViewerObjectsCache = true [ClientStack.LindenCaps] ;; Long list of capabilities taken from @@ -1729,17 +1712,12 @@ [Economy] ; the economy module in use ; default is the provided BetaGridLikeMoneyModule - ; - This module is for demonstration only - ; The default economy module only implements just enough to allow free actions (transfer of objects, etc). ; There is no intention to implement anything further in core OpenSimulator. ; This functionality has to be provided by third party modules. - ; To use other modules you need to override this setting on OpenSim.ini Economy (or startup) section ; economymodule = BetaGridLikeMoneyModule - ; These economy values get used in the BetaGridLikeMoneyModule. - This module is for demonstration only - - ; The default economy module only implements just enough to allow free actions (transfer of objects, etc). - ; There is no intention to implement anything further in core OpenSimulator. - ; This functionality has to be provided by third party modules. + ; Economy values get used in the BetaGridLikeMoneyModule. ;; Enables selling things for $0. Default is true. ; SellEnabled = true @@ -1767,6 +1745,14 @@ ;PriceObjectRent = 0 ;PriceObjectScaleFactor = 10 ;PriceParcelRent = 0 + + ; Mesh upload settings, independent of economymodule + + ; Create inventory entries for textures uploaded with a model + ; default is false, ie, do not create + ; MeshModelAllowTextureToInventory = true + + [XEngine] ; Enable this engine in this OpenSim instance diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 0f9bb4b27b..726e468304 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -568,6 +568,8 @@ ;; ;; To turn off basic dos protection, set the DOSMaxRequestsInTimeFrame to 0. + ;; Allow banning via hashed MAC must be set in both [GatekeeperService] and [LoginService] + ;DeniedMacs = "YOURLONGMACTRSING ANOTHERMAC" [MapImageService] LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" @@ -663,6 +665,8 @@ ;; Leave blank or commented for no exceptions. ; DisallowExcept = "http://myfriendgrid.com:8002, http://myboss.com:8002" + ;; Allow banning via hashed MAC must be set in both [GatekeeperService] and [LoginService] + ;DeniedMacs = "YOURLONGMACTRSING ANOTHERMAC" [UserAgentService] LocalServiceModule = "OpenSim.Services.HypergridService.dll:UserAgentService" diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 3222a94ad1..50986de847 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -495,6 +495,8 @@ ;; ;; To turn off basic dos protection, set the DOSMaxRequestsInTimeFrame to 0. + ;; Allow banning via hashed MAC + ;DeniedMacs = "YOURLONGMACTRSING ANOTHERMAC" [MapImageService] LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" diff --git a/bin/ScriptSyntax.xml b/bin/ScriptSyntax.xml index 8f2f6002f9..2282adaea1 100644 --- a/bin/ScriptSyntax.xml +++ b/bin/ScriptSyntax.xml @@ -1,4 +1,4 @@ -20392e48-fad2-094e-bc5b-cda003a1e940 +24121ec8-c0a3-099d-8d83-64feaa32418c llsd-lsl-syntax-version2 controls @@ -1513,7 +1513,7 @@ OS_APIVERSION typeinteger - value3 + value4 OS_ATTACH_MSG_ALL typeinteger @@ -1539,6 +1539,36 @@ typeinteger value0x1 + OS_LTPAG_ALGNLV + typeinteger + value0x4 + tooltiposLocalTeleportAgent align lookat to velocity + + OS_LTPAG_FORCEFLY + typeinteger + value0x8 + tooltiposLocalTeleportAgent force fly + + OS_LTPAG_FORCENOFLY + typeinteger + value0x16 + tooltiposLocalTeleportAgent force no fly + + OS_LTPAG_NONE + typeinteger + value0x0 + tooltiposLocalTeleportAgent no flags + + OS_LTPAG_USELOOKAT + typeinteger + value0x2 + tooltiposLocalTeleportAgent use lookat + + OS_LTPAG_USEVEL + typeinteger + value0x1 + tooltiposLocalTeleportAgent use velocity + OS_NPC_CREATOR_OWNED typeinteger value0x1 @@ -6119,6 +6149,14 @@ osApproxEquals + + returninteger + arguments + vatypevector + vbtypevector + + + osApproxEquals returninteger arguments @@ -6136,15 +6174,6 @@ osApproxEquals - - returninteger - arguments - vatypevector - vbtypevector - margintypefloat - - - osApproxEquals returninteger arguments @@ -6159,6 +6188,7 @@ arguments vatypevector vbtypevector + margintypefloat osAvatarName2Key @@ -6653,6 +6683,11 @@ rulestypelist + osGetPSTWallclock + + returnfloat + arguments + osGetRegionMapTexture returnkey @@ -6776,6 +6811,16 @@ returnstring arguments + osLocalTeleportAgent + + arguments + agenttypekey + positiontypevector + velocitytypevector + lookattypevector + flagstypeinteger + + osLoopSound arguments @@ -6865,6 +6910,7 @@ nametypestring positiontypevector notecardtypestring + optionstypeinteger osNpcCreate @@ -6875,7 +6921,6 @@ nametypestring positiontypevector notecardtypestring - optionstypeinteger osNpcGetOwner @@ -7354,6 +7399,17 @@ osSetProjectionParams + + arguments + linknumbertypeinteger + projectiontypeinteger + texturetypekey + fovtypefloat + focustypefloat + ambtypefloat + + + osSetProjectionParams arguments primtypekey @@ -7525,6 +7581,7 @@ arguments srctypestring starttypeinteger + lengthtypeinteger osStringSubString @@ -7533,7 +7590,6 @@ arguments srctypestring starttypeinteger - lengthtypeinteger osSunGetParam @@ -7551,6 +7607,23 @@ osTeleportAgent + + arguments + agenttypestring + regionNametypestring + positiontypevector + lookattypevector + + + osTeleportAgent + + arguments + agenttypestring + positiontypevector + lookattypevector + + + osTeleportAgent arguments agenttypestring @@ -7560,23 +7633,6 @@ lookattypevector - osTeleportAgent - - arguments - agenttypestring - positiontypevector - lookattypevector - - - osTeleportAgent - - arguments - agenttypestring - regionNametypestring - positiontypevector - lookattypevector - - osTeleportObject returninteger @@ -7597,7 +7653,8 @@ osTeleportOwner arguments - regionNametypestring + regionXtypeinteger + regionYtypeinteger positiontypevector lookattypevector @@ -7605,8 +7662,7 @@ osTeleportOwner arguments - regionXtypeinteger - regionYtypeinteger + regionNametypestring positiontypevector lookattypevector diff --git a/bin/Warp3D.dll b/bin/Warp3D.dll index 523d67f95c..055b8bcf0f 100755 Binary files a/bin/Warp3D.dll and b/bin/Warp3D.dll differ diff --git a/runprebuild.bat b/runprebuild.bat index e2b68326b5..0bee6f5781 100755 --- a/runprebuild.bat +++ b/runprebuild.bat @@ -5,21 +5,26 @@ bin\Prebuild.exe /target vs2015 setlocal ENABLEEXTENSIONS set VALUE_NAME=MSBuildToolsPath - -rem try find vs2017 if "%PROCESSOR_ARCHITECTURE%"=="x86" set PROGRAMS=%ProgramFiles% if defined ProgramFiles(x86) set PROGRAMS=%ProgramFiles(x86)% +rem Try to find VS2019 for %%e in (Enterprise Professional Community) do ( + if exist "%PROGRAMS%\Microsoft Visual Studio\2019\%%e\MSBuild\Current\Bin\MSBuild.exe" ( - if exist "%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe" ( - - set ValueValue="%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\" + set ValueValue="%PROGRAMS%\Microsoft Visual Studio\2019\%%e\MSBuild\Current\Bin\MSBuild" goto :found ) - ) +rem try find vs2017 +for %%e in (Enterprise Professional Community) do ( + if exist "%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild.exe" ( + + set ValueValue="%PROGRAMS%\Microsoft Visual Studio\2017\%%e\MSBuild\15.0\Bin\MSBuild" + goto :found + ) +) rem We have to use grep or find to locate the correct line, because reg query spits rem out 4 lines before Windows 7 but 2 lines after Windows 7. @@ -35,7 +40,7 @@ if defined FOUNDGREP ( rem try vs2015 FOR /F "usebackq tokens=1-3" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0" /v %VALUE_NAME% 2^>nul ^| %FINDCMD% "%VALUE_NAME%"`) DO ( - set ValueValue=%%C + set ValueValue=%%C\msbuild goto :found ) @@ -49,6 +54,8 @@ goto :done :found @echo Found msbuild at %ValueValue% @echo Creating compile.bat - @echo %ValueValue%\msbuild opensim.sln > compile.bat - +rem To compile in debug mode + @echo %ValueValue% opensim.sln > compile.bat +rem To compile in release mode comment line (add rem to start) above and uncomment next (remove rem) +rem @echo %ValueValue% /P:Config=Release opensim.sln > compile.bat :done \ No newline at end of file