diff --git a/OpenSim/Framework/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs new file mode 100644 index 0000000000..239fc566a9 --- /dev/null +++ b/OpenSim/Framework/CachedTextureEventArg.cs @@ -0,0 +1,46 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public class CachedTextureRequestArg + { + public int BakedTextureIndex; + public UUID WearableHashID; + } + + public class CachedTextureResponseArg + { + public int BakedTextureIndex; + public UUID BakedTextureID; + public String HostName; + } +} diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c88828b73a..9631a4625b 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -65,6 +65,7 @@ namespace OpenSim.Framework public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems); + public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List cachedTextureRequest); public delegate void StartAnim(IClientAPI remoteClient, UUID animID); @@ -789,6 +790,7 @@ namespace OpenSim.Framework event EstateChangeInfo OnEstateChangeInfo; event EstateManageTelehub OnEstateManageTelehub; // [Obsolete("LLClientView Specific.")] + event CachedTextureRequest OnCachedTextureRequest; event SetAppearance OnSetAppearance; // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] event AvatarNowWearing OnAvatarNowWearing; @@ -1100,6 +1102,8 @@ namespace OpenSim.Framework /// void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); + void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures); + void SendStartPingCheck(byte seq); /// diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 800488dd5e..17b59da508 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event ModifyTerrain OnModifyTerrain; public event Action OnRegionHandShakeReply; public event GenericCall1 OnRequestWearables; + public event CachedTextureRequest OnCachedTextureRequest; public event SetAppearance OnSetAppearance; public event AvatarNowWearing OnAvatarNowWearing; public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; @@ -11707,8 +11708,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } /// - /// Send a response back to a client when it asks the asset server (via the region server) if it has - /// its appearance texture cached. /// /// /// At the moment, we always reply that there is no cached texture. @@ -11716,6 +11715,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// /// + // TODO: Convert old handler to use new method + /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) + { + AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; + + if (cachedtex.AgentData.SessionID != SessionId) + return false; + + + List requestArgs = new List(); + + for (int i = 0; i < cachedtex.WearableData.Length; i++) + { + CachedTextureRequestArg arg = new CachedTextureRequestArg(); + arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex; + arg.WearableHashID = cachedtex.WearableData[i].ID; + + requestArgs.Add(arg); + } + + CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; + if (handlerCachedTextureRequest != null) + { + handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); + } + + return true; + }*/ + protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) { //m_log.Debug("texture cached: " + packet.ToString()); @@ -11874,6 +11902,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } + /// + /// Send a response back to a client when it asks the asset server (via the region server) if it has + /// its appearance texture cached. + /// + /// + /// + /// + /// + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + ScenePresence presence = avatar as ScenePresence; + if (presence == null) + return; + + AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); + + // TODO: don't create new blocks if recycling an old packet + cachedresp.AgentData.AgentID = m_agentId; + cachedresp.AgentData.SessionID = m_sessionId; + cachedresp.AgentData.SerialNum = serial; + cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count]; + + for (int i = 0; i < cachedTextures.Count; i++) + { + cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); + cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex; + cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID; + cachedresp.WearableData[i].HostName = new byte[0]; + } + + cachedresp.Header.Zerocoded = true; + OutPacket(cachedresp, ThrottleOutPacketType.Task); + } + protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) { MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index bc79944f90..09cc9983a8 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -55,6 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory private int m_savetime = 5; // seconds to wait before saving changed appearance private int m_sendtime = 2; // seconds to wait before sending changed appearance + private bool m_reusetextures = false; private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); @@ -73,6 +74,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory { m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); + m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures); + // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); } @@ -131,6 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory client.OnRequestWearables += Client_OnRequestWearables; client.OnSetAppearance += Client_OnSetAppearance; client.OnAvatarNowWearing += Client_OnAvatarNowWearing; + client.OnCachedTextureRequest += Client_OnCachedTextureRequest; } #endregion @@ -1068,6 +1072,61 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory QueueAppearanceSave(client.AgentId); } } + + /// + /// Respond to the cached textures request from the client + /// + /// + /// + /// + private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List cachedTextureRequest) + { + // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); + ScenePresence sp = m_scene.GetScenePresence(client.AgentId); + + List cachedTextureResponse = new List(); + foreach (CachedTextureRequestArg request in cachedTextureRequest) + { + UUID texture = UUID.Zero; + int index = request.BakedTextureIndex; + + if (m_reusetextures) + { + // this is the most insanely dumb way to do this... however it seems to + // actually work. if the appearance has been reset because wearables have + // changed then the texture entries are zero'd out until the bakes are + // uploaded. on login, if the textures exist in the cache (eg if you logged + // into the simulator recently, then the appearance will pull those and send + // them back in the packet and you won't have to rebake. if the textures aren't + // in the cache then the intial makeroot() call in scenepresence will zero + // them out. + // + // a better solution (though how much better is an open question) is to + // store the hashes in the appearance and compare them. Thats's coming. + + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; + if (face != null) + texture = face.TextureID; + + // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index); + } + + CachedTextureResponseArg response = new CachedTextureResponseArg(); + response.BakedTextureIndex = index; + response.BakedTextureID = texture; + response.HostName = null; + + cachedTextureResponse.Add(response); + } + + // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial); + // The serial number appears to be used to match requests and responses + // in the texture transaction. We just send back the serial number + // that was provided in the request. The viewer bumps this for us. + client.SendCachedTextureResponse(sp, serial, cachedTextureResponse); + } + + #endregion public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs index 948c8934a9..73e706c339 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs @@ -136,15 +136,18 @@ namespace OpenSim.Region.CoreModules.World.Estate // Handle local regions locally // - foreach (Scene s in m_EstateModule.Scenes) + lock (m_EstateModule.Scenes) { - if (regions.Contains(s.RegionInfo.RegionID)) + foreach (Scene s in m_EstateModule.Scenes) { - // All regions in one estate are in the same scope. - // Use that scope. - // - ScopeID = s.RegionInfo.ScopeID; - regions.Remove(s.RegionInfo.RegionID); + if (regions.Contains(s.RegionInfo.RegionID)) + { + // All regions in one estate are in the same scope. + // Use that scope. + // + ScopeID = s.RegionInfo.ScopeID; + regions.Remove(s.RegionInfo.RegionID); + } } } diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs index 1f099c61ad..f54ab2c13e 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs @@ -93,7 +93,8 @@ namespace OpenSim.Region.CoreModules.World.Estate public void AddRegion(Scene scene) { - m_Scenes.Add(scene); + lock (m_Scenes) + m_Scenes.Add(scene); scene.EventManager.OnNewClient += OnNewClient; } @@ -111,7 +112,8 @@ namespace OpenSim.Region.CoreModules.World.Estate { scene.EventManager.OnNewClient -= OnNewClient; - m_Scenes.Remove(scene); + lock (m_Scenes) + m_Scenes.Remove(scene); } public string Name diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 686c605d77..550f089d97 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -660,6 +660,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server public event BakeTerrain OnBakeTerrain; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event SetAppearance OnSetAppearance; public event AvatarNowWearing OnAvatarNowWearing; public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; @@ -943,7 +944,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server { } + + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + } + public void SendStartPingCheck(byte seq) { diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 7918c224fb..d1bb5472d3 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -393,6 +393,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; @@ -573,6 +574,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + + } + public virtual void Kick(string message) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index e7c1633c76..32f6a6480d 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -198,6 +198,7 @@ namespace OpenSim.Tests.Common.Mock public event EstateCovenantRequest OnEstateCovenantRequest; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; @@ -512,6 +513,11 @@ namespace OpenSim.Tests.Common.Mock { } + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + + } + public virtual void Kick(string message) { } diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 60e4be2743..a5a43b1c86 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -679,6 +679,9 @@ ; in other situations (e.g. appearance baking failures where the avatar only appears as a cloud to others). ResendAppearanceUpdates = true + ; Turning this on responds to CachedTexture packets to possibly avoid rebaking the avatar + ; on every login + ReuseTextures = false [Attachments] ; Controls whether avatar attachments are enabled.