aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs1610
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs746
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs521
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs110
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs14
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs144
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs329
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs412
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs22
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs297
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs14
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs17
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs203
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs101
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs3435
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs388
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs778
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs87
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs139
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs47
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs75
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs27
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs405
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs21
-rw-r--r--OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs8
37 files changed, 6198 insertions, 3849 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs
index aabdb51..8f65a69 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs
@@ -133,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenCaps
133 { 133 {
134 data = new AgentPrefs(agent); 134 data = new AgentPrefs(agent);
135 } 135 }
136 136
137 if (req.ContainsKey("access_prefs")) 137 if (req.ContainsKey("access_prefs"))
138 { 138 {
139 OSDMap accessPrefs = (OSDMap)req["access_prefs"]; // We could check with ContainsKey... 139 OSDMap accessPrefs = (OSDMap)req["access_prefs"]; // We could check with ContainsKey...
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
index bbadc55..e3c430c 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs
@@ -53,7 +53,7 @@ namespace OpenSim.Region.ClientStack.Linden
53 public class AvatarPickerSearchModule : INonSharedRegionModule 53 public class AvatarPickerSearchModule : INonSharedRegionModule
54 { 54 {
55// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56 56
57 private Scene m_scene; 57 private Scene m_scene;
58 private IPeople m_People; 58 private IPeople m_People;
59 private bool m_Enabled = false; 59 private bool m_Enabled = false;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 774202e..6f5775a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -26,11 +26,14 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Timers;
29using System.Collections; 30using System.Collections;
30using System.Collections.Generic; 31using System.Collections.Generic;
32using System.Collections.Specialized;
31using System.IO; 33using System.IO;
32using System.Reflection; 34using System.Reflection;
33using System.Text; 35using System.Text;
36using System.Web;
34 37
35using OpenMetaverse; 38using OpenMetaverse;
36using OpenMetaverse.StructuredData; 39using OpenMetaverse.StructuredData;
@@ -40,11 +43,11 @@ using log4net;
40using OpenSim.Framework; 43using OpenSim.Framework;
41using OpenSim.Framework.Capabilities; 44using OpenSim.Framework.Capabilities;
42using OpenSim.Region.Framework; 45using OpenSim.Region.Framework;
46using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes; 47using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization; 48using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Framework.Servers; 49using OpenSim.Framework.Servers;
46using OpenSim.Framework.Servers.HttpServer; 50using OpenSim.Framework.Servers.HttpServer;
47using OpenSim.Framework.Client;
48using OpenSim.Services.Interfaces; 51using OpenSim.Services.Interfaces;
49 52
50using Caps = OpenSim.Framework.Capabilities.Caps; 53using Caps = OpenSim.Framework.Capabilities.Caps;
@@ -55,14 +58,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
55namespace OpenSim.Region.ClientStack.Linden 58namespace OpenSim.Region.ClientStack.Linden
56{ 59{
57 public delegate void UpLoadedAsset( 60 public delegate void UpLoadedAsset(
58 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 61 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
59 byte[] data, string inventoryType, string assetType); 62 byte[] data, string inventoryType, string assetType,
63 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
64 bool IsAtestUpload, ref string error, ref int nextOwnerMask, ref int groupMask, ref int everyoneMask);
60 65
61 public delegate UUID UpdateItem(UUID itemID, byte[] data); 66 public delegate UUID UpdateItem(UUID itemID, byte[] data);
62 67
63 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 68 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
64 69
65 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 70 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
66 71
67 public delegate void NewAsset(AssetBase asset); 72 public delegate void NewAsset(AssetBase asset);
68 73
@@ -87,21 +92,12 @@ namespace OpenSim.Region.ClientStack.Linden
87 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 92 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
88 93
89 private Scene m_Scene; 94 private Scene m_Scene;
95 private UUID m_AgentID;
90 private Caps m_HostCapsObj; 96 private Caps m_HostCapsObj;
97 private ModelCost m_ModelCost;
91 98
92 private static readonly string m_requestPath = "0000/";
93 // private static readonly string m_mapLayerPath = "0001/";
94 private static readonly string m_newInventory = "0002/";
95 //private static readonly string m_requestTexture = "0003/";
96 private static readonly string m_notecardUpdatePath = "0004/";
97 private static readonly string m_notecardTaskUpdatePath = "0005/";
98 // private static readonly string m_fetchInventoryPath = "0006/";
99 private static readonly string m_copyFromNotecardPath = "0007/";
100 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 99 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
101 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 100
102 /* 0102 - 0103 RESERVED */
103 private static readonly string m_UpdateAgentInformationPath = "0500/";
104
105 // These are callbacks which will be setup by the scene so that we can update scene data when we 101 // These are callbacks which will be setup by the scene so that we can update scene data when we
106 // receive capability calls 102 // receive capability calls
107 public NewInventoryItem AddNewInventoryItem = null; 103 public NewInventoryItem AddNewInventoryItem = null;
@@ -115,12 +111,45 @@ namespace OpenSim.Region.ClientStack.Linden
115 private IAssetService m_assetService; 111 private IAssetService m_assetService;
116 private bool m_dumpAssetsToFile = false; 112 private bool m_dumpAssetsToFile = false;
117 private string m_regionName; 113 private string m_regionName;
114
118 private int m_levelUpload = 0; 115 private int m_levelUpload = 0;
119 116
120 public BunchOfCaps(Scene scene, Caps caps) 117 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
118 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
119
120 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
121 // may not be visible till relog
122
123 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
124 private UUID m_testAssetsCreatorID = UUID.Zero;
125
126 private float m_PrimScaleMin = 0.001f;
127
128 private bool m_AllowCapHomeLocation = true;
129 private bool m_AllowCapGroupMemberData = true;
130 private IUserManagement m_UserManager;
131
132
133 private enum FileAgentInventoryState : int
134 {
135 idle = 0,
136 processRequest = 1,
137 waitUpload = 2,
138 processUpload = 3
139 }
140 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
141
142 public BunchOfCaps(Scene scene, UUID agentID, Caps caps)
121 { 143 {
122 m_Scene = scene; 144 m_Scene = scene;
145 m_AgentID = agentID;
123 m_HostCapsObj = caps; 146 m_HostCapsObj = caps;
147
148 // create a model upload cost provider
149 m_ModelCost = new ModelCost(scene);
150
151 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
152
124 IConfigSource config = m_Scene.Config; 153 IConfigSource config = m_Scene.Config;
125 if (config != null) 154 if (config != null)
126 { 155 {
@@ -135,10 +164,45 @@ namespace OpenSim.Region.ClientStack.Linden
135 { 164 {
136 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 165 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
137 } 166 }
167 // economy for model upload
168 IConfig EconomyConfig = config.Configs["Economy"];
169 if (EconomyConfig != null)
170 {
171 m_ModelCost.Econfig(EconomyConfig);
172
173 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
174
175 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
176 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
177 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
178 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
179 if (testcreator != "")
180 {
181 UUID id;
182 UUID.TryParse(testcreator, out id);
183 if (id != null)
184 m_testAssetsCreatorID = id;
185 }
186 }
187
188 IConfig CapsConfig = config.Configs["ClientStack.LindenCaps"];
189 if (CapsConfig != null)
190 {
191 string homeLocationUrl = CapsConfig.GetString("Cap_HomeLocation", "localhost");
192 if(homeLocationUrl == String.Empty)
193 m_AllowCapHomeLocation = false;
194
195 string GroupMemberDataUrl = CapsConfig.GetString("Cap_GroupMemberData", "localhost");
196 if(GroupMemberDataUrl == String.Empty)
197 m_AllowCapGroupMemberData = false;
198 }
138 } 199 }
139 200
140 m_assetService = m_Scene.AssetService; 201 m_assetService = m_Scene.AssetService;
141 m_regionName = m_Scene.RegionInfo.RegionName; 202 m_regionName = m_Scene.RegionInfo.RegionName;
203 m_UserManager = m_Scene.RequestModuleInterface<IUserManagement>();
204 if (m_UserManager == null)
205 m_log.Error("[CAPS]: GetDisplayNames disabled because user management component not found");
142 206
143 RegisterHandlers(); 207 RegisterHandlers();
144 208
@@ -146,6 +210,13 @@ namespace OpenSim.Region.ClientStack.Linden
146 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 210 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
147 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 211 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
148 GetClient = m_Scene.SceneGraph.GetControllingClient; 212 GetClient = m_Scene.SceneGraph.GetControllingClient;
213
214 m_FileAgentInventoryState = FileAgentInventoryState.idle;
215 }
216
217 public string GetNewCapPath()
218 {
219 return "/CAPS/" + UUID.Random();
149 } 220 }
150 221
151 /// <summary> 222 /// <summary>
@@ -153,33 +224,67 @@ namespace OpenSim.Region.ClientStack.Linden
153 /// </summary> 224 /// </summary>
154 public void RegisterHandlers() 225 public void RegisterHandlers()
155 { 226 {
156 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 227 // this path is also defined elsewhere so keeping it
228 string seedcapsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath +"0000/";
157 229
158 RegisterRegionServiceHandlers(capsBase); 230 // the root of all evil path needs to be capsBase + m_requestPath
159 RegisterInventoryServiceHandlers(capsBase); 231 m_HostCapsObj.RegisterHandler(
232 "SEED", new RestStreamHandler("POST", seedcapsBase, SeedCapRequest, "SEED", null));
233
234// m_log.DebugFormat(
235// "[CAPS]: Registered seed capability {0} for {1}", seedcapsBase, m_HostCapsObj.AgentID);
236
237 RegisterRegionServiceHandlers();
238 RegisterInventoryServiceHandlers();
239 RegisterOtherHandlers();
160 } 240 }
161 241
162 public void RegisterRegionServiceHandlers(string capsBase) 242 public void RegisterRegionServiceHandlers()
163 { 243 {
164 try 244 try
165 { 245 {
166 // the root of all evil
167 m_HostCapsObj.RegisterHandler(
168 "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
169
170// m_log.DebugFormat(
171// "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
172
173 //m_capsHandlers["MapLayer"] = 246 //m_capsHandlers["MapLayer"] =
174 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", 247 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
175 // capsBase + m_mapLayerPath, 248 // GetNewCapPath(),
176 // GetMapLayer); 249 // GetMapLayer);
177 IRequestHandler req 250
178 = new RestStreamHandler( 251 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler(
179 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); 252 "POST", GetNewCapPath(), GetObjectPhysicsData, "GetObjectPhysicsData", null);
253 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
254
255 IRequestHandler getObjectCostHandler = new RestStreamHandler(
256 "POST", GetNewCapPath(), GetObjectCost, "GetObjectCost", null );
257 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
180 258
259 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler(
260 "POST", GetNewCapPath(), ResourceCostSelected, "ResourceCostSelected", null);
261 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
262
263 IRequestHandler req = new RestStreamHandler(
264 "POST", GetNewCapPath(), ScriptTaskInventory, "UpdateScript", null);
181 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); 265 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
182 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); 266 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
267
268 if(m_AllowCapHomeLocation)
269 {
270 IRequestHandler HomeLocationHandler = new RestStreamHandler(
271 "POST", GetNewCapPath(), HomeLocation, "HomeLocation", null);
272 m_HostCapsObj.RegisterHandler("HomeLocation", HomeLocationHandler);
273 }
274
275 if(m_AllowCapGroupMemberData)
276 {
277 IRequestHandler GroupMemberDataHandler = new RestStreamHandler(
278 "POST", GetNewCapPath(), GroupMemberData, "GroupMemberData", null);
279 m_HostCapsObj.RegisterHandler("GroupMemberData", GroupMemberDataHandler);
280 }
281
282
283// IRequestHandler animSetRequestHandler
284// = new RestStreamHandler(
285// "POST", capsBase + m_animSetTaskUpdatePath, AnimSetTaskInventory, "UpdateScript", null);
286
287// m_HostCapsObj.RegisterHandler("UpdateAnimSetTaskInventory", animSetRequestHandler);
183 } 288 }
184 catch (Exception e) 289 catch (Exception e)
185 { 290 {
@@ -187,68 +292,29 @@ namespace OpenSim.Region.ClientStack.Linden
187 } 292 }
188 } 293 }
189 294
190 public void RegisterInventoryServiceHandlers(string capsBase) 295 public void RegisterInventoryServiceHandlers()
191 { 296 {
192 try 297 try
193 { 298 {
194 // I don't think this one works... 299 m_HostCapsObj.RegisterHandler("NewFileAgentInventory",
195 m_HostCapsObj.RegisterHandler(
196 "NewFileAgentInventory",
197 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 300 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
198 "POST", 301 "POST", GetNewCapPath(), NewAgentInventoryRequest, "NewFileAgentInventory", null));
199 capsBase + m_newInventory,
200 NewAgentInventoryRequest,
201 "NewFileAgentInventory",
202 null));
203
204 IRequestHandler req
205 = new RestStreamHandler(
206 "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null);
207 302
303 IRequestHandler req = new RestStreamHandler(
304 "POST", GetNewCapPath(), NoteCardAgentInventory, "Update*", null);
208 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 305 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
306 m_HostCapsObj.RegisterHandler("UpdateAnimSetAgentInventory", req);
209 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 307 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
210 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 308 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
211 309
212 IRequestHandler getObjectPhysicsDataHandler 310 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler(
213 = new RestStreamHandler( 311 "POST", GetNewCapPath(), UpdateAgentInformation, "UpdateAgentInformation", null);
214 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
215 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
216
217 IRequestHandler UpdateAgentInformationHandler
218 = new RestStreamHandler(
219 "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null);
220 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 312 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
221 313
222 m_HostCapsObj.RegisterHandler( 314 IRequestHandler CopyInventoryFromNotecardHandler = new RestStreamHandler(
223 "CopyInventoryFromNotecard", 315 "POST", GetNewCapPath(), CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null);
224 new RestStreamHandler( 316 m_HostCapsObj.RegisterHandler("CopyInventoryFromNotecard", CopyInventoryFromNotecardHandler);
225 "POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null)); 317
226
227 // As of RC 1.22.9 of the Linden client this is
228 // supported
229
230 //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest);
231
232 // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and
233 // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires
234 // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service,
235 // but when I went on the Linden grid, the
236 // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead,
237 // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP
238 //
239 // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid
240 // we will be
241 // able to get the data we need to implement the necessary part of the protocol to fix the issue above.
242 // m_capsHandlers["FetchInventoryDescendents"] =
243 // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest);
244
245 // m_capsHandlers["FetchInventoryDescendents"] =
246 // new LLSDStreamhandler<LLSDFetchInventoryDescendents, LLSDInventoryDescendents>("POST",
247 // capsBase + m_fetchInventory,
248 // FetchInventory));
249 // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST",
250 // capsBase + m_requestTexture,
251 // RequestTexture);
252 } 318 }
253 catch (Exception e) 319 catch (Exception e)
254 { 320 {
@@ -256,6 +322,22 @@ namespace OpenSim.Region.ClientStack.Linden
256 } 322 }
257 } 323 }
258 324
325 public void RegisterOtherHandlers()
326 {
327 try
328 {
329 if (m_UserManager != null)
330 {
331 IRequestHandler GetDisplayNamesHandler = new RestStreamHandler(
332 "GET", GetNewCapPath(), GetDisplayNames, "GetDisplayNames", null);
333 m_HostCapsObj.RegisterHandler("GetDisplayNames", GetDisplayNamesHandler);
334 }
335 }
336 catch (Exception e)
337 {
338 m_log.Error("[CAPS]: " + e.ToString());
339 }
340 }
259 /// <summary> 341 /// <summary>
260 /// Construct a client response detailing all the capabilities this server can provide. 342 /// Construct a client response detailing all the capabilities this server can provide.
261 /// </summary> 343 /// </summary>
@@ -268,8 +350,11 @@ namespace OpenSim.Region.ClientStack.Linden
268 public string SeedCapRequest(string request, string path, string param, 350 public string SeedCapRequest(string request, string path, string param,
269 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 351 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
270 { 352 {
271// m_log.DebugFormat( 353 m_log.DebugFormat(
272// "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 354 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
355
356 if (!m_HostCapsObj.WaitForActivation())
357 return string.Empty;
273 358
274 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 359 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
275 { 360 {
@@ -314,30 +399,28 @@ namespace OpenSim.Region.ClientStack.Linden
314 LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); 399 LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate();
315 LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); 400 LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest);
316 401
317 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 402 string uploaderPath = GetNewCapPath();
318 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
319 403
320 TaskInventoryScriptUpdater uploader = 404 TaskInventoryScriptUpdater uploader =
321 new TaskInventoryScriptUpdater( 405 new TaskInventoryScriptUpdater(
322 llsdUpdateRequest.item_id, 406 llsdUpdateRequest.item_id,
323 llsdUpdateRequest.task_id, 407 llsdUpdateRequest.task_id,
324 llsdUpdateRequest.is_script_running, 408 llsdUpdateRequest.is_script_running,
325 capsBase + uploaderPath, 409 uploaderPath,
326 m_HostCapsObj.HttpListener, 410 m_HostCapsObj.HttpListener,
327 m_dumpAssetsToFile); 411 m_dumpAssetsToFile);
328 uploader.OnUpLoad += TaskScriptUpdated; 412 uploader.OnUpLoad += TaskScriptUpdated;
329 413
330 m_HostCapsObj.HttpListener.AddStreamHandler( 414 m_HostCapsObj.HttpListener.AddStreamHandler(
331 new BinaryStreamHandler( 415 new BinaryStreamHandler(
332 "POST", capsBase + uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null)); 416 "POST", uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null));
333 417
334 string protocol = "http://"; 418 string protocol = "http://";
335 419
336 if (m_HostCapsObj.SSLCaps) 420 if (m_HostCapsObj.SSLCaps)
337 protocol = "https://"; 421 protocol = "https://";
338 422
339 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 423 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
340 uploaderPath;
341 424
342 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 425 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
343 uploadResponse.uploader = uploaderURL; 426 uploadResponse.uploader = uploaderURL;
@@ -400,83 +483,208 @@ namespace OpenSim.Region.ClientStack.Linden
400 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 483 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
401 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 484 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
402 485
486 // start by getting the client
487 IClientAPI client = null;
488 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
489
490 // check current state so we only have one service at a time
491 lock (m_ModelCost)
492 {
493 switch (m_FileAgentInventoryState)
494 {
495 case FileAgentInventoryState.processRequest:
496 case FileAgentInventoryState.processUpload:
497 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
498 resperror.message = "Uploader busy processing previus request";
499 resperror.identifier = UUID.Zero;
500
501 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
502 errorResponse.uploader = "";
503 errorResponse.state = "error";
504 errorResponse.error = resperror;
505 return errorResponse;
506 break;
507 case FileAgentInventoryState.waitUpload:
508 // todo stop current uploader server
509 break;
510 case FileAgentInventoryState.idle:
511 default:
512 break;
513 }
514
515 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
516 }
517
518 int cost = 0;
519 int nreqtextures = 0;
520 int nreqmeshs= 0;
521 int nreqinstances = 0;
522 bool IsAtestUpload = false;
523
524 string assetName = llsdRequest.name;
525
526 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
527
403 if (llsdRequest.asset_type == "texture" || 528 if (llsdRequest.asset_type == "texture" ||
404 llsdRequest.asset_type == "animation" || 529 llsdRequest.asset_type == "animation" ||
530 llsdRequest.asset_type == "animatn" || // this is the asset name actually used by viewers
531 llsdRequest.asset_type == "mesh" ||
405 llsdRequest.asset_type == "sound") 532 llsdRequest.asset_type == "sound")
406 { 533 {
407 ScenePresence avatar = null; 534 ScenePresence avatar = null;
408 IClientAPI client = null;
409 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 535 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
410 536
411 // check user level 537 // check user level
412 if (avatar != null) 538 if (avatar != null)
413 { 539 {
414 client = avatar.ControllingClient; 540 if (avatar.GodController.UserLevel < m_levelUpload)
415
416 if (avatar.UserLevel < m_levelUpload)
417 { 541 {
418 if (client != null) 542 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
419 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 543 resperror.message = "Insufficient permissions to upload";
544 resperror.identifier = UUID.Zero;
420 545
421 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 546 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
422 errorResponse.uploader = ""; 547 errorResponse.uploader = "";
423 errorResponse.state = "error"; 548 errorResponse.state = "error";
549 errorResponse.error = resperror;
550 lock (m_ModelCost)
551 m_FileAgentInventoryState = FileAgentInventoryState.idle;
424 return errorResponse; 552 return errorResponse;
425 } 553 }
426 } 554 }
427 555
428 // check funds 556 // check test upload and funds
429 if (client != null) 557 if (client != null)
430 { 558 {
431 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 559 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
432 560
561 int baseCost = 0;
433 if (mm != null) 562 if (mm != null)
563 baseCost = mm.UploadCharge;
564
565 string warning = String.Empty;
566
567 if (llsdRequest.asset_type == "mesh")
434 { 568 {
435 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 569 string error;
570 int modelcost;
571
572
573 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
574 meshcostdata, out error, ref warning))
436 { 575 {
437 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 576 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
577 resperror.message = error;
578 resperror.identifier = UUID.Zero;
438 579
439 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 580 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
440 errorResponse.uploader = ""; 581 errorResponse.uploader = "";
441 errorResponse.state = "error"; 582 errorResponse.state = "error";
583 errorResponse.error = resperror;
584
585 lock (m_ModelCost)
586 m_FileAgentInventoryState = FileAgentInventoryState.idle;
442 return errorResponse; 587 return errorResponse;
443 } 588 }
589 cost = modelcost;
590 }
591 else
592 {
593 cost = baseCost;
444 } 594 }
595
596 if (cost > 0 && mm != null)
597 {
598 // check for test upload
599
600 if (m_ForceFreeTestUpload) // all are test
601 {
602 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
603 assetName = "TEST-" + assetName;
604
605 IsAtestUpload = true;
606 }
607
608 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
609 {
610
611 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
612 }
613
614
615 if(IsAtestUpload) // let user know, still showing cost estimation
616 warning += "Upload will have no cost, for testing purposes only. Other uses are prohibited. Items will not work after 48 hours or on other regions";
617
618 // check funds
619 else
620 {
621 if (!mm.UploadCovered(client.AgentId, (int)cost))
622 {
623 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
624 resperror.message = "Insuficient funds";
625 resperror.identifier = UUID.Zero;
626
627 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
628 errorResponse.uploader = "";
629 errorResponse.state = "error";
630 errorResponse.error = resperror;
631 lock (m_ModelCost)
632 m_FileAgentInventoryState = FileAgentInventoryState.idle;
633 return errorResponse;
634 }
635 }
636 }
637
638 if (client != null && warning != String.Empty)
639 client.SendAgentAlertMessage(warning, true);
445 } 640 }
446 } 641 }
447 642
448 string assetName = llsdRequest.name;
449 string assetDes = llsdRequest.description; 643 string assetDes = llsdRequest.description;
450 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
451 UUID newAsset = UUID.Random(); 644 UUID newAsset = UUID.Random();
452 UUID newInvItem = UUID.Random(); 645 UUID newInvItem = UUID.Random();
453 UUID parentFolder = llsdRequest.folder_id; 646 UUID parentFolder = llsdRequest.folder_id;
454 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 647 string uploaderPath = GetNewCapPath();
648 UUID texturesFolder = UUID.Zero;
649
650 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
651 texturesFolder = llsdRequest.texture_folder_id;
455 652
456 AssetUploader uploader = 653 AssetUploader uploader =
457 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 654 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
458 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 655 llsdRequest.asset_type, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
656 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload,
657 llsdRequest.next_owner_mask, llsdRequest.group_mask, llsdRequest.everyone_mask);
459 658
460 m_HostCapsObj.HttpListener.AddStreamHandler( 659 m_HostCapsObj.HttpListener.AddStreamHandler(
461 new BinaryStreamHandler( 660 new BinaryStreamHandler(
462 "POST", 661 "POST",
463 capsBase + uploaderPath, 662 uploaderPath,
464 uploader.uploaderCaps, 663 uploader.uploaderCaps,
465 "NewAgentInventoryRequest", 664 "NewAgentInventoryRequest",
466 m_HostCapsObj.AgentID.ToString())); 665 m_HostCapsObj.AgentID.ToString()));
467 666
468 string protocol = "http://"; 667 string protocol = "http://";
469
470 if (m_HostCapsObj.SSLCaps) 668 if (m_HostCapsObj.SSLCaps)
471 protocol = "https://"; 669 protocol = "https://";
472 670
473 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 671 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
474 uploaderPath;
475 672
476 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 673 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
477 uploadResponse.uploader = uploaderURL; 674 uploadResponse.uploader = uploaderURL;
478 uploadResponse.state = "upload"; 675 uploadResponse.state = "upload";
676 uploadResponse.upload_price = (int)cost;
677
678 if (llsdRequest.asset_type == "mesh")
679 {
680 uploadResponse.data = meshcostdata;
681 }
682
479 uploader.OnUpLoad += UploadCompleteHandler; 683 uploader.OnUpLoad += UploadCompleteHandler;
684
685 lock (m_ModelCost)
686 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
687
480 return uploadResponse; 688 return uploadResponse;
481 } 689 }
482 690
@@ -488,8 +696,14 @@ namespace OpenSim.Region.ClientStack.Linden
488 /// <param name="data"></param> 696 /// <param name="data"></param>
489 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 697 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
490 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 698 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
491 string assetType) 699 string assetType, int cost,
700 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
701 bool IsAtestUpload, ref string error,
702 ref int nextOwnerMask, ref int groupMask, ref int everyoneMask)
492 { 703 {
704 lock (m_ModelCost)
705 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
706
493 m_log.DebugFormat( 707 m_log.DebugFormat(
494 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 708 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
495 assetID, inventoryItem, inventoryType, assetType); 709 assetID, inventoryItem, inventoryType, assetType);
@@ -497,6 +711,34 @@ namespace OpenSim.Region.ClientStack.Linden
497 sbyte assType = 0; 711 sbyte assType = 0;
498 sbyte inType = 0; 712 sbyte inType = 0;
499 713
714 IClientAPI client = null;
715
716 UUID owner_id = m_HostCapsObj.AgentID;
717 UUID creatorID;
718
719 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
720
721 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
722
723 if (istest && m_testAssetsCreatorID != UUID.Zero)
724 creatorID = m_testAssetsCreatorID;
725 else
726 creatorID = owner_id;
727
728 string creatorIDstr = creatorID.ToString();
729
730 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
731 if (mm != null)
732 {
733 // make sure client still has enougth credit
734 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
735 {
736 error = "Insufficient funds.";
737 return;
738 }
739 }
740
741 // strings to types
500 if (inventoryType == "sound") 742 if (inventoryType == "sound")
501 { 743 {
502 inType = (sbyte)InventoryType.Sound; 744 inType = (sbyte)InventoryType.Sound;
@@ -511,6 +753,12 @@ namespace OpenSim.Region.ClientStack.Linden
511 inType = (sbyte)InventoryType.Animation; 753 inType = (sbyte)InventoryType.Animation;
512 assType = (sbyte)AssetType.Animation; 754 assType = (sbyte)AssetType.Animation;
513 } 755 }
756 else if (inventoryType == "animset")
757 {
758 inType = (sbyte)CustomInventoryType.AnimationSet;
759 assType = (sbyte)CustomAssetType.AnimationSet;
760 m_log.Debug("got animset upload request");
761 }
514 else if (inventoryType == "wearable") 762 else if (inventoryType == "wearable")
515 { 763 {
516 inType = (sbyte)InventoryType.Wearable; 764 inType = (sbyte)InventoryType.Wearable;
@@ -526,191 +774,290 @@ namespace OpenSim.Region.ClientStack.Linden
526 } 774 }
527 else if (inventoryType == "object") 775 else if (inventoryType == "object")
528 { 776 {
529 inType = (sbyte)InventoryType.Object; 777 if (assetType == "mesh") // this code for now is for mesh models uploads only
530 assType = (sbyte)AssetType.Object; 778 {
531 779 inType = (sbyte)InventoryType.Object;
532 List<Vector3> positions = new List<Vector3>(); 780 assType = (sbyte)AssetType.Object;
533 List<Quaternion> rotations = new List<Quaternion>();
534 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
535 OSDArray instance_list = (OSDArray)request["instance_list"];
536 OSDArray mesh_list = (OSDArray)request["mesh_list"];
537 OSDArray texture_list = (OSDArray)request["texture_list"];
538 SceneObjectGroup grp = null;
539 781
540 InventoryFolderBase textureUploadFolder = null; 782 List<Vector3> positions = new List<Vector3>();
783 List<Quaternion> rotations = new List<Quaternion>();
784 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
541 785
542 List<InventoryFolderBase> foldersToUpdate = new List<InventoryFolderBase>(); 786 // compare and get updated information
543 List<InventoryItemBase> itemsToUpdate = new List<InventoryItemBase>(); 787/* does nothing still we do need something to avoid special viewer to upload something diferent from the cost estimation
544 IClientInventory clientInv = null; 788 bool mismatchError = true;
545
546 if (texture_list.Count > 0)
547 {
548 ScenePresence avatar = null;
549 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
550 789
551 if (avatar != null) 790 while (mismatchError)
552 { 791 {
553 IClientCore core = (IClientCore)avatar.ControllingClient; 792 mismatchError = false;
793 }
794
795 if (mismatchError)
796 {
797 error = "Upload and fee estimation information don't match";
798 lock (m_ModelCost)
799 m_FileAgentInventoryState = FileAgentInventoryState.idle;
800
801 return;
802 }
803*/
804 OSDArray instance_list = (OSDArray)request["instance_list"];
805 OSDArray mesh_list = (OSDArray)request["mesh_list"];
806 OSDArray texture_list = (OSDArray)request["texture_list"];
807 SceneObjectGroup grp = null;
808
809 // create and store texture assets
810 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
811 texturesFolder != UUID.Zero);
812
813
814 List<UUID> textures = new List<UUID>();
815
816
817// if (doTextInv)
818 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
819
820 if(client == null) // don't put textures in inventory if there is no client
821 doTextInv = false;
554 822
555 if (core.TryGet<IClientInventory>(out clientInv)) 823 for (int i = 0; i < texture_list.Count; i++)
824 {
825 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
826 textureAsset.Data = texture_list[i].AsBinary();
827 if (istest)
828 textureAsset.Local = true;
829 m_assetService.Store(textureAsset);
830 textures.Add(textureAsset.FullID);
831
832 if (doTextInv)
556 { 833 {
557 var systemTextureFolder = m_Scene.InventoryService.GetFolderForType(m_HostCapsObj.AgentID, FolderType.Texture); 834 string name = assetName;
558 textureUploadFolder = new InventoryFolderBase(UUID.Random(), assetName, m_HostCapsObj.AgentID, (short)FolderType.None, systemTextureFolder.ID, 1); 835 if (name.Length > 25)
559 if (m_Scene.InventoryService.AddFolder(textureUploadFolder)) 836 name = name.Substring(0, 24);
560 { 837 name += "_Texture#" + i.ToString();
561 foldersToUpdate.Add(textureUploadFolder); 838 InventoryItemBase texitem = new InventoryItemBase();
839 texitem.Owner = m_HostCapsObj.AgentID;
840 texitem.CreatorId = creatorIDstr;
841 texitem.CreatorData = String.Empty;
842 texitem.ID = UUID.Random();
843 texitem.AssetID = textureAsset.FullID;
844 texitem.Description = "mesh model texture";
845 texitem.Name = name;
846 texitem.AssetType = (int)AssetType.Texture;
847 texitem.InvType = (int)InventoryType.Texture;
848 texitem.Folder = texturesFolder;
849
850 texitem.CurrentPermissions
851 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
852
853 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
854 texitem.EveryOnePermissions = 0;
855 texitem.NextPermissions = (uint)PermissionMask.All;
856 texitem.CreationDate = Util.UnixTimeSinceEpoch();
857
858 m_Scene.AddInventoryItem(client, texitem);
859 texitem = null;
860 }
861 }
562 862
563 m_log.DebugFormat( 863 // create and store meshs assets
564 "[BUNCH OF CAPS]: Created new folder '{0}' ({1}) for textures uploaded with mesh object {2}", 864 List<UUID> meshAssets = new List<UUID>();
565 textureUploadFolder.Name, textureUploadFolder.ID, assetName); 865 List<bool> meshAvatarSkeletons = new List<bool>();
566 } 866 List<bool> meshAvatarColliders = new List<bool>();
567 else 867
868 bool curAvSkeleton;
869 bool curAvCollider;
870 for (int i = 0; i < mesh_list.Count; i++)
871 {
872 curAvSkeleton = false;
873 curAvCollider = false;
874
875 // we do need to parse the mesh now
876 OSD osd = OSDParser.DeserializeLLSDBinary(mesh_list[i]);
877 if (osd is OSDMap)
878 {
879 OSDMap mosd = (OSDMap)osd;
880 if (mosd.ContainsKey("skeleton"))
568 { 881 {
569 textureUploadFolder = null; 882 OSDMap skeleton = (OSDMap)mosd["skeleton"];
883 int sksize = skeleton["size"].AsInteger();
884 if (sksize > 0)
885 curAvSkeleton = true;
570 } 886 }
571 } 887 }
572 }
573 }
574 888
575 List<UUID> textures = new List<UUID>(); 889 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
576 for (int i = 0; i < texture_list.Count; i++) 890 meshAsset.Data = mesh_list[i].AsBinary();
577 { 891 if (istest)
578 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 892 meshAsset.Local = true;
579 textureAsset.Data = texture_list[i].AsBinary(); 893 m_assetService.Store(meshAsset);
580 m_assetService.Store(textureAsset); 894 meshAssets.Add(meshAsset.FullID);
581 textures.Add(textureAsset.FullID); 895 meshAvatarSkeletons.Add(curAvSkeleton);
896 meshAvatarColliders.Add(curAvCollider);
897
898 // test code
899 if (curAvSkeleton && client != null)
900 {
901 string name = assetName;
902 if (name.Length > 25)
903 name = name.Substring(0, 24);
904 name += "_Mesh#" + i.ToString();
905 InventoryItemBase meshitem = new InventoryItemBase();
906 meshitem.Owner = m_HostCapsObj.AgentID;
907 meshitem.CreatorId = creatorIDstr;
908 meshitem.CreatorData = String.Empty;
909 meshitem.ID = UUID.Random();
910 meshitem.AssetID = meshAsset.FullID;
911 meshitem.Description = "mesh ";
912 meshitem.Name = name;
913 meshitem.AssetType = (int)AssetType.Mesh;
914 meshitem.InvType = (int)InventoryType.Mesh;
915 // meshitem.Folder = UUID.Zero; // send to default
916
917 meshitem.Folder = parentFolder; // dont let it go to folder Meshes that viewers dont show
918
919 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
920 // (owner) permissions. This becomes a problem if next permissions are changed.
921 meshitem.CurrentPermissions
922 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
923
924 meshitem.BasePermissions = (uint)PermissionMask.All;
925 meshitem.EveryOnePermissions = 0;
926 meshitem.NextPermissions = (uint)PermissionMask.All;
927 meshitem.CreationDate = Util.UnixTimeSinceEpoch();
928
929 m_Scene.AddInventoryItem(client, meshitem);
930 meshitem = null;
931 }
932 }
582 933
583 if (textureUploadFolder != null) 934 int skipedMeshs = 0;
935 // build prims from instances
936 for (int i = 0; i < instance_list.Count; i++)
584 { 937 {
585 InventoryItemBase textureItem = new InventoryItemBase(); 938 OSDMap inner_instance_list = (OSDMap)instance_list[i];
586 textureItem.Owner = m_HostCapsObj.AgentID;
587 textureItem.CreatorId = m_HostCapsObj.AgentID.ToString();
588 textureItem.CreatorData = String.Empty;
589 textureItem.ID = UUID.Random();
590 textureItem.AssetID = textureAsset.FullID;
591 textureItem.Description = assetDescription;
592 textureItem.Name = assetName + " - Texture " + (i + 1).ToString();
593 textureItem.AssetType = (int)AssetType.Texture;
594 textureItem.InvType = (int)InventoryType.Texture;
595 textureItem.Folder = textureUploadFolder.ID;
596 textureItem.CurrentPermissions
597 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
598 textureItem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
599 textureItem.EveryOnePermissions = 0;
600 textureItem.NextPermissions = (uint)PermissionMask.All;
601 textureItem.CreationDate = Util.UnixTimeSinceEpoch();
602 m_Scene.InventoryService.AddItem(textureItem);
603 itemsToUpdate.Add(textureItem);
604
605 m_log.DebugFormat(
606 "[BUNCH OF CAPS]: Created new inventory item '{0}' ({1}) for texture uploaded with mesh object {2}",
607 textureItem.Name, textureItem.ID, assetName);
608 }
609 }
610 939
611 if (clientInv != null && (foldersToUpdate.Count > 0 || itemsToUpdate.Count > 0)) 940 // skip prims that are 2 small
612 { 941 Vector3 scale = inner_instance_list["scale"].AsVector3();
613 clientInv.SendBulkUpdateInventory(foldersToUpdate.ToArray(), itemsToUpdate.ToArray());
614 }
615 942
616 for (int i = 0; i < mesh_list.Count; i++) 943 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
617 { 944 {
618 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 945 skipedMeshs++;
946 continue;
947 }
619 948
620 Primitive.TextureEntry textureEntry 949 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
621 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
622 OSDMap inner_instance_list = (OSDMap)instance_list[i];
623 950
624 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 951 PrimitiveBaseShape pbs = null;
625 for (uint face = 0; face < face_list.Count; face++) 952 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
626 { 953 {
627 OSDMap faceMap = (OSDMap)face_list[(int)face]; 954 int meshindx = inner_instance_list["mesh"].AsInteger();
628 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 955 if (meshAssets.Count > meshindx)
629 if(faceMap.ContainsKey("fullbright")) 956 pbs = PrimitiveBaseShape.CreateMesh(face_list.Count, meshAssets[meshindx]);
630 f.Fullbright = faceMap["fullbright"].AsBoolean(); 957 }
631 if (faceMap.ContainsKey ("diffuse_color")) 958 if(pbs == null) // fallback
632 f.RGBA = faceMap["diffuse_color"].AsColor4(); 959 pbs = PrimitiveBaseShape.CreateBox();
960
961 Primitive.TextureEntry textureEntry
962 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
633 963
634 int textureNum = faceMap["image"].AsInteger(); 964 for (uint face = 0; face < face_list.Count; face++)
635 float imagerot = faceMap["imagerot"].AsInteger(); 965 {
636 float offsets = (float)faceMap["offsets"].AsReal(); 966 OSDMap faceMap = (OSDMap)face_list[(int)face];
637 float offsett = (float)faceMap["offsett"].AsReal();
638 float scales = (float)faceMap["scales"].AsReal();
639 float scalet = (float)faceMap["scalet"].AsReal();
640 967
641 if(imagerot != 0) 968 Primitive.TextureEntryFace f = textureEntry.CreateFace(face); //clone the default
642 f.Rotation = imagerot; 969 if (faceMap.ContainsKey("fullbright"))
970 f.Fullbright = faceMap["fullbright"].AsBoolean();
971 if (faceMap.ContainsKey("diffuse_color"))
972 f.RGBA = faceMap["diffuse_color"].AsColor4();
643 973
644 if(offsets != 0) 974 int textureNum = faceMap["image"].AsInteger();
645 f.OffsetU = offsets; 975 float imagerot = faceMap["imagerot"].AsInteger();
976 float offsets = (float)faceMap["offsets"].AsReal();
977 float offsett = (float)faceMap["offsett"].AsReal();
978 float scales = (float)faceMap["scales"].AsReal();
979 float scalet = (float)faceMap["scalet"].AsReal();
646 980
647 if (offsett != 0) 981 if (imagerot != 0)
648 f.OffsetV = offsett; 982 f.Rotation = imagerot;
649 983
650 if (scales != 0) 984 if (offsets != 0)
651 f.RepeatU = scales; 985 f.OffsetU = offsets;
652 986
653 if (scalet != 0) 987 if (offsett != 0)
654 f.RepeatV = scalet; 988 f.OffsetV = offsett;
655 989
656 if (textures.Count > textureNum) 990 if (scales != 0)
657 f.TextureID = textures[textureNum]; 991 f.RepeatU = scales;
992
993 if (scalet != 0)
994 f.RepeatV = scalet;
995
996 if (textures.Count > textureNum)
997 f.TextureID = textures[textureNum];
998
999 textureEntry.FaceTextures[face] = f;
1000 }
1001 pbs.TextureEntry = textureEntry.GetBytes();
1002
1003 Vector3 position = inner_instance_list["position"].AsVector3();
1004 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
1005
1006 // for now viwers do send fixed defaults
1007 // but this may change
1008// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
1009 byte physicsShapeType = (byte)PhysShapeType.convex; // default is simple convex
1010// int material = inner_instance_list["material"].AsInteger();
1011 byte material = (byte)Material.Wood;
1012
1013 SceneObjectPart prim
1014 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
1015
1016 prim.Scale = scale;
1017 rotations.Add(rotation);
1018 positions.Add(position);
1019 prim.UUID = UUID.Random();
1020 prim.CreatorID = creatorID;
1021 prim.OwnerID = owner_id;
1022 prim.GroupID = UUID.Zero;
1023 prim.LastOwnerID = creatorID;
1024 prim.RezzerID = creatorID;
1025 prim.CreationDate = Util.UnixTimeSinceEpoch();
1026
1027 if (grp == null)
1028 prim.Name = assetName;
658 else 1029 else
659 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; 1030 prim.Name = assetName + "#" + i.ToString();
660 1031
661 textureEntry.FaceTextures[face] = f; 1032 prim.EveryoneMask = 0;
662 } 1033 prim.GroupMask = 0;
663 1034
664 pbs.TextureEntry = textureEntry.GetBytes(); 1035 if (restrictPerms)
665 1036 {
666 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 1037 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
667 meshAsset.Data = mesh_list[i].AsBinary(); 1038 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
668 m_assetService.Store(meshAsset); 1039 prim.NextOwnerMask = 0;
669 1040 }
670 pbs.SculptEntry = true; 1041 else
671 pbs.SculptTexture = meshAsset.FullID; 1042 {
672 pbs.SculptType = (byte)SculptType.Mesh; 1043 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
673 pbs.SculptData = meshAsset.Data; 1044 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
674 1045 prim.GroupMask = prim.BaseMask & (uint)groupMask;
675 Vector3 position = inner_instance_list["position"].AsVector3(); 1046 prim.EveryoneMask = prim.BaseMask & (uint)everyoneMask;
676 Vector3 scale = inner_instance_list["scale"].AsVector3(); 1047 prim.NextOwnerMask = prim.BaseMask & (uint)nextOwnerMask;
677 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 1048 // If the viewer gives us bogus permissions, revert to the SL
678 1049 // default of transfer only.
679// no longer used - begin ------------------------ 1050 if ((prim.NextOwnerMask & (uint)PermissionMask.All) == 0)
680// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger(); 1051 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
681// int material = inner_instance_list["material"].AsInteger(); 1052 }
682// int mesh = inner_instance_list["mesh"].AsInteger(); 1053
683 1054 if(istest)
684// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 1055 prim.Description = "For testing only. Other uses are prohibited";
685// int base_mask = permissions["base_mask"].AsInteger(); 1056 else
686// int everyone_mask = permissions["everyone_mask"].AsInteger(); 1057 prim.Description = "";
687// UUID creator_id = permissions["creator_id"].AsUUID(); 1058
688// UUID group_id = permissions["group_id"].AsUUID(); 1059 prim.Material = material;
689// int group_mask = permissions["group_mask"].AsInteger(); 1060 prim.PhysicsShapeType = physicsShapeType;
690// bool is_owner_group = permissions["is_owner_group"].AsBoolean();
691// UUID last_owner_id = permissions["last_owner_id"].AsUUID();
692// int next_owner_mask = permissions["next_owner_mask"].AsInteger();
693// UUID owner_id = permissions["owner_id"].AsUUID();
694// int owner_mask = permissions["owner_mask"].AsInteger();
695// no longer used - end ------------------------
696
697 UUID owner_id = m_HostCapsObj.AgentID;
698
699 SceneObjectPart prim
700 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
701
702 prim.Scale = scale;
703 //prim.OffsetPosition = position;
704 rotations.Add(rotation);
705 positions.Add(position);
706 prim.UUID = UUID.Random();
707 prim.CreatorID = owner_id;
708 prim.OwnerID = owner_id;
709 prim.GroupID = UUID.Zero;
710 prim.LastOwnerID = prim.OwnerID;
711 prim.CreationDate = Util.UnixTimeSinceEpoch();
712 prim.Name = assetName;
713 prim.Description = "";
714 1061
715// prim.BaseMask = (uint)base_mask; 1062// prim.BaseMask = (uint)base_mask;
716// prim.EveryoneMask = (uint)everyone_mask; 1063// prim.EveryoneMask = (uint)everyone_mask;
@@ -718,52 +1065,65 @@ namespace OpenSim.Region.ClientStack.Linden
718// prim.NextOwnerMask = (uint)next_owner_mask; 1065// prim.NextOwnerMask = (uint)next_owner_mask;
719// prim.OwnerMask = (uint)owner_mask; 1066// prim.OwnerMask = (uint)owner_mask;
720 1067
721 if (grp == null) 1068 if (grp == null)
722 grp = new SceneObjectGroup(prim); 1069 {
723 else 1070 grp = new SceneObjectGroup(prim);
724 grp.AddPart(prim); 1071 grp.LastOwnerID = creatorID;
725 } 1072 grp.RezzerID = creatorID;
1073 }
1074 else
1075 grp.AddPart(prim);
1076 }
726 1077
727 Vector3 rootPos = positions[0]; 1078 Vector3 rootPos = positions[0];
728 1079
729 if (grp.Parts.Length > 1) 1080 if (grp.Parts.Length > 1)
730 { 1081 {
731 // Fix first link number 1082 // Fix first link number
732 grp.RootPart.LinkNum++; 1083 grp.RootPart.LinkNum++;
733 1084
734 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1085 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
735 Quaternion tmprot; 1086 Quaternion tmprot;
736 Vector3 offset; 1087 Vector3 offset;
737 1088
738 // fix children rotations and positions 1089 // fix children rotations and positions
739 for (int i = 1; i < rotations.Count; i++) 1090 for (int i = 1; i < rotations.Count; i++)
740 { 1091 {
741 tmprot = rotations[i]; 1092 tmprot = rotations[i];
742 tmprot = rootRotConj * tmprot; 1093 tmprot = rootRotConj * tmprot;
743 1094
744 grp.Parts[i].RotationOffset = tmprot; 1095 grp.Parts[i].RotationOffset = tmprot;
745 1096
746 offset = positions[i] - rootPos; 1097 offset = positions[i] - rootPos;
1098
1099 offset *= rootRotConj;
1100 grp.Parts[i].OffsetPosition = offset;
1101 }
747 1102
748 offset *= rootRotConj; 1103 grp.AbsolutePosition = rootPos;
749 grp.Parts[i].OffsetPosition = offset; 1104 grp.UpdateGroupRotationR(rotations[0]);
1105 }
1106 else
1107 {
1108 grp.AbsolutePosition = rootPos;
1109 grp.UpdateGroupRotationR(rotations[0]);
750 } 1110 }
751 1111
752 grp.AbsolutePosition = rootPos; 1112 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
753 grp.UpdateGroupRotationR(rotations[0]);
754 } 1113 }
755 else 1114
1115 else // not a mesh model
756 { 1116 {
757 grp.AbsolutePosition = rootPos; 1117 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
758 grp.UpdateGroupRotationR(rotations[0]); 1118 return;
759 } 1119 }
760
761 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
762 } 1120 }
763 1121
764 AssetBase asset; 1122 AssetBase asset;
765 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1123 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
766 asset.Data = data; 1124 asset.Data = data;
1125 if (istest)
1126 asset.Local = true;
767 if (AddNewAsset != null) 1127 if (AddNewAsset != null)
768 AddNewAsset(asset); 1128 AddNewAsset(asset);
769 else if (m_assetService != null) 1129 else if (m_assetService != null)
@@ -771,11 +1131,17 @@ namespace OpenSim.Region.ClientStack.Linden
771 1131
772 InventoryItemBase item = new InventoryItemBase(); 1132 InventoryItemBase item = new InventoryItemBase();
773 item.Owner = m_HostCapsObj.AgentID; 1133 item.Owner = m_HostCapsObj.AgentID;
774 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1134 item.CreatorId = creatorIDstr;
775 item.CreatorData = String.Empty; 1135 item.CreatorData = String.Empty;
776 item.ID = inventoryItem; 1136 item.ID = inventoryItem;
777 item.AssetID = asset.FullID; 1137 item.AssetID = asset.FullID;
778 item.Description = assetDescription; 1138 if (istest)
1139 {
1140 item.Description = "For testing only. Other uses are prohibited";
1141 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1142 }
1143 else
1144 item.Description = assetDescription;
779 item.Name = assetName; 1145 item.Name = assetName;
780 item.AssetType = assType; 1146 item.AssetType = assType;
781 item.InvType = inType; 1147 item.InvType = inType;
@@ -783,18 +1149,69 @@ namespace OpenSim.Region.ClientStack.Linden
783 1149
784 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1150 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
785 // (owner) permissions. This becomes a problem if next permissions are changed. 1151 // (owner) permissions. This becomes a problem if next permissions are changed.
786 item.CurrentPermissions
787 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
788 1152
789 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1153 if (inType == (sbyte)CustomInventoryType.AnimationSet)
790 item.EveryOnePermissions = 0; 1154 {
791 item.NextPermissions = (uint)PermissionMask.All; 1155 AnimationSet.setCreateItemPermitions(item);
1156 }
1157
1158 else if (restrictPerms)
1159 {
1160 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1161 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1162 item.GroupPermissions = 0;
1163 item.EveryOnePermissions = 0;
1164 item.NextPermissions = 0;
1165 }
1166 else
1167 {
1168 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1169 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1170 item.GroupPermissions = item.BasePermissions & (uint)groupMask;
1171 item.EveryOnePermissions = item.BasePermissions & (uint)everyoneMask;
1172 item.NextPermissions = item.BasePermissions & (uint)nextOwnerMask;
1173 if ((item.NextPermissions & (uint)PermissionMask.All) == 0)
1174 item.NextPermissions = (uint)PermissionMask.Transfer;
1175 }
1176
792 item.CreationDate = Util.UnixTimeSinceEpoch(); 1177 item.CreationDate = Util.UnixTimeSinceEpoch();
793 1178
1179 everyoneMask = (int)item.EveryOnePermissions;
1180 groupMask = (int)item.GroupPermissions;
1181 nextOwnerMask = (int)item.NextPermissions;
1182
1183 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1184
794 if (AddNewInventoryItem != null) 1185 if (AddNewInventoryItem != null)
795 { 1186 {
796 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1187 if (istest)
1188 {
1189 m_Scene.AddInventoryItem(client, item);
1190/*
1191 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1192 if (client != null)
1193 client.SendAgentAlertMessage("Upload will have no cost, for personal test purposes only. Other uses are forbiden. Items may not work on a another region" , true);
1194 */
1195 }
1196 else
1197 {
1198 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1199// if (client != null)
1200// {
1201// // let users see anything.. i don't so far
1202// string str;
1203// if (cost > 0)
1204// // dont remember where is money unit name to put here
1205// str = "Upload complete. charged " + cost.ToString() + "$";
1206// else
1207// str = "Upload complete";
1208// client.SendAgentAlertMessage(str, true);
1209// }
1210 }
797 } 1211 }
1212
1213 lock (m_ModelCost)
1214 m_FileAgentInventoryState = FileAgentInventoryState.idle;
798 } 1215 }
799 1216
800 /// <summary> 1217 /// <summary>
@@ -857,24 +1274,22 @@ namespace OpenSim.Region.ClientStack.Linden
857 LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); 1274 LLSDItemUpdate llsdRequest = new LLSDItemUpdate();
858 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); 1275 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
859 1276
860 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 1277 string uploaderPath = GetNewCapPath();
861 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
862 1278
863 ItemUpdater uploader = 1279 ItemUpdater uploader =
864 new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 1280 new ItemUpdater(llsdRequest.item_id, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
865 uploader.OnUpLoad += ItemUpdated; 1281 uploader.OnUpLoad += ItemUpdated;
866 1282
867 m_HostCapsObj.HttpListener.AddStreamHandler( 1283 m_HostCapsObj.HttpListener.AddStreamHandler(
868 new BinaryStreamHandler( 1284 new BinaryStreamHandler(
869 "POST", capsBase + uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null)); 1285 "POST", uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null));
870 1286
871 string protocol = "http://"; 1287 string protocol = "http://";
872 1288
873 if (m_HostCapsObj.SSLCaps) 1289 if (m_HostCapsObj.SSLCaps)
874 protocol = "https://"; 1290 protocol = "https://";
875 1291
876 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 1292 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath;
877 uploaderPath;
878 1293
879 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 1294 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
880 uploadResponse.uploader = uploaderURL; 1295 uploadResponse.uploader = uploaderURL;
@@ -930,29 +1345,22 @@ namespace OpenSim.Region.ClientStack.Linden
930 IClientAPI client = null; 1345 IClientAPI client = null;
931 1346
932 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); 1347 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
933 item = m_Scene.InventoryService.GetItem(new InventoryItemBase(itemID)); 1348 item = m_Scene.InventoryService.GetItem(m_HostCapsObj.AgentID, itemID);
934 if (item != null) 1349 if (item != null)
935 { 1350 {
936 string message; 1351 string message;
937 copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message); 1352 copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message);
938 if (client != null) 1353 if (copyItem != null && client != null)
939 { 1354 {
940 if (copyItem != null) 1355 m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder);
941 { 1356 client.SendBulkUpdateInventory(copyItem);
942 m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder);
943 client.SendBulkUpdateInventory(copyItem);
944 }
945 else
946 {
947 client.SendAgentAlertMessage(message, false);
948 }
949 } 1357 }
950 } 1358 }
951 else 1359 else
952 { 1360 {
953 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID); 1361 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID);
954 if (client != null) 1362 if (client != null)
955 client.SendAgentAlertMessage("Failed to retrieve item", false); 1363 client.SendAlertMessage("Failed to retrieve item");
956 } 1364 }
957 } 1365 }
958 catch (Exception e) 1366 catch (Exception e)
@@ -995,26 +1403,483 @@ namespace OpenSim.Region.ClientStack.Linden
995 return response; 1403 return response;
996 } 1404 }
997 1405
998 public string UpdateAgentInformation(string request, string path, 1406 public string GetObjectCost(string request, string path,
999 string param, IOSHttpRequest httpRequest, 1407 string param, IOSHttpRequest httpRequest,
1000 IOSHttpResponse httpResponse) 1408 IOSHttpResponse httpResponse)
1001 { 1409 {
1002 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); 1410 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1003 OSDMap accessPrefs = (OSDMap)req["access_prefs"]; 1411 OSDMap resp = new OSDMap();
1004 string desiredMaturity = accessPrefs["max"]; 1412
1413 OSDArray object_ids = (OSDArray)req["object_ids"];
1414
1415 for (int i = 0; i < object_ids.Count; i++)
1416 {
1417 UUID uuid = object_ids[i].AsUUID();
1418
1419 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1420 SceneObjectGroup grp = null;
1421 if (part != null)
1422 grp = part.ParentGroup;
1423 if (grp != null)
1424 {
1425 float linksetCost;
1426 float linksetPhysCost;
1427 float partCost;
1428 float partPhysCost;
1429
1430 grp.GetResourcesCosts(part,out linksetCost,out linksetPhysCost,out partCost,out partPhysCost);
1431
1432 OSDMap object_data = new OSDMap();
1433 object_data["linked_set_resource_cost"] = linksetCost;
1434 object_data["resource_cost"] = partCost;
1435 object_data["physics_cost"] = partPhysCost;
1436 object_data["linked_set_physics_cost"] = linksetPhysCost;
1437 object_data["resource_limiting_type"] = "legacy";
1438 resp[uuid.ToString()] = object_data;
1439 }
1440 }
1441 if(resp.Count == 0)
1442 {
1443 OSDMap object_data = new OSDMap();
1444 object_data["linked_set_resource_cost"] = 0;
1445 object_data["resource_cost"] = 0;
1446 object_data["physics_cost"] = 0;
1447 object_data["linked_set_physics_cost"] = 0;
1448 resp[UUID.Zero.ToString()] = object_data;
1449 }
1450 string response = OSDParser.SerializeLLSDXmlString(resp);
1451 return response;
1452 }
1453
1454 public string ResourceCostSelected(string request, string path,
1455 string param, IOSHttpRequest httpRequest,
1456 IOSHttpResponse httpResponse)
1457 {
1458 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1459 OSDMap resp = new OSDMap();
1460
1461
1462 float phys=0;
1463 float stream=0;
1464 float simul=0;
1465
1466 if (req.ContainsKey("selected_roots"))
1467 {
1468 OSDArray object_ids = (OSDArray)req["selected_roots"];
1469
1470 // should go by SOG suming costs for all parts
1471 // ll v3 works ok with several objects select we get the list and adds ok
1472 // FS calls per object so results are wrong guess fs bug
1473 for (int i = 0; i < object_ids.Count; i++)
1474 {
1475 UUID uuid = object_ids[i].AsUUID();
1476 float Physc;
1477 float simulc;
1478 float streamc;
1479
1480 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1481 if (grp != null)
1482 {
1483 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1484 phys += Physc;
1485 stream += streamc;
1486 simul += simulc;
1487 }
1488 }
1489 }
1490 else if (req.ContainsKey("selected_prims"))
1491 {
1492 OSDArray object_ids = (OSDArray)req["selected_prims"];
1493
1494 // don't see in use in any of the 2 viewers
1495 // guess it should be for edit linked but... nothing
1496 // should go to SOP per part
1497 for (int i = 0; i < object_ids.Count; i++)
1498 {
1499 UUID uuid = object_ids[i].AsUUID();
1500
1501 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1502 if (part != null)
1503 {
1504 phys += part.PhysicsCost;
1505 stream += part.StreamingCost;
1506 simul += part.SimulationCost;
1507 }
1508 }
1509 }
1510
1511 OSDMap object_data = new OSDMap();
1512
1513 object_data["physics"] = phys;
1514 object_data["streaming"] = stream;
1515 object_data["simulation"] = simul;
1516
1517 resp["selected"] = object_data;
1518// resp["transaction_id"] = "undef";
1519 string response = OSDParser.SerializeLLSDXmlString(resp);
1520 return response;
1521 }
1005 1522
1523 public string UpdateAgentInformation(string request, string path,
1524 string param, IOSHttpRequest httpRequest,
1525 IOSHttpResponse httpResponse)
1526 {
1527// OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1006 OSDMap resp = new OSDMap(); 1528 OSDMap resp = new OSDMap();
1007 OSDMap respAccessPrefs = new OSDMap(); 1529
1008 respAccessPrefs["max"] = desiredMaturity; // echoing the maturity back means success 1530 OSDMap accessPrefs = new OSDMap();
1009 resp["access_prefs"] = respAccessPrefs; 1531 accessPrefs["max"] = "A";
1532
1533 resp["access_prefs"] = accessPrefs;
1010 1534
1011 string response = OSDParser.SerializeLLSDXmlString(resp); 1535 string response = OSDParser.SerializeLLSDXmlString(resp);
1012 return response; 1536 return response;
1537 }
1538
1539 public bool OSDMapTOVector3(OSDMap map, out Vector3 v)
1540 {
1541 v = Vector3.Zero;
1542 if(!map.ContainsKey("X"))
1543 return false;
1544 if(!map.ContainsKey("Y"))
1545 return false;
1546 if(!map.ContainsKey("Z"))
1547 return false;
1548 v.X = (float)map["X"].AsReal();
1549 v.Y = (float)map["Y"].AsReal();
1550 v.Z = (float)map["Z"].AsReal();
1551 return true;
1552 }
1553
1554 public string HomeLocation(string request, string path, string param, IOSHttpRequest httpRequest,
1555 IOSHttpResponse httpResponse)
1556 {
1557 OSDMap resp = new OSDMap();
1558
1559 resp["success"] = "false";
1560
1561
1562 bool fail = true;
1563 string message = "Set Home request failed";
1564 int locationID = 1;
1565 Vector3 pos = Vector3.Zero;
1566 Vector3 lookAt = Vector3.Zero;
1567
1568 IClientAPI client = null;
1569 ScenePresence sp;
1570
1571 while(true)
1572 {
1573 if(m_Scene.GridUserService == null)
1574 break;
1575
1576 if(m_Scene.UserManagementModule == null)
1577 break;
1578
1579 m_Scene.TryGetScenePresence(m_AgentID, out sp);
1580 if(sp == null || sp.IsChildAgent || sp.IsDeleted)
1581 break;
1582
1583 if(sp.IsInTransit && !sp.IsInLocalTransit)
1584 break;
1585
1586 client = sp.ControllingClient;
1587
1588 if(!m_Scene.UserManagementModule.IsLocalGridUser(m_AgentID))
1589 break;
1590
1591 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1592 if(!req.ContainsKey("HomeLocation"))
1593 break;
1594
1595 OSDMap HLocation = (OSDMap)req["HomeLocation"];
1596 if(!HLocation.ContainsKey("LocationPos"))
1597 break;
1598 if(!HLocation.ContainsKey("LocationLookAt"))
1599 break;
1600
1601 locationID = HLocation["LocationId"].AsInteger();
1602
1603 if(!OSDMapTOVector3((OSDMap)HLocation["LocationPos"], out pos))
1604 break;
1605
1606 if(!OSDMapTOVector3((OSDMap)HLocation["LocationLookAt"], out lookAt))
1607 break;
1608
1609 ILandObject land = m_Scene.LandChannel.GetLandObject(pos);
1610 if(land == null)
1611 break;
1612
1613 ulong gpowers = client.GetGroupPowers(land.LandData.GroupID);
1614 SceneObjectGroup telehub = null;
1615 if (m_Scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
1616 // Does the telehub exist in the scene?
1617 telehub = m_Scene.GetSceneObjectGroup(m_Scene.RegionInfo.RegionSettings.TelehubObject);
1618
1619 if (!m_Scene.Permissions.IsAdministrator(m_AgentID) && // (a) gods and land managers can set home
1620 !m_Scene.Permissions.IsGod(m_AgentID) &&
1621 m_AgentID != land.LandData.OwnerID && // (b) land owners can set home
1622 // (c) members of the land-associated group in roles that can set home
1623 ((gpowers & (ulong)GroupPowers.AllowSetHome) != (ulong)GroupPowers.AllowSetHome) &&
1624 // (d) parcels with telehubs can be the home of anyone
1625 (telehub == null || !land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y)))
1626 {
1627 message = "You are not allowed to set your home location in this parcel.";
1628 break;
1629 }
1630
1631 string userId;
1632 UUID test;
1633 if (!m_Scene.UserManagementModule.GetUserUUI(m_AgentID, out userId))
1634 {
1635 message = "Set Home request failed. (User Lookup)";
1636 break;
1637 }
1638
1639 if (!UUID.TryParse(userId, out test))
1640 {
1641 message = "Set Home request failed. (HG visitor)";
1642 break;
1643 }
1644
1645 if (m_Scene.GridUserService.SetHome(userId, land.RegionUUID, pos, lookAt))
1646 fail = false;
1647
1648 break;
1649 }
1650
1651 string response;
1652
1653 if(fail)
1654 {
1655 if(client != null)
1656 client.SendAlertMessage(message);
1657 response = OSDParser.SerializeLLSDXmlString(resp);
1658 return response;
1659 }
1660
1661 // so its http but still needs a udp reply to inform user? crap :p
1662 if(client != null)
1663 client.SendAlertMessage("Home position set.","HomePositionSet");
1664
1665 resp["success"] = "true";
1666 OSDMap homeloc = new OSDMap();
1667 OSDMap homelocpos = new OSDMap();
1668 // for some odd reason viewers send pos as reals but read as integer
1669 homelocpos["X"] = new OSDReal(pos.X);
1670 homelocpos["Y"] = new OSDReal(pos.Y);
1671 homelocpos["Z"] = new OSDReal(pos.Z);
1672 homeloc["LocationPos"] = homelocpos;
1673
1674 resp["HomeLocation"] = homeloc;
1675
1676 response = OSDParser.SerializeLLSDXmlString(resp);
1677 return response;
1678 }
1679
1680 private static int CompareRolesByMembersDesc(GroupRolesData x, GroupRolesData y)
1681 {
1682 return -(x.Members.CompareTo(y.Members));
1683 }
1684
1685 public string GroupMemberData(string request, string path, string param, IOSHttpRequest httpRequest,
1686 IOSHttpResponse httpResponse)
1687 {
1688 OSDMap resp = new OSDMap();
1689
1690 string response;
1691
1692 bool fail = true;
1693 IClientAPI client = null;
1694 ScenePresence sp;
1695 IGroupsModule m_GroupsModule;
1696 UUID groupID = UUID.Zero;
1697
1698 while(true)
1699 {
1700 m_GroupsModule = m_Scene.RequestModuleInterface<IGroupsModule>();
1701 if(m_GroupsModule == null)
1702 break;
1703
1704 m_Scene.TryGetScenePresence(m_AgentID, out sp);
1705 if(sp == null || sp.IsChildAgent || sp.IsDeleted)
1706 break;
1707
1708 if(sp.IsInTransit && !sp.IsInLocalTransit)
1709 break;
1710
1711 client = sp.ControllingClient;
1712
1713 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1714 if(!req.ContainsKey("group_id"))
1715 break;
1716
1717 groupID = req["group_id"].AsUUID();
1718 if(groupID == UUID.Zero)
1719 break;
1720
1721 List<GroupRolesData> roles = m_GroupsModule.GroupRoleDataRequest(client, groupID);
1722 if(roles == null || roles.Count == 0)
1723 break;
1724
1725 List<GroupMembersData> members = m_GroupsModule.GroupMembersRequest(client, groupID);
1726 if(members == null || members.Count == 0)
1727 break;
1728
1729 int memberCount = members.Count;
1730
1731 Dictionary<string,int> titles = new Dictionary<string,int>();
1732 int i = 0;
1733
1734 ulong defaultPowers = 0;
1735
1736
1737 // build titles array and index
1738 roles.Sort(CompareRolesByMembersDesc);
1739
1740 OSDArray osdtitles = new OSDArray();
1741 foreach(GroupRolesData grd in roles)
1742 {
1743 if(grd.Title == null)
1744 continue;
1745 string title = grd.Title;
1746 if(i==0)
1747 defaultPowers = grd.Powers;
1748
1749 if(!titles.ContainsKey(title))
1750 {
1751 titles[title] = i++;
1752 osdtitles.Add(new OSDString(title));
1753 }
1754 }
1755
1756 if(titles.Count == 0)
1757 break;
1758
1759 OSDMap osdmembers = new OSDMap();
1760 foreach(GroupMembersData gmd in members)
1761 {
1762 OSDMap m = new OSDMap();
1763 if(gmd.OnlineStatus != null && gmd.OnlineStatus != "")
1764 m["last_login"] = new OSDString(gmd.OnlineStatus);
1765 if(gmd.AgentPowers != defaultPowers)
1766 m["powers"] = new OSDString((gmd.AgentPowers).ToString("X"));
1767 if(gmd.Title != null && titles.ContainsKey(gmd.Title) && titles[gmd.Title] != 0)
1768 m["title"] = new OSDInteger(titles[gmd.Title]);
1769 if(gmd.IsOwner)
1770 m["owner"] = new OSDString("true");
1771 if(gmd.Contribution != 0)
1772 m["donated_square_meters"] = new OSDInteger(gmd.Contribution);
1773
1774 osdmembers[(gmd.AgentID).ToString()] = m;
1775 }
1776
1777 OSDMap osddefaults = new OSDMap();
1778 osddefaults["default_powers"] = new OSDString(defaultPowers.ToString("X"));
1779
1780 resp["group_id"] = new OSDUUID(groupID);
1781 resp["agent_id"] = new OSDUUID(m_AgentID);
1782 resp["member_count"] = new OSDInteger(memberCount);
1783 resp["defaults"] = osddefaults;
1784 resp["titles"] = osdtitles;
1785 resp["members"] = osdmembers;
1786
1787 fail = false;
1788 break;
1789 }
1790
1791 if(fail)
1792 {
1793 resp["group_id"] = new OSDUUID(groupID);
1794 resp["agent_id"] = new OSDUUID(m_AgentID);
1795 resp["member_count"] = new OSDInteger(0);
1796 resp["defaults"] = new OSDMap();
1797 resp["titles"] = new OSDArray();
1798 resp["members"] = new OSDMap();
1799 }
1800
1801 response = OSDParser.SerializeLLSDXmlString(resp);
1802 return response;
1803 }
1804
1805 public string GetDisplayNames(string request, string path,
1806 string param, IOSHttpRequest httpRequest,
1807 IOSHttpResponse httpResponse)
1808 {
1809 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.Gone;
1810 httpResponse.ContentType = "text/plain";
1811
1812 ScenePresence sp = m_Scene.GetScenePresence(m_AgentID);
1813 if(sp == null || sp.IsDeleted)
1814 return "";
1815
1816 if(sp.IsInTransit && !sp.IsInLocalTransit)
1817 {
1818 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable;
1819 httpResponse.AddHeader("Retry-After","30");
1820 return "";
1821 }
1822
1823 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
1824 string[] ids = query.GetValues("ids");
1825
1826 Dictionary<UUID,string> names = m_UserManager.GetUsersNames(ids);
1827
1828 OSDMap osdReply = new OSDMap();
1829 OSDArray agents = new OSDArray();
1830
1831 osdReply["agents"] = agents;
1832 foreach (KeyValuePair<UUID,string> kvp in names)
1833 {
1834 if (string.IsNullOrEmpty(kvp.Value))
1835 continue;
1836 if(kvp.Key == UUID.Zero)
1837 continue;
1838
1839 string[] parts = kvp.Value.Split(new char[] {' '});
1840 OSDMap osdname = new OSDMap();
1841
1842 // dont tell about unknown users, we can't send them back on Bad either
1843 if(parts[0] == "Unknown")
1844 continue;
1845/*
1846 if(parts[0] == "Unknown")
1847 {
1848 osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1));
1849 osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2));
1850 }
1851 else
1852*/
1853 {
1854 osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8));
1855 osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1));
1856 }
1857 osdname["display_name"] = OSD.FromString(kvp.Value);
1858 osdname["legacy_first_name"] = parts[0];
1859 osdname["legacy_last_name"] = parts[1];
1860 osdname["username"] = OSD.FromString(kvp.Value);
1861 osdname["id"] = OSD.FromUUID(kvp.Key);
1862 osdname["is_display_name_default"] = OSD.FromBoolean(true);
1863
1864 agents.Add(osdname);
1865 }
1866
1867 // Full content request
1868 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK;
1869 //httpResponse.ContentLength = ??;
1870 httpResponse.ContentType = "application/llsd+xml";
1871
1872 string reply = OSDParser.SerializeLLSDXmlString(osdReply);
1873 return reply;
1013 } 1874 }
1014 } 1875 }
1015 1876
1016 public class AssetUploader 1877 public class AssetUploader
1017 { 1878 {
1879 private static readonly ILog m_log =
1880 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1881
1882
1018 public event UpLoadedAsset OnUpLoad; 1883 public event UpLoadedAsset OnUpLoad;
1019 private UpLoadedAsset handlerUpLoad = null; 1884 private UpLoadedAsset handlerUpLoad = null;
1020 1885
@@ -1029,10 +1894,26 @@ namespace OpenSim.Region.ClientStack.Linden
1029 1894
1030 private string m_invType = String.Empty; 1895 private string m_invType = String.Empty;
1031 private string m_assetType = String.Empty; 1896 private string m_assetType = String.Empty;
1897 private int m_cost;
1898 private string m_error = String.Empty;
1899
1900 private Timer m_timeoutTimer = new Timer();
1901 private UUID m_texturesFolder;
1902 private int m_nreqtextures;
1903 private int m_nreqmeshs;
1904 private int m_nreqinstances;
1905 private bool m_IsAtestUpload;
1906
1907 private int m_nextOwnerMask;
1908 private int m_groupMask;
1909 private int m_everyoneMask;
1910
1032 1911
1033 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1912 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
1034 UUID parentFolderID, string invType, string assetType, string path, 1913 UUID parentFolderID, string invType, string assetType, string path,
1035 IHttpServer httpServer, bool dumpAssetsToFile) 1914 IHttpServer httpServer, bool dumpAssetsToFile,
1915 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1916 bool IsAtestUpload, int nextOwnerMask, int groupMask, int everyoneMask)
1036 { 1917 {
1037 m_assetName = assetName; 1918 m_assetName = assetName;
1038 m_assetDes = description; 1919 m_assetDes = description;
@@ -1044,6 +1925,22 @@ namespace OpenSim.Region.ClientStack.Linden
1044 m_assetType = assetType; 1925 m_assetType = assetType;
1045 m_invType = invType; 1926 m_invType = invType;
1046 m_dumpAssetsToFile = dumpAssetsToFile; 1927 m_dumpAssetsToFile = dumpAssetsToFile;
1928 m_cost = totalCost;
1929
1930 m_texturesFolder = texturesFolder;
1931 m_nreqtextures = nreqtextures;
1932 m_nreqmeshs = nreqmeshs;
1933 m_nreqinstances = nreqinstances;
1934 m_IsAtestUpload = IsAtestUpload;
1935
1936 m_timeoutTimer.Elapsed += TimedOut;
1937 m_timeoutTimer.Interval = 120000;
1938 m_timeoutTimer.AutoReset = false;
1939 m_timeoutTimer.Start();
1940
1941 m_nextOwnerMask = nextOwnerMask;
1942 m_groupMask = groupMask;
1943 m_everyoneMask = everyoneMask;
1047 } 1944 }
1048 1945
1049 /// <summary> 1946 /// <summary>
@@ -1058,12 +1955,14 @@ namespace OpenSim.Region.ClientStack.Linden
1058 UUID inv = inventoryItemID; 1955 UUID inv = inventoryItemID;
1059 string res = String.Empty; 1956 string res = String.Empty;
1060 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1957 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1958/*
1061 uploadComplete.new_asset = newAssetID.ToString(); 1959 uploadComplete.new_asset = newAssetID.ToString();
1062 uploadComplete.new_inventory_item = inv; 1960 uploadComplete.new_inventory_item = inv;
1063 uploadComplete.state = "complete"; 1961 uploadComplete.state = "complete";
1064 1962
1065 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1963 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1066 1964*/
1965 m_timeoutTimer.Stop();
1067 httpListener.RemoveStreamHandler("POST", uploaderPath); 1966 httpListener.RemoveStreamHandler("POST", uploaderPath);
1068 1967
1069 // TODO: probably make this a better set of extensions here 1968 // TODO: probably make this a better set of extensions here
@@ -1080,12 +1979,55 @@ namespace OpenSim.Region.ClientStack.Linden
1080 handlerUpLoad = OnUpLoad; 1979 handlerUpLoad = OnUpLoad;
1081 if (handlerUpLoad != null) 1980 if (handlerUpLoad != null)
1082 { 1981 {
1083 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1982 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1983 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload,
1984 ref m_error, ref m_nextOwnerMask, ref m_groupMask, ref m_everyoneMask);
1084 } 1985 }
1085 1986
1987 uploadComplete.new_next_owner_mask = m_nextOwnerMask;
1988 uploadComplete.new_group_mask = m_groupMask;
1989 uploadComplete.new_everyone_mask = m_everyoneMask;
1990
1991 if (m_IsAtestUpload)
1992 {
1993 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1994 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1995 resperror.identifier = inv;
1996
1997 uploadComplete.error = resperror;
1998 uploadComplete.state = "Upload4Testing";
1999 }
2000 else
2001 {
2002 if (m_error == String.Empty)
2003 {
2004 uploadComplete.new_asset = newAssetID.ToString();
2005 uploadComplete.new_inventory_item = inv;
2006 // if (m_texturesFolder != UUID.Zero)
2007 // uploadComplete.new_texture_folder_id = m_texturesFolder;
2008 uploadComplete.state = "complete";
2009 }
2010 else
2011 {
2012 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
2013 resperror.message = m_error;
2014 resperror.identifier = inv;
2015
2016 uploadComplete.error = resperror;
2017 uploadComplete.state = "failed";
2018 }
2019 }
2020
2021 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1086 return res; 2022 return res;
1087 } 2023 }
1088 2024
2025 private void TimedOut(object sender, ElapsedEventArgs args)
2026 {
2027 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
2028 httpListener.RemoveStreamHandler("POST", uploaderPath);
2029 }
2030
1089 ///Left this in and commented in case there are unforseen issues 2031 ///Left this in and commented in case there are unforseen issues
1090 //private void SaveAssetToFile(string filename, byte[] data) 2032 //private void SaveAssetToFile(string filename, byte[] data)
1091 //{ 2033 //{
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
index c241075..683c3d5 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs
@@ -63,7 +63,7 @@ namespace OpenSim.Region.ClientStack.Linden
63 { 63 {
64 } 64 }
65 65
66 public void Close() { } 66 public void Close() { }
67 67
68 public void AddRegion(Scene scene) 68 public void AddRegion(Scene scene)
69 { 69 {
@@ -80,11 +80,11 @@ namespace OpenSim.Region.ClientStack.Linden
80 } 80 }
81 81
82 public void PostInitialise() { } 82 public void PostInitialise() { }
83 #endregion 83 #endregion
84 84
85 private void OnRegisterCaps(UUID agentID, Caps caps) 85 private void OnRegisterCaps(UUID agentID, Caps caps)
86 { 86 {
87 new BunchOfCaps(m_Scene, caps); 87 new BunchOfCaps(m_Scene, agentID, caps);
88 } 88 }
89 89
90 } 90 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
new file mode 100644
index 0000000..eb1ab45
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
@@ -0,0 +1,746 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29using System;
30using System.IO;
31using System.Collections;
32using System.Collections.Generic;
33using System.Text;
34
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37
38using OpenSim.Framework;
39using OpenSim.Region.Framework;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Framework.Capabilities;
42
43using ComponentAce.Compression.Libs.zlib;
44
45using OSDArray = OpenMetaverse.StructuredData.OSDArray;
46using OSDMap = OpenMetaverse.StructuredData.OSDMap;
47
48using Nini.Config;
49
50namespace OpenSim.Region.ClientStack.Linden
51{
52 public struct ModelPrimLimits
53 {
54
55 }
56
57 public class ModelCost
58 {
59
60 // upload fee defaults
61 // fees are normalized to 1.0
62 // this parameters scale them to basic cost ( so 1.0 translates to 10 )
63
64 public float ModelMeshCostFactor = 0.0f; // scale total cost relative to basic (excluding textures)
65 public float ModelTextureCostFactor = 1.0f; // scale textures fee to basic.
66 public float ModelMinCostFactor = 0.0f; // 0.5f; // minimum total model free excluding textures
67
68 // itens costs in normalized values
69 // ie will be multiplied by basicCost and factors above
70 public float primCreationCost = 0.002f; // extra cost for each prim creation overhead
71 // weigthed size to normalized cost
72 public float bytecost = 1e-5f;
73
74 // mesh upload fees based on compressed data sizes
75 // several data sections are counted more that once
76 // to promote user optimization
77 // following parameters control how many extra times they are added
78 // to global size.
79 // LOD meshs
80 const float medSizeWth = 1f; // 2x
81 const float lowSizeWth = 1.5f; // 2.5x
82 const float lowestSizeWth = 2f; // 3x
83 // favor potencially physical optimized meshs versus automatic decomposition
84 const float physMeshSizeWth = 6f; // counts 7x
85 const float physHullSizeWth = 8f; // counts 9x
86
87 // stream cost area factors
88 // more or less like SL
89 const float highLodFactor = 17.36f;
90 const float midLodFactor = 277.78f;
91 const float lowLodFactor = 1111.11f;
92
93 // physics cost is below, identical to SL, assuming shape type convex
94 // server cost is below identical to SL assuming non scripted non physical object
95
96 // internal
97 const int bytesPerCoord = 6; // 3 coords, 2 bytes per each
98
99 // control prims dimensions
100 public float PrimScaleMin = 0.001f;
101 public float NonPhysicalPrimScaleMax = 256f;
102 public float PhysicalPrimScaleMax = 10f;
103 public int ObjectLinkedPartsMax = 512;
104
105
106 public ModelCost(Scene scene)
107 {
108 PrimScaleMin = scene.m_minNonphys;
109 NonPhysicalPrimScaleMax = scene.m_maxNonphys;
110 PhysicalPrimScaleMax = scene.m_maxPhys;
111 ObjectLinkedPartsMax = scene.m_linksetCapacity;
112 }
113
114 public void Econfig(IConfig EconomyConfig)
115 {
116 ModelMeshCostFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", ModelMeshCostFactor);
117 ModelTextureCostFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", ModelTextureCostFactor);
118 ModelMinCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", ModelMinCostFactor);
119 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
120 primCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", primCreationCost);
121 bytecost = EconomyConfig.GetFloat("ModelMeshByteCost", bytecost);
122 }
123
124 // storage for a single mesh asset cost parameters
125 private class ameshCostParam
126 {
127 // LOD sizes for size dependent streaming cost
128 public int highLODSize;
129 public int medLODSize;
130 public int lowLODSize;
131 public int lowestLODSize;
132 // normalized fee based on compressed data sizes
133 public float costFee;
134 // physics cost
135 public float physicsCost;
136 }
137
138 // calculates a mesh model costs
139 // returns false on error, with a reason on parameter error
140 // resources input LLSD request
141 // basicCost input region assets upload cost
142 // totalcost returns model total upload fee
143 // meshcostdata returns detailed costs for viewer
144 // avatarSkeleton if mesh includes a avatar skeleton
145 // useAvatarCollider if we should use physics mesh for avatar
146 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost,
147 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
148 {
149 totalcost = 0;
150 error = string.Empty;
151
152 bool avatarSkeleton = false;
153
154 if (resources == null ||
155 resources.instance_list == null ||
156 resources.instance_list.Array.Count == 0)
157 {
158 error = "missing model information.";
159 return false;
160 }
161
162 int numberInstances = resources.instance_list.Array.Count;
163
164 if (ObjectLinkedPartsMax != 0 && numberInstances > ObjectLinkedPartsMax)
165 {
166 error = "Model would have more than " + ObjectLinkedPartsMax.ToString() + " linked prims";
167 return false;
168 }
169
170 meshcostdata.model_streaming_cost = 0.0;
171 meshcostdata.simulation_cost = 0.0;
172 meshcostdata.physics_cost = 0.0;
173 meshcostdata.resource_cost = 0.0;
174
175 meshcostdata.upload_price_breakdown.mesh_instance = 0;
176 meshcostdata.upload_price_breakdown.mesh_physics = 0;
177 meshcostdata.upload_price_breakdown.mesh_streaming = 0;
178 meshcostdata.upload_price_breakdown.model = 0;
179
180 int itmp;
181
182 // textures cost
183 if (resources.texture_list != null && resources.texture_list.Array.Count > 0)
184 {
185 float textures_cost = (float)(resources.texture_list.Array.Count * basicCost);
186 textures_cost *= ModelTextureCostFactor;
187
188 itmp = (int)(textures_cost + 0.5f); // round
189 meshcostdata.upload_price_breakdown.texture = itmp;
190 totalcost += itmp;
191 }
192
193 // meshs assets cost
194 float meshsfee = 0;
195 int numberMeshs = 0;
196 bool haveMeshs = false;
197
198 bool curskeleton;
199 bool curAvatarPhys;
200
201 List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
202
203 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
204 {
205 numberMeshs = resources.mesh_list.Array.Count;
206
207 for (int i = 0; i < numberMeshs; i++)
208 {
209 ameshCostParam curCost = new ameshCostParam();
210 byte[] data = (byte[])resources.mesh_list.Array[i];
211
212 if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error))
213 {
214 return false;
215 }
216
217 if (curskeleton)
218 {
219 if (avatarSkeleton)
220 {
221 error = "model can only contain a avatar skeleton";
222 return false;
223 }
224 avatarSkeleton = true;
225 }
226 meshsCosts.Add(curCost);
227 meshsfee += curCost.costFee;
228 }
229 haveMeshs = true;
230 }
231
232 // instances (prims) cost
233
234
235 int mesh;
236 int skipedSmall = 0;
237 for (int i = 0; i < numberInstances; i++)
238 {
239 Hashtable inst = (Hashtable)resources.instance_list.Array[i];
240
241 ArrayList ascale = (ArrayList)inst["scale"];
242 Vector3 scale;
243 double tmp;
244 tmp = (double)ascale[0];
245 scale.X = (float)tmp;
246 tmp = (double)ascale[1];
247 scale.Y = (float)tmp;
248 tmp = (double)ascale[2];
249 scale.Z = (float)tmp;
250
251 if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin)
252 {
253 skipedSmall++;
254 continue;
255 }
256
257 if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax)
258 {
259 error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale";
260 return false;
261 }
262
263 if (haveMeshs && inst.ContainsKey("mesh"))
264 {
265 mesh = (int)inst["mesh"];
266
267 if (mesh >= numberMeshs)
268 {
269 error = "Incoerent model information.";
270 return false;
271 }
272
273 // streamming cost
274
275 float sqdiam = scale.LengthSquared();
276
277 ameshCostParam curCost = meshsCosts[mesh];
278 float mesh_streaming = streamingCost(curCost, sqdiam);
279
280 meshcostdata.model_streaming_cost += mesh_streaming;
281 meshcostdata.physics_cost += curCost.physicsCost;
282 }
283 else // instance as no mesh ??
284 {
285 // to do later if needed
286 meshcostdata.model_streaming_cost += 0.5f;
287 meshcostdata.physics_cost += 1.0f;
288 }
289
290 // assume unscripted and static prim server cost
291 meshcostdata.simulation_cost += 0.5f;
292 // charge for prims creation
293 meshsfee += primCreationCost;
294 }
295
296 if (skipedSmall > 0)
297 {
298 if (skipedSmall > numberInstances / 2)
299 {
300 error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() +
301 "m minimum allowed size. Please check scalling";
302 return false;
303 }
304 else
305 warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() +
306 " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() +
307 "m minimum allowed size. Please check scalling ";
308 }
309
310 if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost)
311 meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
312 else
313 meshcostdata.resource_cost = meshcostdata.physics_cost;
314
315 if (meshcostdata.resource_cost < meshcostdata.simulation_cost)
316 meshcostdata.resource_cost = meshcostdata.simulation_cost;
317
318 // scale cost
319 // at this point a cost of 1.0 whould mean basic cost
320 meshsfee *= ModelMeshCostFactor;
321
322 if (meshsfee < ModelMinCostFactor)
323 meshsfee = ModelMinCostFactor;
324
325 // actually scale it to basic cost
326 meshsfee *= (float)basicCost;
327
328 meshsfee += 0.5f; // rounding
329
330 totalcost += (int)meshsfee;
331
332 // breakdown prices
333 // don't seem to be in use so removed code for now
334
335 return true;
336 }
337
338 // single mesh asset cost
339 private bool MeshCost(byte[] data, ameshCostParam cost,out bool skeleton, out bool avatarPhys, out string error)
340 {
341 cost.highLODSize = 0;
342 cost.medLODSize = 0;
343 cost.lowLODSize = 0;
344 cost.lowestLODSize = 0;
345 cost.physicsCost = 0.0f;
346 cost.costFee = 0.0f;
347
348 error = string.Empty;
349
350 skeleton = false;
351 avatarPhys = false;
352
353 if (data == null || data.Length == 0)
354 {
355 error = "Missing model information.";
356 return false;
357 }
358
359 OSD meshOsd = null;
360 int start = 0;
361
362 error = "Invalid model data";
363
364 using (MemoryStream ms = new MemoryStream(data))
365 {
366 try
367 {
368 OSD osd = OSDParser.DeserializeLLSDBinary(ms);
369 if (osd is OSDMap)
370 meshOsd = (OSDMap)osd;
371 else
372 return false;
373 }
374 catch
375 {
376 return false;
377 }
378 start = (int)ms.Position;
379 }
380
381 OSDMap map = (OSDMap)meshOsd;
382 OSDMap tmpmap;
383
384 int highlod_size = 0;
385 int medlod_size = 0;
386 int lowlod_size = 0;
387 int lowestlod_size = 0;
388 int skin_size = 0;
389
390 int hulls_size = 0;
391 int phys_nhulls;
392 int phys_hullsvertices = 0;
393
394 int physmesh_size = 0;
395 int phys_ntriangles = 0;
396
397 int submesh_offset = -1;
398
399 if (map.ContainsKey("skeleton"))
400 {
401 tmpmap = (OSDMap)map["skeleton"];
402 if (tmpmap.ContainsKey("offset") && tmpmap.ContainsKey("size"))
403 {
404 int sksize = tmpmap["size"].AsInteger();
405 if(sksize > 0)
406 skeleton = true;
407 }
408 }
409
410 if (map.ContainsKey("physics_convex"))
411 {
412 tmpmap = (OSDMap)map["physics_convex"];
413 if (tmpmap.ContainsKey("offset"))
414 submesh_offset = tmpmap["offset"].AsInteger() + start;
415 if (tmpmap.ContainsKey("size"))
416 hulls_size = tmpmap["size"].AsInteger();
417 }
418
419 if (submesh_offset < 0 || hulls_size == 0)
420 {
421 error = "Missing physics_convex block";
422 return false;
423 }
424
425 if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
426 {
427 error = "Bad physics_convex block";
428 return false;
429 }
430
431 submesh_offset = -1;
432
433 // only look for LOD meshs sizes
434
435 if (map.ContainsKey("high_lod"))
436 {
437 tmpmap = (OSDMap)map["high_lod"];
438 // see at least if there is a offset for this one
439 if (tmpmap.ContainsKey("offset"))
440 submesh_offset = tmpmap["offset"].AsInteger() + start;
441 if (tmpmap.ContainsKey("size"))
442 highlod_size = tmpmap["size"].AsInteger();
443 }
444
445 if (submesh_offset < 0 || highlod_size <= 0)
446 {
447 error = "Missing high_lod block";
448 return false;
449 }
450
451 bool haveprev = true;
452
453 if (map.ContainsKey("medium_lod"))
454 {
455 tmpmap = (OSDMap)map["medium_lod"];
456 if (tmpmap.ContainsKey("size"))
457 medlod_size = tmpmap["size"].AsInteger();
458 else
459 haveprev = false;
460 }
461
462 if (haveprev && map.ContainsKey("low_lod"))
463 {
464 tmpmap = (OSDMap)map["low_lod"];
465 if (tmpmap.ContainsKey("size"))
466 lowlod_size = tmpmap["size"].AsInteger();
467 else
468 haveprev = false;
469 }
470
471 if (haveprev && map.ContainsKey("lowest_lod"))
472 {
473 tmpmap = (OSDMap)map["lowest_lod"];
474 if (tmpmap.ContainsKey("size"))
475 lowestlod_size = tmpmap["size"].AsInteger();
476 }
477
478 if (map.ContainsKey("skin"))
479 {
480 tmpmap = (OSDMap)map["skin"];
481 if (tmpmap.ContainsKey("size"))
482 skin_size = tmpmap["size"].AsInteger();
483 }
484
485 cost.highLODSize = highlod_size;
486 cost.medLODSize = medlod_size;
487 cost.lowLODSize = lowlod_size;
488 cost.lowestLODSize = lowestlod_size;
489
490 submesh_offset = -1;
491
492 tmpmap = null;
493 if(map.ContainsKey("physics_mesh"))
494 tmpmap = (OSDMap)map["physics_mesh"];
495 else if (map.ContainsKey("physics_shape")) // old naming
496 tmpmap = (OSDMap)map["physics_shape"];
497
498 if(tmpmap != null)
499 {
500 if (tmpmap.ContainsKey("offset"))
501 submesh_offset = tmpmap["offset"].AsInteger() + start;
502 if (tmpmap.ContainsKey("size"))
503 physmesh_size = tmpmap["size"].AsInteger();
504
505 if (submesh_offset >= 0 || physmesh_size > 0)
506 {
507
508 if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
509 {
510 error = "Model data parsing error";
511 return false;
512 }
513 }
514 }
515
516 // upload is done in convex shape type so only one hull
517 phys_hullsvertices++;
518 cost.physicsCost = 0.04f * phys_hullsvertices;
519
520 float sfee;
521
522 sfee = data.Length; // start with total compressed data size
523
524 // penalize lod meshs that should be more builder optimized
525 sfee += medSizeWth * medlod_size;
526 sfee += lowSizeWth * lowlod_size;
527 sfee += lowestSizeWth * lowlod_size;
528
529 // physics
530 // favor potencial optimized meshs versus automatic decomposition
531 if (physmesh_size != 0)
532 sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull
533 else
534 sfee += physHullSizeWth * hulls_size;
535
536 // bytes to money
537 sfee *= bytecost;
538
539 cost.costFee = sfee;
540 return true;
541 }
542
543 // parses a LOD or physics mesh component
544 private bool submesh(byte[] data, int offset, int size, out int ntriangles)
545 {
546 ntriangles = 0;
547
548 OSD decodedMeshOsd = new OSD();
549 byte[] meshBytes = new byte[size];
550 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
551 try
552 {
553 using (MemoryStream inMs = new MemoryStream(meshBytes))
554 {
555 using (MemoryStream outMs = new MemoryStream())
556 {
557 using (ZOutputStream zOut = new ZOutputStream(outMs))
558 {
559 byte[] readBuffer = new byte[4096];
560 int readLen = 0;
561 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
562 {
563 zOut.Write(readBuffer, 0, readLen);
564 }
565 zOut.Flush();
566 outMs.Seek(0, SeekOrigin.Begin);
567
568 byte[] decompressedBuf = outMs.GetBuffer();
569 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
570 }
571 }
572 }
573 }
574 catch
575 {
576 return false;
577 }
578
579 OSDArray decodedMeshOsdArray = null;
580
581 byte[] dummy;
582
583 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
584 foreach (OSD subMeshOsd in decodedMeshOsdArray)
585 {
586 if (subMeshOsd is OSDMap)
587 {
588 OSDMap subtmpmap = (OSDMap)subMeshOsd;
589 if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"]))
590 continue;
591
592 if (!subtmpmap.ContainsKey("Position"))
593 return false;
594
595 if (subtmpmap.ContainsKey("TriangleList"))
596 {
597 dummy = subtmpmap["TriangleList"].AsBinary();
598 ntriangles += dummy.Length / bytesPerCoord;
599 }
600 else
601 return false;
602 }
603 }
604
605 return true;
606 }
607
608 // parses convex hulls component
609 private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls)
610 {
611 nvertices = 0;
612 nhulls = 1;
613
614 OSD decodedMeshOsd = new OSD();
615 byte[] meshBytes = new byte[size];
616 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
617 try
618 {
619 using (MemoryStream inMs = new MemoryStream(meshBytes))
620 {
621 using (MemoryStream outMs = new MemoryStream())
622 {
623 using (ZOutputStream zOut = new ZOutputStream(outMs))
624 {
625 byte[] readBuffer = new byte[4096];
626 int readLen = 0;
627 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
628 {
629 zOut.Write(readBuffer, 0, readLen);
630 }
631 zOut.Flush();
632 outMs.Seek(0, SeekOrigin.Begin);
633
634 byte[] decompressedBuf = outMs.GetBuffer();
635 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
636 }
637 }
638 }
639 }
640 catch
641 {
642 return false;
643 }
644
645 OSDMap cmap = (OSDMap)decodedMeshOsd;
646 if (cmap == null)
647 return false;
648
649 byte[] dummy;
650
651 // must have one of this
652 if (cmap.ContainsKey("BoundingVerts"))
653 {
654 dummy = cmap["BoundingVerts"].AsBinary();
655 nvertices = dummy.Length / bytesPerCoord;
656 }
657 else
658 return false;
659
660/* upload is done with convex shape type
661 if (cmap.ContainsKey("HullList"))
662 {
663 dummy = cmap["HullList"].AsBinary();
664 nhulls += dummy.Length;
665 }
666
667
668 if (cmap.ContainsKey("Positions"))
669 {
670 dummy = cmap["Positions"].AsBinary();
671 nvertices = dummy.Length / bytesPerCoord;
672 }
673 */
674
675 return true;
676 }
677
678 // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length
679 private float streamingCost(ameshCostParam curCost, float sqdiam)
680 {
681 // compute efective areas
682 float ma = 262144f;
683
684 float mh = sqdiam * highLodFactor;
685 if (mh > ma)
686 mh = ma;
687 float mm = sqdiam * midLodFactor;
688 if (mm > ma)
689 mm = ma;
690
691 float ml = sqdiam * lowLodFactor;
692 if (ml > ma)
693 ml = ma;
694
695 float mlst = ma;
696
697 mlst -= ml;
698 ml -= mm;
699 mm -= mh;
700
701 if (mlst < 1.0f)
702 mlst = 1.0f;
703 if (ml < 1.0f)
704 ml = 1.0f;
705 if (mm < 1.0f)
706 mm = 1.0f;
707 if (mh < 1.0f)
708 mh = 1.0f;
709
710 ma = mlst + ml + mm + mh;
711
712 // get LODs compressed sizes
713 // giving 384 bytes bonus
714 int lst = curCost.lowestLODSize - 384;
715 int l = curCost.lowLODSize - 384;
716 int m = curCost.medLODSize - 384;
717 int h = curCost.highLODSize - 384;
718
719 // use previus higher LOD size on missing ones
720 if (m <= 0)
721 m = h;
722 if (l <= 0)
723 l = m;
724 if (lst <= 0)
725 lst = l;
726
727 // force minumum sizes
728 if (lst < 16)
729 lst = 16;
730 if (l < 16)
731 l = 16;
732 if (m < 16)
733 m = 16;
734 if (h < 16)
735 h = 16;
736
737 // compute cost weighted by relative effective areas
738 float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh;
739 cost /= ma;
740
741 cost *= 0.004f; // overall tunning parameter
742
743 return cost;
744 }
745 }
746}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index 9b9f6a7..7c9a1c4 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -74,13 +74,12 @@ namespace OpenSim.Region.ClientStack.Linden
74 private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); 74 private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
75 75
76 protected Scene m_scene; 76 protected Scene m_scene;
77 77
78 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>(); 78 private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
79 79
80 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>(); 80 private Dictionary<UUID, Queue<OSD>> queues = new Dictionary<UUID, Queue<OSD>>();
81 private Dictionary<UUID, UUID> m_QueueUUIDAvatarMapping = new Dictionary<UUID, UUID>();
82 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>(); 81 private Dictionary<UUID, UUID> m_AvatarQueueUUIDMapping = new Dictionary<UUID, UUID>();
83 82
84 #region INonSharedRegionModule methods 83 #region INonSharedRegionModule methods
85 public virtual void Initialise(IConfigSource config) 84 public virtual void Initialise(IConfigSource config)
86 { 85 {
@@ -171,7 +170,7 @@ namespace OpenSim.Region.ClientStack.Linden
171 foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues) 170 foreach (KeyValuePair<UUID, Queue<OSD>> kvp in queues)
172 { 171 {
173 MainConsole.Instance.OutputFormat( 172 MainConsole.Instance.OutputFormat(
174 "For agent {0} there are {1} messages queued for send.", 173 "For agent {0} there are {1} messages queued for send.",
175 kvp.Key, kvp.Value.Count); 174 kvp.Key, kvp.Value.Count);
176 } 175 }
177 } 176 }
@@ -190,7 +189,7 @@ namespace OpenSim.Region.ClientStack.Linden
190 { 189 {
191 if (DebugLevel > 0) 190 if (DebugLevel > 0)
192 m_log.DebugFormat( 191 m_log.DebugFormat(
193 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", 192 "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
194 agentId, m_scene.RegionInfo.RegionName); 193 agentId, m_scene.RegionInfo.RegionName);
195 194
196 queues[agentId] = new Queue<OSD>(); 195 queues[agentId] = new Queue<OSD>();
@@ -201,6 +200,7 @@ namespace OpenSim.Region.ClientStack.Linden
201 } 200 }
202 201
203 /// <summary> 202 /// <summary>
203
204 /// May return a null queue 204 /// May return a null queue
205 /// </summary> 205 /// </summary>
206 /// <param name="agentId"></param> 206 /// <param name="agentId"></param>
@@ -231,26 +231,20 @@ namespace OpenSim.Region.ClientStack.Linden
231 lock (queue) 231 lock (queue)
232 queue.Enqueue(ev); 232 queue.Enqueue(ev);
233 } 233 }
234 else if (DebugLevel > 0) 234 else
235 { 235 {
236 ScenePresence sp = m_scene.GetScenePresence(avatarID);
237
238 // This assumes that an NPC should never have a queue.
239 if (sp != null && sp.PresenceType != PresenceType.Npc)
240 {
241 OSDMap evMap = (OSDMap)ev; 236 OSDMap evMap = (OSDMap)ev;
242 m_log.WarnFormat( 237 m_log.WarnFormat(
243 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}", 238 "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
244 sp.Name, sp.UUID, evMap["message"], m_scene.Name); 239 avatarID, evMap["message"], m_scene.Name);
245 }
246 } 240 }
247 } 241 }
248 catch (NullReferenceException e) 242 catch (NullReferenceException e)
249 { 243 {
250 m_log.Error("[EVENTQUEUE] Caught exception: " + e); 244 m_log.Error("[EVENTQUEUE] Caught exception: " + e);
251 return false; 245 return false;
252 } 246 }
253 247
254 return true; 248 return true;
255 } 249 }
256 250
@@ -263,28 +257,13 @@ namespace OpenSim.Region.ClientStack.Linden
263 lock (queues) 257 lock (queues)
264 queues.Remove(agentID); 258 queues.Remove(agentID);
265 259
266 List<UUID> removeitems = new List<UUID>();
267 lock (m_AvatarQueueUUIDMapping) 260 lock (m_AvatarQueueUUIDMapping)
268 m_AvatarQueueUUIDMapping.Remove(agentID); 261 m_AvatarQueueUUIDMapping.Remove(agentID);
269 262
270 UUID searchval = UUID.Zero; 263 lock (m_ids)
271
272 removeitems.Clear();
273
274 lock (m_QueueUUIDAvatarMapping)
275 { 264 {
276 foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) 265 if (!m_ids.ContainsKey(agentID))
277 { 266 m_ids.Remove(agentID);
278 searchval = m_QueueUUIDAvatarMapping[ky];
279
280 if (searchval == agentID)
281 {
282 removeitems.Add(ky);
283 }
284 }
285
286 foreach (UUID ky in removeitems)
287 m_QueueUUIDAvatarMapping.Remove(ky);
288 } 267 }
289 268
290 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 269 // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
@@ -309,55 +288,95 @@ namespace OpenSim.Region.ClientStack.Linden
309 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", 288 "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
310 agentID, caps, m_scene.RegionInfo.RegionName); 289 agentID, caps, m_scene.RegionInfo.RegionName);
311 290
312 // Let's instantiate a Queue for this agent right now
313 TryGetQueue(agentID);
314
315 UUID eventQueueGetUUID; 291 UUID eventQueueGetUUID;
292 Queue<OSD> queue;
293 Random rnd = new Random(Environment.TickCount);
294 int nrnd = rnd.Next(30000000);
295 if (nrnd < 0)
296 nrnd = -nrnd;
316 297
317 lock (m_AvatarQueueUUIDMapping) 298 lock (queues)
318 { 299 {
319 // Reuse open queues. The client does! 300 if (queues.ContainsKey(agentID))
320 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) 301 queue = queues[agentID];
302 else
303 queue = null;
304
305 if (queue == null)
321 { 306 {
322 //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); 307 queue = new Queue<OSD>();
323 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; 308 queues[agentID] = queue;
309
310 // push markers to handle old responses still waiting
311 // this will cost at most viewer getting two forced noevents
312 // even being a new queue better be safe
313 queue.Enqueue(null);
314 queue.Enqueue(null); // one should be enough
315
316 lock (m_AvatarQueueUUIDMapping)
317 {
318 eventQueueGetUUID = UUID.Random();
319 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
320 {
321 // oops this should not happen ?
322 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue");
323 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
324 }
325 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
326 }
327 lock (m_ids)
328 {
329 if (!m_ids.ContainsKey(agentID))
330 m_ids.Add(agentID, nrnd);
331 else
332 m_ids[agentID] = nrnd;
333 }
324 } 334 }
325 else 335 else
326 { 336 {
327 eventQueueGetUUID = UUID.Random(); 337 // push markers to handle old responses still waiting
328 //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); 338 // this will cost at most viewer getting two forced noevents
339 // even being a new queue better be safe
340 queue.Enqueue(null);
341 queue.Enqueue(null); // one should be enough
342
343 // reuse or not to reuse TODO FIX
344 lock (m_AvatarQueueUUIDMapping)
345 {
346 // Reuse open queues. The client does!
347 // Its reuse caps path not queues those are been reused already
348 if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
349 {
350 m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
351 eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
352 }
353 else
354 {
355 eventQueueGetUUID = UUID.Random();
356 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
357 m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
358 }
359 }
360 lock (m_ids)
361 {
362 // change to negative numbers so they are changed at end of sending first marker
363 // old data on a queue may be sent on a response for a new caps
364 // but at least will be sent with coerent IDs
365 if (!m_ids.ContainsKey(agentID))
366 m_ids.Add(agentID, -nrnd); // should not happen
367 else
368 m_ids[agentID] = -m_ids[agentID];
369 }
329 } 370 }
330 } 371 }
331 372
332 lock (m_QueueUUIDAvatarMapping)
333 {
334 if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID))
335 m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID);
336 }
337
338 lock (m_AvatarQueueUUIDMapping)
339 {
340 if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID))
341 m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
342 }
343
344 caps.RegisterPollHandler( 373 caps.RegisterPollHandler(
345 "EventQueueGet", 374 "EventQueueGet",
346 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); 375 new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
347
348 Random rnd = new Random(Environment.TickCount);
349 lock (m_ids)
350 {
351 if (!m_ids.ContainsKey(agentID))
352 m_ids.Add(agentID, rnd.Next(30000000));
353 }
354 } 376 }
355 377
356 public bool HasEvents(UUID requestID, UUID agentID) 378 public bool HasEvents(UUID requestID, UUID agentID)
357 { 379 {
358 // Don't use this, because of race conditions at agent closing time
359 //Queue<OSD> queue = TryGetQueue(agentID);
360
361 Queue<OSD> queue = GetQueue(agentID); 380 Queue<OSD> queue = GetQueue(agentID);
362 if (queue != null) 381 if (queue != null)
363 lock (queue) 382 lock (queue)
@@ -366,7 +385,8 @@ namespace OpenSim.Region.ClientStack.Linden
366 return queue.Count > 0; 385 return queue.Count > 0;
367 } 386 }
368 387
369 return false; 388 //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID);
389 return true;
370 } 390 }
371 391
372 /// <summary> 392 /// <summary>
@@ -383,6 +403,10 @@ namespace OpenSim.Region.ClientStack.Linden
383 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); 403 ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
384 } 404 }
385 } 405 }
406 public void Drop(UUID requestID, UUID pAgentId)
407 {
408 // do nothing for now, hope client close will do it
409 }
386 410
387 public Hashtable GetEvents(UUID requestID, UUID pAgentId) 411 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
388 { 412 {
@@ -395,55 +419,65 @@ namespace OpenSim.Region.ClientStack.Linden
395 return NoEvents(requestID, pAgentId); 419 return NoEvents(requestID, pAgentId);
396 } 420 }
397 421
398 OSD element; 422 OSD element = null;;
423 OSDArray array = new OSDArray();
424 int thisID = 0;
425 bool negativeID = false;
426
399 lock (queue) 427 lock (queue)
400 { 428 {
401 if (queue.Count == 0) 429 if (queue.Count == 0)
402 return NoEvents(requestID, pAgentId); 430 return NoEvents(requestID, pAgentId);
403 element = queue.Dequeue(); // 15s timeout
404 }
405
406 int thisID = 0;
407 lock (m_ids)
408 thisID = m_ids[pAgentId];
409 431
410 OSDArray array = new OSDArray(); 432 lock (m_ids)
411 if (element == null) // didn't have an event in 15s 433 thisID = m_ids[pAgentId];
412 {
413 // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
414 array.Add(EventQueueHelper.KeepAliveEvent());
415 //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName);
416 }
417 else
418 {
419 if (DebugLevel > 0)
420 LogOutboundDebugMessage(element, pAgentId);
421 434
422 array.Add(element); 435 if (thisID < 0)
436 {
437 negativeID = true;
438 thisID = -thisID;
439 }
423 440
424 lock (queue) 441 while (queue.Count > 0)
425 { 442 {
426 while (queue.Count > 0) 443 element = queue.Dequeue();
427 { 444 // add elements until a marker is found
428 element = queue.Dequeue(); 445 // so they get into a response
446 if (element == null)
447 break;
448 if (DebugLevel > 0)
449 LogOutboundDebugMessage(element, pAgentId);
450 array.Add(element);
451 thisID++;
452 }
453 }
429 454
430 if (DebugLevel > 0) 455 OSDMap events = null;
431 LogOutboundDebugMessage(element, pAgentId);
432 456
433 array.Add(element); 457 if (array.Count > 0)
434 thisID++; 458 {
435 } 459 events = new OSDMap();
436 } 460 events.Add("events", array);
461 events.Add("id", new OSDInteger(thisID));
437 } 462 }
438 463
439 OSDMap events = new OSDMap(); 464 if (negativeID && element == null)
440 events.Add("events", array); 465 {
466 Random rnd = new Random(Environment.TickCount);
467 thisID = rnd.Next(30000000);
468 if (thisID < 0)
469 thisID = -thisID;
470 }
441 471
442 events.Add("id", new OSDInteger(thisID));
443 lock (m_ids) 472 lock (m_ids)
444 { 473 {
445 m_ids[pAgentId] = thisID + 1; 474 m_ids[pAgentId] = thisID + 1;
446 } 475 }
476
477 // if there where no elements before a marker send a NoEvents
478 if (array.Count == 0)
479 return NoEvents(requestID, pAgentId);
480
447 Hashtable responsedata = new Hashtable(); 481 Hashtable responsedata = new Hashtable();
448 responsedata["int_response_code"] = 200; 482 responsedata["int_response_code"] = 200;
449 responsedata["content_type"] = "application/xml"; 483 responsedata["content_type"] = "application/xml";
@@ -461,266 +495,18 @@ namespace OpenSim.Region.ClientStack.Linden
461 responsedata["content_type"] = "text/plain"; 495 responsedata["content_type"] = "text/plain";
462 responsedata["keepalive"] = false; 496 responsedata["keepalive"] = false;
463 responsedata["reusecontext"] = false; 497 responsedata["reusecontext"] = false;
464 responsedata["str_response_string"] = "Upstream error: "; 498 responsedata["str_response_string"] = "<llsd></llsd>";
465 responsedata["error_status_text"] = "Upstream error:"; 499 responsedata["error_status_text"] = "<llsd></llsd>";
466 responsedata["http_protocol_version"] = "HTTP/1.0"; 500 responsedata["http_protocol_version"] = "HTTP/1.0";
467 return responsedata; 501 return responsedata;
468 } 502 }
469 503/* this is not a event message
470// public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps)
471// {
472// // TODO: this has to be redone to not busy-wait (and block the thread),
473// // TODO: as soon as we have a non-blocking way to handle HTTP-requests.
474//
475//// if (m_log.IsDebugEnabled)
476//// {
477//// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ ";
478//// foreach (object key in request.Keys)
479//// {
480//// debug += key.ToString() + "=" + request[key].ToString() + " ";
481//// }
482//// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name);
483//// }
484//
485// Queue<OSD> queue = TryGetQueue(agentID);
486// OSD element;
487//
488// lock (queue)
489// element = queue.Dequeue(); // 15s timeout
490//
491// Hashtable responsedata = new Hashtable();
492//
493// int thisID = 0;
494// lock (m_ids)
495// thisID = m_ids[agentID];
496//
497// if (element == null)
498// {
499// //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName);
500// if (thisID == -1) // close-request
501// {
502// m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName);
503// responsedata["int_response_code"] = 404; //501; //410; //404;
504// responsedata["content_type"] = "text/plain";
505// responsedata["keepalive"] = false;
506// responsedata["str_response_string"] = "Closed EQG";
507// return responsedata;
508// }
509// responsedata["int_response_code"] = 502;
510// responsedata["content_type"] = "text/plain";
511// responsedata["keepalive"] = false;
512// responsedata["str_response_string"] = "Upstream error: ";
513// responsedata["error_status_text"] = "Upstream error:";
514// responsedata["http_protocol_version"] = "HTTP/1.0";
515// return responsedata;
516// }
517//
518// OSDArray array = new OSDArray();
519// if (element == null) // didn't have an event in 15s
520// {
521// // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say!
522// array.Add(EventQueueHelper.KeepAliveEvent());
523// //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
524// }
525// else
526// {
527// array.Add(element);
528//
529// if (element is OSDMap)
530// {
531// OSDMap ev = (OSDMap)element;
532// m_log.DebugFormat(
533// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
534// ev["message"], m_scene.GetScenePresence(agentID).Name);
535// }
536//
537// lock (queue)
538// {
539// while (queue.Count > 0)
540// {
541// element = queue.Dequeue();
542//
543// if (element is OSDMap)
544// {
545// OSDMap ev = (OSDMap)element;
546// m_log.DebugFormat(
547// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
548// ev["message"], m_scene.GetScenePresence(agentID).Name);
549// }
550//
551// array.Add(element);
552// thisID++;
553// }
554// }
555// }
556//
557// OSDMap events = new OSDMap();
558// events.Add("events", array);
559//
560// events.Add("id", new OSDInteger(thisID));
561// lock (m_ids)
562// {
563// m_ids[agentID] = thisID + 1;
564// }
565//
566// responsedata["int_response_code"] = 200;
567// responsedata["content_type"] = "application/xml";
568// responsedata["keepalive"] = false;
569// responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events);
570//
571// m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]);
572//
573// return responsedata;
574// }
575
576// public Hashtable EventQueuePath2(Hashtable request)
577// {
578// string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/","");
579// // pull off the last "/" in the path.
580// Hashtable responsedata = new Hashtable();
581// capuuid = capuuid.Substring(0, capuuid.Length - 1);
582// capuuid = capuuid.Replace("/CAPS/EQG/", "");
583// UUID AvatarID = UUID.Zero;
584// UUID capUUID = UUID.Zero;
585//
586// // parse the path and search for the avatar with it registered
587// if (UUID.TryParse(capuuid, out capUUID))
588// {
589// lock (m_QueueUUIDAvatarMapping)
590// {
591// if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
592// {
593// AvatarID = m_QueueUUIDAvatarMapping[capUUID];
594// }
595// }
596//
597// if (AvatarID != UUID.Zero)
598// {
599// return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID));
600// }
601// else
602// {
603// responsedata["int_response_code"] = 404;
604// responsedata["content_type"] = "text/plain";
605// responsedata["keepalive"] = false;
606// responsedata["str_response_string"] = "Not Found";
607// responsedata["error_status_text"] = "Not Found";
608// responsedata["http_protocol_version"] = "HTTP/1.0";
609// return responsedata;
610// // return 404
611// }
612// }
613// else
614// {
615// responsedata["int_response_code"] = 404;
616// responsedata["content_type"] = "text/plain";
617// responsedata["keepalive"] = false;
618// responsedata["str_response_string"] = "Not Found";
619// responsedata["error_status_text"] = "Not Found";
620// responsedata["http_protocol_version"] = "HTTP/1.0";
621// return responsedata;
622// // return 404
623// }
624// }
625
626 public OSD EventQueueFallBack(string path, OSD request, string endpoint)
627 {
628 // This is a fallback element to keep the client from loosing EventQueueGet
629 // Why does CAPS fail sometimes!?
630 m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!");
631 string capuuid = path.Replace("/CAPS/EQG/","");
632 capuuid = capuuid.Substring(0, capuuid.Length - 1);
633
634// UUID AvatarID = UUID.Zero;
635 UUID capUUID = UUID.Zero;
636 if (UUID.TryParse(capuuid, out capUUID))
637 {
638/* Don't remove this yet code cleaners!
639 * Still testing this!
640 *
641 lock (m_QueueUUIDAvatarMapping)
642 {
643 if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID))
644 {
645 AvatarID = m_QueueUUIDAvatarMapping[capUUID];
646 }
647 }
648
649
650 if (AvatarID != UUID.Zero)
651 {
652 // Repair the CAP!
653 //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID);
654 //string capsBase = "/CAPS/EQG/";
655 //caps.RegisterHandler("EventQueueGet",
656 //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/",
657 //delegate(Hashtable m_dhttpMethod)
658 //{
659 // return ProcessQueue(m_dhttpMethod, AvatarID, caps);
660 //}));
661 // start new ID sequence.
662 Random rnd = new Random(System.Environment.TickCount);
663 lock (m_ids)
664 {
665 if (!m_ids.ContainsKey(AvatarID))
666 m_ids.Add(AvatarID, rnd.Next(30000000));
667 }
668
669
670 int thisID = 0;
671 lock (m_ids)
672 thisID = m_ids[AvatarID];
673
674 BlockingLLSDQueue queue = GetQueue(AvatarID);
675 OSDArray array = new OSDArray();
676 LLSD element = queue.Dequeue(15000); // 15s timeout
677 if (element == null)
678 {
679
680 array.Add(EventQueueHelper.KeepAliveEvent());
681 }
682 else
683 {
684 array.Add(element);
685 while (queue.Count() > 0)
686 {
687 array.Add(queue.Dequeue(1));
688 thisID++;
689 }
690 }
691 OSDMap events = new OSDMap();
692 events.Add("events", array);
693
694 events.Add("id", new LLSDInteger(thisID));
695
696 lock (m_ids)
697 {
698 m_ids[AvatarID] = thisID + 1;
699 }
700
701 return events;
702 }
703 else
704 {
705 return new LLSD();
706 }
707*
708*/
709 }
710 else
711 {
712 //return new LLSD();
713 }
714
715 return new OSDString("shutdown404!");
716 }
717
718 public void DisableSimulator(ulong handle, UUID avatarID) 504 public void DisableSimulator(ulong handle, UUID avatarID)
719 { 505 {
720 OSD item = EventQueueHelper.DisableSimulator(handle); 506 OSD item = EventQueueHelper.DisableSimulator(handle);
721 Enqueue(item, avatarID); 507 Enqueue(item, avatarID);
722 } 508 }
723 509*/
724 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) 510 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
725 { 511 {
726 if (DebugLevel > 0) 512 if (DebugLevel > 0)
@@ -732,7 +518,7 @@ namespace OpenSim.Region.ClientStack.Linden
732 } 518 }
733 519
734 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, 520 public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath,
735 ulong regionHandle, int regionSizeX, int regionSizeY) 521 ulong regionHandle, int regionSizeX, int regionSizeY)
736 { 522 {
737 if (DebugLevel > 0) 523 if (DebugLevel > 0)
738 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}", 524 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}",
@@ -742,9 +528,9 @@ namespace OpenSim.Region.ClientStack.Linden
742 Enqueue(item, avatarID); 528 Enqueue(item, avatarID);
743 } 529 }
744 530
745 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, 531 public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
746 IPEndPoint regionExternalEndPoint, 532 IPEndPoint regionExternalEndPoint,
747 uint locationID, uint flags, string capsURL, 533 uint locationID, uint flags, string capsURL,
748 UUID avatarID, int regionSizeX, int regionSizeY) 534 UUID avatarID, int regionSizeX, int regionSizeY)
749 { 535 {
750 if (DebugLevel > 0) 536 if (DebugLevel > 0)
@@ -774,33 +560,40 @@ namespace OpenSim.Region.ClientStack.Linden
774 uint timeStamp, bool offline, int parentEstateID, Vector3 position, 560 uint timeStamp, bool offline, int parentEstateID, Vector3 position,
775 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) 561 uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket)
776 { 562 {
777 OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, 563 OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
778 timeStamp, offline, parentEstateID, position, ttl, transactionID, 564 timeStamp, offline, parentEstateID, position, ttl, transactionID,
779 fromGroup, binaryBucket); 565 fromGroup, binaryBucket);
780 Enqueue(item, toAgent); 566 Enqueue(item, toAgent);
781 //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item); 567 //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item);
782 568
783 } 569 }
784 570
785 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, 571 public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat,
786 bool isModerator, bool textMute) 572 bool isModerator, bool textMute, bool isEnterorLeave)
787 { 573 {
788 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, 574 OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
789 isModerator, textMute); 575 isModerator, textMute, isEnterorLeave);
790 Enqueue(item, fromAgent); 576 Enqueue(item, toAgent);
791 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); 577 //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
792 } 578 }
793 579
580 public void ChatterBoxForceClose(UUID toAgent, UUID sessionID, string reason)
581 {
582 OSD item = EventQueueHelper.ChatterBoxForceClose(sessionID, reason);
583
584 Enqueue(item, toAgent);
585 }
586
794 public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) 587 public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
795 { 588 {
796 OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage); 589 OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage);
797 Enqueue(item, avatarID); 590 Enqueue(item, avatarID);
798 } 591 }
799 592
800 public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) 593 public void GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data)
801 { 594 {
802 OSD item = EventQueueHelper.GroupMembership(groupUpdate); 595 OSD item = EventQueueHelper.GroupMembershipData(receiverAgent, data);
803 Enqueue(item, avatarID); 596 Enqueue(item, receiverAgent);
804 } 597 }
805 598
806 public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID) 599 public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID)
@@ -827,4 +620,4 @@ namespace OpenSim.Region.ClientStack.Linden
827 Enqueue(item, avatarID); 620 Enqueue(item, avatarID);
828 } 621 }
829 } 622 }
830} \ No newline at end of file 623}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 384af74..461f776 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -32,6 +32,8 @@ using OpenMetaverse.Packets;
32using OpenMetaverse.StructuredData; 32using OpenMetaverse.StructuredData;
33using OpenMetaverse.Messages.Linden; 33using OpenMetaverse.Messages.Linden;
34 34
35using OpenSim.Framework;
36
35namespace OpenSim.Region.ClientStack.Linden 37namespace OpenSim.Region.ClientStack.Linden
36{ 38{
37 public class EventQueueHelper 39 public class EventQueueHelper
@@ -76,9 +78,9 @@ namespace OpenSim.Region.ClientStack.Linden
76 78
77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); 79 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); 80 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); 81 llsdSimInfo.Add("Port", OSD.FromInteger(endPoint.Port));
80 llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint) regionSizeX)); 82 llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
81 llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint) regionSizeY)); 83 llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
82 84
83 OSDArray arr = new OSDArray(1); 85 OSDArray arr = new OSDArray(1);
84 arr.Add(llsdSimInfo); 86 arr.Add(llsdSimInfo);
@@ -88,7 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden
88 90
89 return BuildEvent("EnableSimulator", llsdBody); 91 return BuildEvent("EnableSimulator", llsdBody);
90 } 92 }
91 93/*
92 public static OSD DisableSimulator(ulong handle) 94 public static OSD DisableSimulator(ulong handle)
93 { 95 {
94 //OSDMap llsdSimInfo = new OSDMap(1); 96 //OSDMap llsdSimInfo = new OSDMap(1);
@@ -103,7 +105,7 @@ namespace OpenSim.Region.ClientStack.Linden
103 105
104 return BuildEvent("DisableSimulator", llsdBody); 106 return BuildEvent("DisableSimulator", llsdBody);
105 } 107 }
106 108*/
107 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, 109 public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
108 IPEndPoint newRegionExternalEndPoint, 110 IPEndPoint newRegionExternalEndPoint,
109 string capsURL, UUID agentID, UUID sessionID, 111 string capsURL, UUID agentID, UUID sessionID,
@@ -157,6 +159,12 @@ namespace OpenSim.Region.ClientStack.Linden
157 uint locationID, uint flags, string capsURL, UUID agentID, 159 uint locationID, uint flags, string capsURL, UUID agentID,
158 int regionSizeX, int regionSizeY) 160 int regionSizeX, int regionSizeY)
159 { 161 {
162 // not sure why flags get overwritten here
163 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
164 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
165 else
166 flags = (uint)TeleportFlags.ViaLocation;
167
160 OSDMap info = new OSDMap(); 168 OSDMap info = new OSDMap();
161 info.Add("AgentID", OSD.FromUUID(agentID)); 169 info.Add("AgentID", OSD.FromUUID(agentID));
162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? 170 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
@@ -165,7 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden
165 info.Add("SimAccess", OSD.FromInteger(simAccess)); 173 info.Add("SimAccess", OSD.FromInteger(simAccess));
166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); 174 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 175 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
168 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 176// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
177 info.Add("TeleportFlags", OSD.FromUInteger(flags));
169 info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); 178 info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
170 info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); 179 info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
171 180
@@ -185,13 +194,13 @@ namespace OpenSim.Region.ClientStack.Linden
185 script.Add("ItemID", OSD.FromUUID(itemID)); 194 script.Add("ItemID", OSD.FromUUID(itemID));
186 script.Add("Running", OSD.FromBoolean(running)); 195 script.Add("Running", OSD.FromBoolean(running));
187 script.Add("Mono", OSD.FromBoolean(mono)); 196 script.Add("Mono", OSD.FromBoolean(mono));
188 197
189 OSDArray scriptArr = new OSDArray(); 198 OSDArray scriptArr = new OSDArray();
190 scriptArr.Add(script); 199 scriptArr.Add(script);
191 200
192 OSDMap body = new OSDMap(); 201 OSDMap body = new OSDMap();
193 body.Add("Script", scriptArr); 202 body.Add("Script", scriptArr);
194 203
195 return BuildEvent("ScriptRunningReply", body); 204 return BuildEvent("ScriptRunningReply", body);
196 } 205 }
197 206
@@ -204,8 +213,8 @@ namespace OpenSim.Region.ClientStack.Linden
204 {"sim-ip-and-port", new OSDString(simIpAndPort)}, 213 {"sim-ip-and-port", new OSDString(simIpAndPort)},
205 {"seed-capability", new OSDString(seedcap)}, 214 {"seed-capability", new OSDString(seedcap)},
206 {"region-handle", OSD.FromULong(regionHandle)}, 215 {"region-handle", OSD.FromULong(regionHandle)},
207 {"region-size-x", OSD.FromInteger(regionSizeX)}, 216 {"region-size-x", OSD.FromUInteger((uint)regionSizeX)},
208 {"region-size-y", OSD.FromInteger(regionSizeY)} 217 {"region-size-y", OSD.FromUInteger((uint)regionSizeY)}
209 }; 218 };
210 219
211 return BuildEvent("EstablishAgentCommunication", body); 220 return BuildEvent("EstablishAgentCommunication", body);
@@ -234,7 +243,7 @@ namespace OpenSim.Region.ClientStack.Linden
234 { 243 {
235 OSDMap messageParams = new OSDMap(15); 244 OSDMap messageParams = new OSDMap(15);
236 messageParams.Add("type", new OSDInteger((int)dialog)); 245 messageParams.Add("type", new OSDInteger((int)dialog));
237 246
238 OSDArray positionArray = new OSDArray(3); 247 OSDArray positionArray = new OSDArray(3);
239 positionArray.Add(OSD.FromReal(position.X)); 248 positionArray.Add(OSD.FromReal(position.X));
240 positionArray.Add(OSD.FromReal(position.Y)); 249 positionArray.Add(OSD.FromReal(position.Y));
@@ -299,20 +308,29 @@ namespace OpenSim.Region.ClientStack.Linden
299 } 308 }
300 309
301 public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID, 310 public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID,
302 UUID agentID, bool canVoiceChat, bool isModerator, bool textMute) 311 UUID agentID, bool canVoiceChat, bool isModerator, bool textMute, bool isEnterorLeave)
303 { 312 {
304 OSDMap body = new OSDMap(); 313 OSDMap body = new OSDMap();
305 OSDMap agentUpdates = new OSDMap(); 314 OSDMap agentUpdates = new OSDMap();
306 OSDMap infoDetail = new OSDMap(); 315 OSDMap infoDetail = new OSDMap();
307 OSDMap mutes = new OSDMap(); 316 OSDMap mutes = new OSDMap();
308 317
318 // this should be a list of agents and parameters
319 // foreach agent
309 mutes.Add("text", OSD.FromBoolean(textMute)); 320 mutes.Add("text", OSD.FromBoolean(textMute));
310 infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat)); 321 infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat));
311 infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator)); 322 infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator));
312 infoDetail.Add("mutes", mutes); 323 infoDetail.Add("mutes", mutes);
313 OSDMap info = new OSDMap(); 324 OSDMap info = new OSDMap();
314 info.Add("info", infoDetail); 325 info.Add("info", infoDetail);
326 if(isEnterorLeave)
327 info.Add("transition",OSD.FromString("ENTER"));
328 else
329 info.Add("transition",OSD.FromString("LEAVE"));
315 agentUpdates.Add(agentID.ToString(), info); 330 agentUpdates.Add(agentID.ToString(), info);
331
332 // foreach end
333
316 body.Add("agent_updates", agentUpdates); 334 body.Add("agent_updates", agentUpdates);
317 body.Add("session_id", OSD.FromUUID(sessionID)); 335 body.Add("session_id", OSD.FromUUID(sessionID));
318 body.Add("updates", new OSD()); 336 body.Add("updates", new OSD());
@@ -324,40 +342,54 @@ namespace OpenSim.Region.ClientStack.Linden
324 return chatterBoxSessionAgentListUpdates; 342 return chatterBoxSessionAgentListUpdates;
325 } 343 }
326 344
327 public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket) 345 public static OSD ChatterBoxForceClose(UUID sessionID, string reason)
328 { 346 {
329 OSDMap groupUpdate = new OSDMap(); 347 OSDMap body = new OSDMap(2);
330 groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate")); 348 body.Add("session_id", new OSDUUID(sessionID));
349 body.Add("reason", new OSDString(reason));
331 350
332 OSDMap body = new OSDMap(); 351 OSDMap chatterBoxForceClose = new OSDMap(2);
333 OSDArray agentData = new OSDArray(); 352 chatterBoxForceClose.Add("message", new OSDString("ForceCloseChatterBoxSession"));
334 OSDMap agentDataMap = new OSDMap(); 353 chatterBoxForceClose.Add("body", body);
335 agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID)); 354 return chatterBoxForceClose;
336 agentData.Add(agentDataMap); 355 }
337 body.Add("AgentData", agentData);
338 356
339 OSDArray groupData = new OSDArray(); 357 public static OSD GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data)
358 {
359 OSDArray AgentData = new OSDArray(1);
360 OSDMap AgentDataMap = new OSDMap(1);
361 AgentDataMap.Add("AgentID", OSD.FromUUID(receiverAgent));
362 AgentData.Add(AgentDataMap);
340 363
341 foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData) 364 OSDArray GroupData = new OSDArray(data.Length);
365 OSDArray NewGroupData = new OSDArray(data.Length);
366
367 foreach (GroupMembershipData membership in data)
342 { 368 {
343 OSDMap groupDataMap = new OSDMap(); 369 OSDMap GroupDataMap = new OSDMap(6);
344 groupDataMap.Add("ListInProfile", OSD.FromBoolean(false)); 370 OSDMap NewGroupDataMap = new OSDMap(1);
345 groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID)); 371
346 groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID)); 372 GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID));
347 groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution)); 373 GroupDataMap.Add("GroupPowers", OSD.FromULong(membership.GroupPowers));
348 groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers))); 374 GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices));
349 groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName))); 375 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture));
350 groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices)); 376 GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution));
377 GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName));
378 NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile));
379
380 GroupData.Add(GroupDataMap);
381 NewGroupData.Add(NewGroupDataMap);
382 }
351 383
352 groupData.Add(groupDataMap); 384 OSDMap llDataStruct = new OSDMap(3);
385 llDataStruct.Add("AgentData", AgentData);
386 llDataStruct.Add("GroupData", GroupData);
387 llDataStruct.Add("NewGroupData", NewGroupData);
353 388
354 } 389 return BuildEvent("AgentGroupDataUpdate", llDataStruct);
355 body.Add("GroupData", groupData);
356 groupUpdate.Add("body", body);
357 390
358 return groupUpdate;
359 } 391 }
360 392
361 public static OSD PlacesQuery(PlacesReplyPacket PlacesReply) 393 public static OSD PlacesQuery(PlacesReplyPacket PlacesReply)
362 { 394 {
363 OSDMap placesReply = new OSDMap(); 395 OSDMap placesReply = new OSDMap();
@@ -391,7 +423,7 @@ namespace OpenSim.Region.ClientStack.Linden
391 QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID)); 423 QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID));
392 QueryDataMap.Add("ProductSku", OSD.FromInteger(0)); 424 QueryDataMap.Add("ProductSku", OSD.FromInteger(0));
393 QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price)); 425 QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price));
394 426
395 QueryData.Add(QueryDataMap); 427 QueryData.Add(QueryDataMap);
396 } 428 }
397 body.Add("QueryData", QueryData); 429 body.Add("QueryData", QueryData);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index 16a902d..ee3f4f1 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -71,7 +71,6 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
71 71
72 IConfigSource config = new IniConfigSource(); 72 IConfigSource config = new IniConfigSource();
73 config.AddConfig("Startup"); 73 config.AddConfig("Startup");
74 config.Configs["Startup"].Set("EventQueue", "true");
75 74
76 CapabilitiesModule capsModule = new CapabilitiesModule(); 75 CapabilitiesModule capsModule = new CapabilitiesModule();
77 m_eqgMod = new EventQueueGetModule(); 76 m_eqgMod = new EventQueueGetModule();
@@ -126,6 +125,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
126 125
127 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); 126 Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
128 127
128 // initial queue as null events
129 eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
130 if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK)
131 {
132 eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
133 if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK)
134 eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
135 }
136
129 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); 137 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK));
130 138
131// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); 139// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]);
@@ -172,7 +180,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
172 TestHelpers.InMethod(); 180 TestHelpers.InMethod();
173// TestHelpers.EnableLogging(); 181// TestHelpers.EnableLogging();
174 182
175 UUID npcId 183 UUID npcId
176 = m_npcMod.CreateNPC( 184 = m_npcMod.CreateNPC(
177 "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance()); 185 "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance());
178 186
@@ -187,4 +195,4 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
187 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway)); 195 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
188 } 196 }
189 } 197 }
190} \ No newline at end of file 198}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs
deleted file mode 100644
index 6617bbc..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs
+++ /dev/null
@@ -1,144 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using Mono.Addins;
39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers;
50
51namespace OpenSim.Region.ClientStack.Linden
52{
53
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetDisplayNamesModule")]
55 public class GetDisplayNamesModule : INonSharedRegionModule
56 {
57 private static readonly ILog m_log =
58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
60 private Scene m_scene;
61 private IUserManagement m_UserManager;
62
63 private bool m_Enabled = false;
64
65 private string m_URL;
66
67 #region ISharedRegionModule Members
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig config = source.Configs["ClientStack.LindenCaps"];
72 if (config == null)
73 return;
74
75 m_URL = config.GetString("Cap_GetDisplayNames", string.Empty);
76 if (m_URL != string.Empty)
77 m_Enabled = true;
78 }
79
80 public void AddRegion(Scene s)
81 {
82 if (!m_Enabled)
83 return;
84
85 m_scene = s;
86 }
87
88 public void RemoveRegion(Scene s)
89 {
90 if (!m_Enabled)
91 return;
92
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
94 m_scene = null;
95 }
96
97 public void RegionLoaded(Scene s)
98 {
99 if (!m_Enabled)
100 return;
101
102 m_UserManager = m_scene.RequestModuleInterface<IUserManagement>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
104 }
105
106 public void PostInitialise()
107 {
108 }
109
110 public void Close() { }
111
112 public string Name { get { return "GetDisplayNamesModule"; } }
113
114 public Type ReplaceableInterface
115 {
116 get { return null; }
117 }
118
119 #endregion
120
121 public void RegisterCaps(UUID agentID, Caps caps)
122 {
123 UUID capID = UUID.Random();
124
125 if (m_URL == "localhost")
126 {
127 m_log.DebugFormat("[GET_DISPLAY_NAMES]: /CAPS/agents/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
128 caps.RegisterHandler(
129 "GetDisplayNames",
130 new GetDisplayNamesHandler("/CAPS/agents" + capID + "/", m_UserManager, "GetDisplayNames", agentID.ToString()));
131 }
132 else
133 {
134// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
135 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
136 if (handler != null)
137 handler.RegisterExternalUserCapsHandler(agentID,caps,"GetDisplayNames", m_URL);
138 else
139 caps.RegisterHandler("GetDisplayNames", m_URL);
140 }
141 }
142
143 }
144}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index f57d857..ba917e39 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Reflection; 32using System.Reflection;
32using System.IO; 33using System.IO;
34using System.Threading;
33using System.Web; 35using System.Web;
34using Mono.Addins; 36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
35using log4net; 38using log4net;
36using Nini.Config; 39using Nini.Config;
37using OpenMetaverse; 40using OpenMetaverse;
@@ -52,15 +55,46 @@ namespace OpenSim.Region.ClientStack.Linden
52 { 55 {
53// private static readonly ILog m_log = 56// private static readonly ILog m_log =
54// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 58
56 private Scene m_scene; 59 private Scene m_scene;
57 private IAssetService m_AssetService; 60 private IAssetService m_AssetService;
58 private bool m_Enabled = true; 61 private bool m_Enabled = true;
59 private string m_URL; 62 private string m_URL;
63
60 private string m_URL2; 64 private string m_URL2;
61 private string m_RedirectURL = null; 65 private string m_RedirectURL = null;
62 private string m_RedirectURL2 = null; 66 private string m_RedirectURL2 = null;
63 67
68 struct aPollRequest
69 {
70 public PollServiceMeshEventArgs thepoll;
71 public UUID reqID;
72 public Hashtable request;
73 }
74
75 public class aPollResponse
76 {
77 public Hashtable response;
78 public int bytes;
79 public int lod;
80 }
81
82
83 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
84
85 private static GetMeshHandler m_getMeshHandler;
86
87 private IAssetService m_assetService = null;
88
89 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
90 private static Thread[] m_workerThreads = null;
91 private static int m_NumberScenes = 0;
92 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
93 new OpenSim.Framework.BlockingQueue<aPollRequest>();
94
95 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
96
97
64 #region Region Module interfaceBase Members 98 #region Region Module interfaceBase Members
65 99
66 public Type ReplaceableInterface 100 public Type ReplaceableInterface
@@ -87,6 +121,7 @@ namespace OpenSim.Region.ClientStack.Linden
87 if (m_URL2 != string.Empty) 121 if (m_URL2 != string.Empty)
88 { 122 {
89 m_Enabled = true; 123 m_Enabled = true;
124
90 m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); 125 m_RedirectURL2 = config.GetString("GetMesh2RedirectURL");
91 } 126 }
92 } 127 }
@@ -97,6 +132,8 @@ namespace OpenSim.Region.ClientStack.Linden
97 return; 132 return;
98 133
99 m_scene = pScene; 134 m_scene = pScene;
135
136 m_assetService = pScene.AssetService;
100 } 137 }
101 138
102 public void RemoveRegion(Scene scene) 139 public void RemoveRegion(Scene scene)
@@ -105,6 +142,9 @@ namespace OpenSim.Region.ClientStack.Linden
105 return; 142 return;
106 143
107 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 144 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
145 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
146 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
147 m_NumberScenes--;
108 m_scene = null; 148 m_scene = null;
109 } 149 }
110 150
@@ -115,55 +155,302 @@ namespace OpenSim.Region.ClientStack.Linden
115 155
116 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 156 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
117 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 157 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
118 } 158 // We'll reuse the same handler for all requests.
159 m_getMeshHandler = new GetMeshHandler(m_assetService);
160 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
161 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
119 162
163 m_NumberScenes++;
164
165 if (m_workerThreads == null)
166 {
167 m_workerThreads = new Thread[2];
168
169 for (uint i = 0; i < 2; i++)
170 {
171 m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests,
172 String.Format("GetMeshWorker{0}", i),
173 ThreadPriority.Normal,
174 true,
175 false,
176 null,
177 int.MaxValue);
178 }
179 }
180 }
120 181
121 public void Close() { } 182 public void Close()
183 {
184 if(m_NumberScenes <= 0 && m_workerThreads != null)
185 {
186 m_log.DebugFormat("[GetMeshModule] Closing");
187 foreach (Thread t in m_workerThreads)
188 Watchdog.AbortThread(t.ManagedThreadId);
189 // This will fail on region shutdown. Its harmless.
190 // Prevent red ink.
191 try
192 {
193 m_queue.Clear();
194 }
195 catch {}
196 }
197 }
122 198
123 public string Name { get { return "GetMeshModule"; } } 199 public string Name { get { return "GetMeshModule"; } }
124 200
125 #endregion 201 #endregion
126 202
203 private static void DoMeshRequests()
204 {
205 while(true)
206 {
207 aPollRequest poolreq = m_queue.Dequeue(4500);
208 Watchdog.UpdateThread();
209 if(m_NumberScenes <= 0)
210 return;
211 if(poolreq.reqID != UUID.Zero)
212 poolreq.thepoll.Process(poolreq);
213 }
214 }
127 215
128 public void RegisterCaps(UUID agentID, Caps caps) 216 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
217 public void ThrottleUpdate(ScenePresence p)
129 { 218 {
130 UUID capID = UUID.Random(); 219 UUID user = p.UUID;
131 bool getMeshRegistered = false; 220 int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset);
221 PollServiceMeshEventArgs args;
222 if (m_pollservices.TryGetValue(user, out args))
223 {
224 args.UpdateThrottle(imagethrottle);
225 }
226 }
227
228 private class PollServiceMeshEventArgs : PollServiceEventArgs
229 {
230 private List<Hashtable> requests =
231 new List<Hashtable>();
232 private Dictionary<UUID, aPollResponse> responses =
233 new Dictionary<UUID, aPollResponse>();
234
235 private Scene m_scene;
236 private MeshCapsDataThrottler m_throttler;
237 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
238 base(null, uri, null, null, null, pId, int.MaxValue)
239 {
240 m_scene = scene;
241 m_throttler = new MeshCapsDataThrottler(100000);
242 // x is request id, y is userid
243 HasEvents = (x, y) =>
244 {
245 lock (responses)
246 {
247 bool ret = m_throttler.hasEvents(x, responses);
248 return ret;
249
250 }
251 };
252 GetEvents = (x, y) =>
253 {
254 lock (responses)
255 {
256 try
257 {
258 return responses[x].response;
259 }
260 finally
261 {
262 responses.Remove(x);
263 m_throttler.PassTime();
264 }
265 }
266 };
267 // x is request id, y is request data hashtable
268 Request = (x, y) =>
269 {
270 aPollRequest reqinfo = new aPollRequest();
271 reqinfo.thepoll = this;
272 reqinfo.reqID = x;
273 reqinfo.request = y;
274
275 m_queue.Enqueue(reqinfo);
276 m_throttler.PassTime();
277 };
132 278
133 if (m_URL == string.Empty) 279 // this should never happen except possible on shutdown
280 NoEvents = (x, y) =>
281 {
282 /*
283 lock (requests)
284 {
285 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
286 requests.Remove(request);
287 }
288 */
289 Hashtable response = new Hashtable();
290
291 response["int_response_code"] = 500;
292 response["str_response_string"] = "Script timeout";
293 response["content_type"] = "text/plain";
294 response["keepalive"] = false;
295 response["reusecontext"] = false;
296
297 return response;
298 };
299 }
300
301 public void Process(aPollRequest requestinfo)
134 { 302 {
303 Hashtable response;
304
305 UUID requestID = requestinfo.reqID;
306
307 if(m_scene.ShuttingDown)
308 return;
309
310 // If the avatar is gone, don't bother to get the texture
311 if (m_scene.GetScenePresence(Id) == null)
312 {
313 response = new Hashtable();
314
315 response["int_response_code"] = 500;
316 response["str_response_string"] = "Script timeout";
317 response["content_type"] = "text/plain";
318 response["keepalive"] = false;
319 response["reusecontext"] = false;
320
321 lock (responses)
322 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
323
324 return;
325 }
326
327 response = m_getMeshHandler.Handle(requestinfo.request);
328 lock (responses)
329 {
330 responses[requestID] = new aPollResponse()
331 {
332 bytes = (int)response["int_bytes"],
333 lod = (int)response["int_lod"],
334 response = response
335 };
336
337 }
338 m_throttler.PassTime();
339 }
135 340
341 internal void UpdateThrottle(int pthrottle)
342 {
343 int tmp = 2 * pthrottle;
344 if(tmp < 10000)
345 tmp = 10000;
346 m_throttler.ThrottleBytes = tmp;
136 } 347 }
137 else if (m_URL == "localhost") 348 }
349
350 public void RegisterCaps(UUID agentID, Caps caps)
351 {
352// UUID capID = UUID.Random();
353 if (m_URL == "localhost")
138 { 354 {
139 getMeshRegistered = true; 355 string capUrl = "/CAPS/" + UUID.Random() + "/";
140 caps.RegisterHandler( 356
141 "GetMesh", 357 // Register this as a poll service
142 new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); 358 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
359
360 args.Type = PollServiceEventArgs.EventType.Mesh;
361 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
362
363 string hostName = m_scene.RegionInfo.ExternalHostName;
364 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
365 string protocol = "http";
366
367 if (MainServer.Instance.UseSSL)
368 {
369 hostName = MainServer.Instance.SSLCommonName;
370 port = MainServer.Instance.SSLPort;
371 protocol = "https";
372 }
373 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
374 m_pollservices[agentID] = args;
375 m_capsDict[agentID] = capUrl;
143 } 376 }
144 else 377 else
145 { 378 {
146 caps.RegisterHandler("GetMesh", m_URL); 379 caps.RegisterHandler("GetMesh", m_URL);
147 } 380 }
381 }
148 382
149 if(m_URL2 == string.Empty) 383 private void DeregisterCaps(UUID agentID, Caps caps)
384 {
385 string capUrl;
386 PollServiceMeshEventArgs args;
387 if (m_capsDict.TryGetValue(agentID, out capUrl))
388 {
389 MainServer.Instance.RemoveHTTPHandler("", capUrl);
390 m_capsDict.Remove(agentID);
391 }
392 if (m_pollservices.TryGetValue(agentID, out args))
150 { 393 {
394 m_pollservices.Remove(agentID);
395 }
396 }
397
398 internal sealed class MeshCapsDataThrottler
399 {
400 private double lastTimeElapsed = 0;
401 private double BytesSent = 0;
151 402
403 public MeshCapsDataThrottler(int pBytes)
404 {
405 if(pBytes < 10000)
406 pBytes = 10000;
407 ThrottleBytes = pBytes;
408 lastTimeElapsed = Util.GetTimeStampMS();
152 } 409 }
153 else if (m_URL2 == "localhost") 410
411 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
154 { 412 {
155 if (!getMeshRegistered) 413 PassTime();
414 // Note, this is called IN LOCK
415 bool haskey = responses.ContainsKey(key);
416
417 if (!haskey)
418 {
419 return false;
420 }
421 aPollResponse response;
422 if (responses.TryGetValue(key, out response))
156 { 423 {
157 caps.RegisterHandler( 424 // Normal
158 "GetMesh2", 425 if (BytesSent <= ThrottleBytes)
159 new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh2", agentID.ToString(), m_RedirectURL2)); 426 {
427 BytesSent += response.bytes;
428 return true;
429 }
430 else
431 {
432 return false;
433 }
160 } 434 }
435 return haskey;
161 } 436 }
162 else 437
438 public void PassTime()
163 { 439 {
164 caps.RegisterHandler("GetMesh2", m_URL2); 440 double currenttime = Util.GetTimeStampMS();
441 double timeElapsed = currenttime - lastTimeElapsed;
442 if(timeElapsed < 50.0)
443 return;
444 int add = (int)(ThrottleBytes * timeElapsed * 0.001);
445 if (add >= 1000)
446 {
447 lastTimeElapsed = currenttime;
448 BytesSent -= add;
449 if (BytesSent < 0) BytesSent = 0;
450 }
165 } 451 }
166 }
167 452
453 public int ThrottleBytes;
454 }
168 } 455 }
169} 456}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index bb932f2..b01c7dc 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -27,18 +27,13 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Specialized; 30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection; 31using System.Reflection;
34using System.IO; 32using System.Threading;
35using System.Web;
36using log4net; 33using log4net;
37using Nini.Config; 34using Nini.Config;
38using Mono.Addins; 35using Mono.Addins;
39using OpenMetaverse; 36using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework; 37using OpenSim.Framework;
43using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
@@ -47,6 +42,7 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
50 46
51namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
52{ 48{
@@ -54,27 +50,49 @@ namespace OpenSim.Region.ClientStack.Linden
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 51 public class GetTextureModule : INonSharedRegionModule
56 { 52 {
57// private static readonly ILog m_log = 53
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 struct aPollRequest
59 55 {
56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID;
58 public Hashtable request;
59 public bool send503;
60 }
61
62 public class aPollResponse
63 {
64 public Hashtable response;
65 public int bytes;
66 }
67
68
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
60 private Scene m_scene; 71 private Scene m_scene;
61 private IAssetService m_assetService;
62 72
63 private bool m_Enabled = false; 73 private static GetTextureHandler m_getTextureHandler;
74
75 private IAssetService m_assetService = null;
76
77 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
78 private static Thread[] m_workerThreads = null;
79 private static int m_NumberScenes = 0;
80 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
81 new OpenSim.Framework.BlockingQueue<aPollRequest>();
64 82
65 // TODO: Change this to a config option 83 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
66 private string m_RedirectURL = null;
67 84
68 private string m_URL; 85 private string m_Url = "localhost";
69 86
70 #region ISharedRegionModule Members 87 #region ISharedRegionModule Members
71 88
72 public void Initialise(IConfigSource source) 89 public void Initialise(IConfigSource source)
73 { 90 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"]; 91 IConfig config = source.Configs["ClientStack.LindenCaps"];
92
75 if (config == null) 93 if (config == null)
76 return; 94 return;
77 95/*
78 m_URL = config.GetString("Cap_GetTexture", string.Empty); 96 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist 97 // Cap doesn't exist
80 if (m_URL != string.Empty) 98 if (m_URL != string.Empty)
@@ -82,39 +100,108 @@ namespace OpenSim.Region.ClientStack.Linden
82 m_Enabled = true; 100 m_Enabled = true;
83 m_RedirectURL = config.GetString("GetTextureRedirectURL"); 101 m_RedirectURL = config.GetString("GetTextureRedirectURL");
84 } 102 }
103*/
104 m_Url = config.GetString("Cap_GetTexture", "localhost");
85 } 105 }
86 106
87 public void AddRegion(Scene s) 107 public void AddRegion(Scene s)
88 { 108 {
89 if (!m_Enabled)
90 return;
91
92 m_scene = s; 109 m_scene = s;
110 m_assetService = s.AssetService;
93 } 111 }
94 112
95 public void RemoveRegion(Scene s) 113 public void RemoveRegion(Scene s)
96 { 114 {
97 if (!m_Enabled)
98 return;
99
100 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 115 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
116 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
117 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
118 m_NumberScenes--;
101 m_scene = null; 119 m_scene = null;
102 } 120 }
103 121
104 public void RegionLoaded(Scene s) 122 public void RegionLoaded(Scene s)
105 { 123 {
106 if (!m_Enabled) 124 // We'll reuse the same handler for all requests.
107 return; 125 m_getTextureHandler = new GetTextureHandler(m_assetService);
108 126
109 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
110 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 127 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
128 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
129 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
130
131 m_NumberScenes++;
132
133 if (m_workerThreads == null)
134 {
135 m_workerThreads = new Thread[2];
136
137 for (uint i = 0; i < 2; i++)
138 {
139 m_workerThreads[i] = WorkManager.StartThread(DoTextureRequests,
140 String.Format("GetTextureWorker{0}", i),
141 ThreadPriority.Normal,
142 true,
143 false,
144 null,
145 int.MaxValue);
146 }
147 }
148 }
149 private int ExtractImageThrottle(byte[] pthrottles)
150 {
151
152 byte[] adjData;
153 int pos = 0;
154
155 if (!BitConverter.IsLittleEndian)
156 {
157 byte[] newData = new byte[7 * 4];
158 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
159
160 for (int i = 0; i < 7; i++)
161 Array.Reverse(newData, i * 4, 4);
162
163 adjData = newData;
164 }
165 else
166 {
167 adjData = pthrottles;
168 }
169
170 pos = pos + 20;
171 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
172 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
173 return texture;
174 }
175
176 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
177 public void ThrottleUpdate(ScenePresence p)
178 {
179 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
180 UUID user = p.UUID;
181 int imagethrottle = ExtractImageThrottle(throttles);
182 PollServiceTextureEventArgs args;
183 if (m_pollservices.TryGetValue(user,out args))
184 {
185 args.UpdateThrottle(imagethrottle);
186 }
111 } 187 }
112 188
113 public void PostInitialise() 189 public void PostInitialise()
114 { 190 {
115 } 191 }
116 192
117 public void Close() { } 193 public void Close()
194 {
195 if(m_NumberScenes <= 0 && m_workerThreads != null)
196 {
197 m_log.DebugFormat("[GetTextureModule] Closing");
198
199 foreach (Thread t in m_workerThreads)
200 Watchdog.AbortThread(t.ManagedThreadId);
201
202 m_queue.Clear();
203 }
204 }
118 205
119 public string Name { get { return "GetTextureModule"; } } 206 public string Name { get { return "GetTextureModule"; } }
120 207
@@ -125,28 +212,277 @@ namespace OpenSim.Region.ClientStack.Linden
125 212
126 #endregion 213 #endregion
127 214
128 public void RegisterCaps(UUID agentID, Caps caps) 215 private class PollServiceTextureEventArgs : PollServiceEventArgs
129 { 216 {
130 UUID capID = UUID.Random(); 217 private List<Hashtable> requests =
218 new List<Hashtable>();
219 private Dictionary<UUID, aPollResponse> responses =
220 new Dictionary<UUID, aPollResponse>();
221
222 private Scene m_scene;
223 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000);
224 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
225 base(null, "", null, null, null, pId, int.MaxValue)
226 {
227 m_scene = scene;
228 // x is request id, y is userid
229 HasEvents = (x, y) =>
230 {
231 lock (responses)
232 {
233 bool ret = m_throttler.hasEvents(x, responses);
234 return ret;
235
236 }
237 };
238 GetEvents = (x, y) =>
239 {
240 lock (responses)
241 {
242 try
243 {
244 return responses[x].response;
245 }
246 finally
247 {
248 responses.Remove(x);
249 m_throttler.PassTime();
250 }
251 }
252 };
253 // x is request id, y is request data hashtable
254 Request = (x, y) =>
255 {
256 aPollRequest reqinfo = new aPollRequest();
257 reqinfo.thepoll = this;
258 reqinfo.reqID = x;
259 reqinfo.request = y;
260 reqinfo.send503 = false;
261
262 lock (responses)
263 {
264 if (responses.Count > 0)
265 {
266 if (m_queue.Count() >= 4)
267 {
268 // Never allow more than 4 fetches to wait
269 reqinfo.send503 = true;
270 }
271 }
272 }
273 m_queue.Enqueue(reqinfo);
274 m_throttler.PassTime();
275 };
276
277 // this should never happen except possible on shutdown
278 NoEvents = (x, y) =>
279 {
280/*
281 lock (requests)
282 {
283 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
284 requests.Remove(request);
285 }
286*/
287 Hashtable response = new Hashtable();
131 288
132 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 289 response["int_response_code"] = 500;
133 if (m_URL == "localhost") 290 response["str_response_string"] = "Script timeout";
291 response["content_type"] = "text/plain";
292 response["keepalive"] = false;
293 response["reusecontext"] = false;
294
295 return response;
296 };
297 }
298
299 public void Process(aPollRequest requestinfo)
134 { 300 {
135// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 301 Hashtable response;
136 caps.RegisterHandler( 302
137 "GetTexture", 303 UUID requestID = requestinfo.reqID;
138 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString(), m_RedirectURL)); 304
305 if(m_scene.ShuttingDown)
306 return;
307
308 if (requestinfo.send503)
309 {
310 response = new Hashtable();
311
312 response["int_response_code"] = 503;
313 response["str_response_string"] = "Throttled";
314 response["content_type"] = "text/plain";
315 response["keepalive"] = false;
316 response["reusecontext"] = false;
317
318 Hashtable headers = new Hashtable();
319 headers["Retry-After"] = 30;
320 response["headers"] = headers;
321
322 lock (responses)
323 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
324
325 return;
326 }
327
328 // If the avatar is gone, don't bother to get the texture
329 if (m_scene.GetScenePresence(Id) == null)
330 {
331 response = new Hashtable();
332
333 response["int_response_code"] = 500;
334 response["str_response_string"] = "Script timeout";
335 response["content_type"] = "text/plain";
336 response["keepalive"] = false;
337 response["reusecontext"] = false;
338
339 lock (responses)
340 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
341
342 return;
343 }
344
345 response = m_getTextureHandler.Handle(requestinfo.request);
346 lock (responses)
347 {
348 responses[requestID] = new aPollResponse()
349 {
350 bytes = (int) response["int_bytes"],
351 response = response
352 };
353
354 }
355 m_throttler.PassTime();
139 } 356 }
140 else 357
358 internal void UpdateThrottle(int pimagethrottle)
141 { 359 {
142// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 360 int tmp = 2 * pimagethrottle;
361 if(tmp < 10000)
362 tmp = 10000;
363 m_throttler.ThrottleBytes = tmp;
364 }
365 }
366
367 private void RegisterCaps(UUID agentID, Caps caps)
368 {
369 if (m_Url == "localhost")
370 {
371 string capUrl = "/CAPS/" + UUID.Random() + "/";
372
373 // Register this as a poll service
374 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
375
376 args.Type = PollServiceEventArgs.EventType.Texture;
377 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
378
379 string hostName = m_scene.RegionInfo.ExternalHostName;
380 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
381 string protocol = "http";
382
383 if (MainServer.Instance.UseSSL)
384 {
385 hostName = MainServer.Instance.SSLCommonName;
386 port = MainServer.Instance.SSLPort;
387 protocol = "https";
388 }
143 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); 389 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
144 if (handler != null) 390 if (handler != null)
145 handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture", m_URL); 391 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
146 else 392 else
147 caps.RegisterHandler("GetTexture", m_URL); 393 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
394 m_pollservices[agentID] = args;
395 m_capsDict[agentID] = capUrl;
396 }
397 else
398 {
399 caps.RegisterHandler("GetTexture", m_Url);
400 }
401 }
402
403 private void DeregisterCaps(UUID agentID, Caps caps)
404 {
405 PollServiceTextureEventArgs args;
406
407 MainServer.Instance.RemoveHTTPHandler("", m_Url);
408 m_capsDict.Remove(agentID);
409
410 if (m_pollservices.TryGetValue(agentID, out args))
411 {
412 m_pollservices.Remove(agentID);
413 }
414 }
415
416 private static void DoTextureRequests()
417 {
418 while (true)
419 {
420 aPollRequest poolreq = m_queue.Dequeue(4500);
421 Watchdog.UpdateThread();
422 if(m_NumberScenes <= 0)
423 return;
424 if(poolreq.reqID != UUID.Zero)
425 poolreq.thepoll.Process(poolreq);
148 } 426 }
149 } 427 }
150 428
429 internal sealed class CapsDataThrottler
430 {
431 private double lastTimeElapsed = 0;
432 private volatile int BytesSent = 0;
433 public CapsDataThrottler(int pBytes)
434 {
435 if(pBytes < 10000)
436 pBytes = 10000;
437 ThrottleBytes = pBytes;
438 lastTimeElapsed = Util.GetTimeStampMS();
439 }
440 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
441 {
442 PassTime();
443 // Note, this is called IN LOCK
444 bool haskey = responses.ContainsKey(key);
445 if (!haskey)
446 {
447 return false;
448 }
449 GetTextureModule.aPollResponse response;
450 if (responses.TryGetValue(key, out response))
451 {
452 // This is any error response
453 if (response.bytes == 0)
454 return true;
455
456 // Normal
457 if (BytesSent <= ThrottleBytes)
458 {
459 BytesSent += response.bytes;
460 return true;
461 }
462 else
463 {
464 return false;
465 }
466 }
467
468 return haskey;
469 }
470
471 public void PassTime()
472 {
473 double currenttime = Util.GetTimeStampMS();
474 double timeElapsed = currenttime - lastTimeElapsed;
475 if(timeElapsed < 50.0)
476 return;
477 int add = (int)(ThrottleBytes * timeElapsed * 0.001);
478 if (add >= 1000)
479 {
480 lastTimeElapsed = currenttime;
481 BytesSent -= add;
482 if (BytesSent < 0) BytesSent = 0;
483 }
484 }
485 public int ThrottleBytes;
486 }
151 } 487 }
152} 488}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 45d33cd..44bf1a5 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -129,23 +129,23 @@ namespace OpenSim.Region.ClientStack.Linden
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); 129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130 130
131 OSDMap data = new OSDMap(); 131 OSDMap data = new OSDMap();
132 ScenePresence sp = m_scene.GetScenePresence(agentID); 132// ScenePresence sp = m_scene.GetScenePresence(m_agentID);
133 data["username"] = sp.Firstname + "." + sp.Lastname; 133// data["username"] = sp.Firstname + "." + sp.Lastname;
134 data["display_name_next_update"] = new OSDDate(DateTime.Now); 134// data["display_name_next_update"] = new OSDDate(DateTime.Now);
135 data["legacy_first_name"] = sp.Firstname; 135// data["legacy_first_name"] = sp.Firstname;
136 data["mesh_upload_status"] = "valid"; 136 data["mesh_upload_status"] = "valid";
137 data["display_name"] = sp.Firstname + " " + sp.Lastname; 137// data["display_name"] = sp.Firstname + " " + sp.Lastname;
138 data["legacy_last_name"] = sp.Lastname; 138// data["legacy_last_name"] = sp.Lastname;
139 data["id"] = agentID; 139// data["id"] = m_agentID;
140 data["is_display_name_default"] = true; 140// data["is_display_name_default"] = true;
141 141
142 //Send back data 142 //Send back data
143 Hashtable responsedata = new Hashtable(); 143 Hashtable responsedata = new Hashtable();
144 responsedata["int_response_code"] = 200; 144 responsedata["int_response_code"] = 200;
145 responsedata["content_type"] = "text/plain"; 145 responsedata["content_type"] = "text/plain";
146 responsedata["keepalive"] = false; 146 responsedata["keepalive"] = false;
147 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data); 147 responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data);
148 return responsedata; 148 return responsedata;
149 } 149 }
150 } 150 }
151} \ No newline at end of file 151}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
deleted file mode 100644
index f69a0bb..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ /dev/null
@@ -1,297 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Framework.Capabilities;
47using PermissionMask = OpenSim.Framework.PermissionMask;
48
49namespace OpenSim.Region.ClientStack.Linden
50{
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")]
52 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
53 {
54// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57// private IAssetService m_assetService;
58 private bool m_dumpAssetsToFile = false;
59 private bool m_enabled = true;
60 private int m_levelUpload = 0;
61
62 #region Region Module interfaceBase Members
63
64
65 public Type ReplaceableInterface
66 {
67 get { return null; }
68 }
69
70 public void Initialise(IConfigSource source)
71 {
72 IConfig meshConfig = source.Configs["Mesh"];
73 if (meshConfig == null)
74 return;
75
76 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
77 m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
78 }
79
80 public void AddRegion(Scene pScene)
81 {
82 m_scene = pScene;
83 }
84
85 public void RemoveRegion(Scene scene)
86 {
87
88 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
89 m_scene = null;
90 }
91
92 public void RegionLoaded(Scene scene)
93 {
94
95// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
96 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
97 }
98
99 #endregion
100
101
102 #region Region Module interface
103
104
105
106 public void Close() { }
107
108 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
109
110
111 public void RegisterCaps(UUID agentID, Caps caps)
112 {
113 if(!m_enabled)
114 return;
115
116 UUID capID = UUID.Random();
117
118// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
119 caps.RegisterHandler(
120 "NewFileAgentInventoryVariablePrice",
121 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
122 "POST",
123 "/CAPS/" + capID.ToString(),
124 req => NewAgentInventoryRequest(req, agentID),
125 "NewFileAgentInventoryVariablePrice",
126 agentID.ToString()));
127 }
128
129 #endregion
130
131 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
132 {
133 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
134 // you need to be aware of this
135
136 //if (llsdRequest.asset_type == "texture" ||
137 // llsdRequest.asset_type == "animation" ||
138 // llsdRequest.asset_type == "sound")
139 // {
140 // check user level
141
142 ScenePresence avatar = null;
143 IClientAPI client = null;
144 m_scene.TryGetScenePresence(agentID, out avatar);
145
146 if (avatar != null)
147 {
148 client = avatar.ControllingClient;
149
150 if (avatar.UserLevel < m_levelUpload)
151 {
152 if (client != null)
153 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
154
155 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
156 errorResponse.rsvp = "";
157 errorResponse.state = "error";
158 return errorResponse;
159 }
160 }
161
162 // check funds
163 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
164
165 if (mm != null)
166 {
167 if (!mm.UploadCovered(agentID, mm.UploadCharge))
168 {
169 if (client != null)
170 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
171
172 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
173 errorResponse.rsvp = "";
174 errorResponse.state = "error";
175 return errorResponse;
176 }
177 }
178
179 // }
180
181 string assetName = llsdRequest.name;
182 string assetDes = llsdRequest.description;
183 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
184 UUID newAsset = UUID.Random();
185 UUID newInvItem = UUID.Random();
186 UUID parentFolder = llsdRequest.folder_id;
187 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
188
189 AssetUploader uploader =
190 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
191 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
192
193 MainServer.Instance.AddStreamHandler(
194 new BinaryStreamHandler(
195 "POST",
196 capsBase + uploaderPath,
197 uploader.uploaderCaps,
198 "NewFileAgentInventoryVariablePrice",
199 agentID.ToString()));
200
201 string protocol = "http://";
202
203 if (MainServer.Instance.UseSSL)
204 protocol = "https://";
205
206 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
207 uploaderPath;
208
209
210 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
211
212 uploadResponse.rsvp = uploaderURL;
213 uploadResponse.state = "upload";
214 uploadResponse.resource_cost = 0;
215 uploadResponse.upload_price = 0;
216
217 uploader.OnUpLoad += //UploadCompleteHandler;
218
219 delegate(
220 string passetName, string passetDescription, UUID passetID,
221 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
222 string passetType)
223 {
224 UploadCompleteHandler(passetName, passetDescription, passetID,
225 pinventoryItem, pparentFolder, pdata, pinventoryType,
226 passetType,agentID);
227 };
228
229 return uploadResponse;
230 }
231
232 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
233 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
234 string assetType,UUID AgentID)
235 {
236// m_log.DebugFormat(
237// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
238
239 sbyte assType = 0;
240 sbyte inType = 0;
241
242 if (inventoryType == "sound")
243 {
244 inType = 1;
245 assType = 1;
246 }
247 else if (inventoryType == "animation")
248 {
249 inType = 19;
250 assType = 20;
251 }
252 else if (inventoryType == "wearable")
253 {
254 inType = 18;
255 switch (assetType)
256 {
257 case "bodypart":
258 assType = 13;
259 break;
260 case "clothing":
261 assType = 5;
262 break;
263 }
264 }
265 else if (inventoryType == "mesh")
266 {
267 inType = (sbyte)InventoryType.Mesh;
268 assType = (sbyte)AssetType.Mesh;
269 }
270
271 AssetBase asset;
272 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
273 asset.Data = data;
274
275 if (m_scene.AssetService != null)
276 m_scene.AssetService.Store(asset);
277
278 InventoryItemBase item = new InventoryItemBase();
279 item.Owner = AgentID;
280 item.CreatorId = AgentID.ToString();
281 item.ID = inventoryItem;
282 item.AssetID = asset.FullID;
283 item.Description = assetDescription;
284 item.Name = assetName;
285 item.AssetType = assType;
286 item.InvType = inType;
287 item.Folder = parentFolder;
288 item.CurrentPermissions
289 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
290 item.BasePermissions = (uint)PermissionMask.All;
291 item.EveryOnePermissions = 0;
292 item.NextPermissions = (uint)PermissionMask.All;
293 item.CreationDate = Util.UnixTimeSinceEpoch();
294 m_scene.AddInventoryItem(item);
295 }
296 }
297}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
index 94f8bc1..b044e56 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs
@@ -47,7 +47,7 @@ namespace OpenSim.Region.ClientStack.Linden
47 { 47 {
48// private static readonly ILog m_log = 48// private static readonly ILog m_log =
49// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 50
51 private Scene m_scene; 51 private Scene m_scene;
52 52
53 #region INonSharedRegionModule Members 53 #region INonSharedRegionModule Members
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden
76 } 76 }
77 77
78 public void Close() 78 public void Close()
79 { 79 {
80 } 80 }
81 81
82 public string Name 82 public string Name
@@ -121,6 +121,9 @@ namespace OpenSim.Region.ClientStack.Linden
121 121
122 122
123 OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]); 123 OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]);
124 if (r.Type != OSDType.Map) // not a proper req
125 return responsedata;
126
124 //UUID session_id = UUID.Zero; 127 //UUID session_id = UUID.Zero;
125 bool bypass_raycast = false; 128 bool bypass_raycast = false;
126 uint everyone_mask = 0; 129 uint everyone_mask = 0;
@@ -157,9 +160,6 @@ namespace OpenSim.Region.ClientStack.Linden
157 int state = 0; 160 int state = 0;
158 int lastattach = 0; 161 int lastattach = 0;
159 162
160 if (r.Type != OSDType.Map) // not a proper req
161 return responsedata;
162
163 OSDMap rm = (OSDMap)r; 163 OSDMap rm = (OSDMap)r;
164 164
165 if (rm.ContainsKey("ObjectData")) //v2 165 if (rm.ContainsKey("ObjectData")) //v2
@@ -307,8 +307,6 @@ namespace OpenSim.Region.ClientStack.Linden
307 } 307 }
308 } 308 }
309 309
310
311
312 Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false); 310 Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false);
313 311
314 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 312 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
@@ -359,6 +357,8 @@ namespace OpenSim.Region.ClientStack.Linden
359 rootpart.NextOwnerMask = next_owner_mask; 357 rootpart.NextOwnerMask = next_owner_mask;
360 rootpart.Material = (byte)material; 358 rootpart.Material = (byte)material;
361 359
360 obj.InvalidateDeepEffectivePerms();
361
362 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); 362 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
363 363
364 responsedata["int_response_code"] = 200; //501; //410; //404; 364 responsedata["int_response_code"] = 200; //501; //410; //404;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
index 769fe28..116c51f 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs
@@ -189,7 +189,7 @@ namespace OpenSim.Region.ClientStack.Linden
189 if (i == 0) 189 if (i == 0)
190 { 190 {
191 rootpos = obj.Position; 191 rootpos = obj.Position;
192// rootrot = obj.Rotation; 192// rootrot = obj.Rotation;
193 } 193 }
194 194
195 // Combine the extraparams data into it's ugly blob again.... 195 // Combine the extraparams data into it's ugly blob again....
@@ -284,6 +284,7 @@ namespace OpenSim.Region.ClientStack.Linden
284 prim.OwnerID = AgentId; 284 prim.OwnerID = AgentId;
285 prim.GroupID = obj.GroupID; 285 prim.GroupID = obj.GroupID;
286 prim.LastOwnerID = prim.OwnerID; 286 prim.LastOwnerID = prim.OwnerID;
287 prim.RezzerID = AgentId;
287 prim.CreationDate = Util.UnixTimeSinceEpoch(); 288 prim.CreationDate = Util.UnixTimeSinceEpoch();
288 prim.Name = obj.Name; 289 prim.Name = obj.Name;
289 prim.Description = ""; 290 prim.Description = "";
@@ -320,7 +321,7 @@ namespace OpenSim.Region.ClientStack.Linden
320 pbs.TextureEntry = tmp.GetBytes(); 321 pbs.TextureEntry = tmp.GetBytes();
321 prim.Shape = pbs; 322 prim.Shape = pbs;
322 prim.Scale = obj.Scale; 323 prim.Scale = obj.Scale;
323 324
324 SceneObjectGroup grp = new SceneObjectGroup(); 325 SceneObjectGroup grp = new SceneObjectGroup();
325 326
326 grp.SetRootPart(prim); 327 grp.SetRootPart(prim);
@@ -328,21 +329,22 @@ namespace OpenSim.Region.ClientStack.Linden
328 if (i == 0) 329 if (i == 0)
329 { 330 {
330 rootGroup = grp; 331 rootGroup = grp;
331 332
332 } 333 }
333 grp.AttachToScene(m_scene); 334 grp.AttachToScene(m_scene);
334 grp.AbsolutePosition = obj.Position; 335 grp.AbsolutePosition = obj.Position;
335 prim.RotationOffset = obj.Rotation; 336 prim.RotationOffset = obj.Rotation;
336 337
338
337 // Required for linking 339 // Required for linking
338 grp.RootPart.ClearUpdateSchedule(); 340 grp.RootPart.ClearUpdateSchedule();
339 341
340 if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) 342 if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos))
341 { 343 {
342 m_scene.AddSceneObject(grp); 344 m_scene.AddSceneObject(grp);
343 grp.AbsolutePosition = obj.Position; 345 grp.AbsolutePosition = obj.Position;
344 } 346 }
345 347
346 allparts[i] = grp; 348 allparts[i] = grp;
347 } 349 }
348 350
@@ -358,7 +360,7 @@ namespace OpenSim.Region.ClientStack.Linden
358 pos 360 pos
359 = m_scene.GetNewRezLocation( 361 = m_scene.GetNewRezLocation(
360 Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false); 362 Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false);
361 363
362 responsedata["int_response_code"] = 200; //501; //410; //404; 364 responsedata["int_response_code"] = 200; //501; //410; //404;
363 responsedata["content_type"] = "text/plain"; 365 responsedata["content_type"] = "text/plain";
364 responsedata["keepalive"] = false; 366 responsedata["keepalive"] = false;
@@ -366,7 +368,7 @@ namespace OpenSim.Region.ClientStack.Linden
366 368
367 return responsedata; 369 return responsedata;
368 } 370 }
369 371
370 private string ConvertUintToBytes(uint val) 372 private string ConvertUintToBytes(uint val)
371 { 373 {
372 byte[] resultbytes = Utils.UIntToBytes(val); 374 byte[] resultbytes = Utils.UIntToBytes(val);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
index 0adfa1a..f36826b 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs
@@ -2,7 +2,7 @@
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4 4
5// General Information about an assembly is controlled through the following 5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly. 7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenCaps")] 8[assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenCaps")]
@@ -14,8 +14,8 @@ using System.Runtime.InteropServices;
14[assembly: AssemblyTrademark("")] 14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")] 15[assembly: AssemblyCulture("")]
16 16
17// Setting ComVisible to false makes the types in this assembly not visible 17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from 18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type. 19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)] 20[assembly: ComVisible(false)]
21 21
@@ -25,9 +25,9 @@ using System.Runtime.InteropServices;
25// Version information for an assembly consists of the following four values: 25// Version information for an assembly consists of the following four values:
26// 26//
27// Major Version 27// Major Version
28// Minor Version 28// Minor Version
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.8.3.*")] 32[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
33 33
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index a133a69..e8387e3 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -58,12 +58,14 @@ namespace OpenSim.Region.ClientStack.Linden
58 { 58 {
59// private static readonly ILog m_log = 59// private static readonly ILog m_log =
60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 60// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
61 61
62 private Scene m_scene; 62 private Scene m_scene;
63 private IEventQueue m_eventQueue; 63 private IEventQueue m_eventQueue;
64 private Commands m_commands = new Commands(); 64 private Commands m_commands = new Commands();
65 public ICommands Commands { get { return m_commands; } } 65 public ICommands Commands { get { return m_commands; } }
66 66
67 public event ConsoleMessage OnConsoleMessage;
68
67 public void Initialise(IConfigSource source) 69 public void Initialise(IConfigSource source)
68 { 70 {
69 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); 71 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
@@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 104
103 public void RegisterCaps(UUID agentID, Caps caps) 105 public void RegisterCaps(UUID agentID, Caps caps)
104 { 106 {
105 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) 107 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
106 return; 108 return;
107 109
108 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
@@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden
118 OSD osd = OSD.FromString(message); 120 OSD osd = OSD.FromString(message);
119 121
120 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); 122 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
123
124 ConsoleMessage handlerConsoleMessage = OnConsoleMessage;
125
126 if (handlerConsoleMessage != null)
127 handlerConsoleMessage( agentID, message);
121 } 128 }
122 129
123 public bool RunCommand(string command, UUID invokerID) 130 public bool RunCommand(string command, UUID invokerID)
@@ -148,7 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden
148 155
149 SendConsoleOutput(agentID, reply); 156 SendConsoleOutput(agentID, reply);
150 } 157 }
151 158
152 public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) 159 public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn)
153 { 160 {
154 m_commands.AddCommand(module, shared, command, help, longhelp, fn); 161 m_commands.AddCommand(module, shared, command, help, longhelp, fn);
@@ -178,8 +185,9 @@ namespace OpenSim.Region.ClientStack.Linden
178 185
179 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 186 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
180 { 187 {
181 StreamReader reader = new StreamReader(request); 188 string message;
182 string message = reader.ReadToEnd(); 189 using(StreamReader reader = new StreamReader(request))
190 message = reader.ReadToEnd();
183 191
184 OSD osd = OSDParser.DeserializeLLSDXml(message); 192 OSD osd = OSDParser.DeserializeLLSDXml(message);
185 193
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
index e258bcb..39f5baf 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -50,12 +50,12 @@ namespace OpenSim.Region.ClientStack.Linden
50 /// This is required for uploading Mesh. 50 /// This is required for uploading Mesh.
51 /// Since is accepts an open-ended response, we also send more information 51 /// Since is accepts an open-ended response, we also send more information
52 /// for viewers that care to interpret it. 52 /// for viewers that care to interpret it.
53 /// 53 ///
54 /// NOTE: Part of this code was adapted from the Aurora project, specifically 54 /// NOTE: Part of this code was adapted from the Aurora project, specifically
55 /// the normal part of the response in the capability handler. 55 /// the normal part of the response in the capability handler.
56 /// </remarks> 56 /// </remarks>
57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimulatorFeaturesModule")] 57 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimulatorFeaturesModule")]
58 public class SimulatorFeaturesModule : ISharedRegionModule, ISimulatorFeaturesModule 58 public class SimulatorFeaturesModule : INonSharedRegionModule, ISimulatorFeaturesModule
59 { 59 {
60 private static readonly ILog m_log = 60 private static readonly ILog m_log =
61 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 61 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -82,7 +82,7 @@ namespace OpenSim.Region.ClientStack.Linden
82 IConfig config = source.Configs["SimulatorFeatures"]; 82 IConfig config = source.Configs["SimulatorFeatures"];
83 83
84 if (config != null) 84 if (config != null)
85 { 85 {
86 // 86 //
87 // All this is obsolete since getting these features from the grid service!! 87 // All this is obsolete since getting these features from the grid service!!
88 // Will be removed after the next release 88 // Will be removed after the next release
@@ -126,10 +126,6 @@ namespace OpenSim.Region.ClientStack.Linden
126 GetGridExtraFeatures(s); 126 GetGridExtraFeatures(s);
127 } 127 }
128 128
129 public void PostInitialise()
130 {
131 }
132
133 public void Close() { } 129 public void Close() { }
134 130
135 public string Name { get { return "SimulatorFeaturesModule"; } } 131 public string Name { get { return "SimulatorFeaturesModule"; } }
@@ -155,6 +151,7 @@ namespace OpenSim.Region.ClientStack.Linden
155 m_features["MeshRezEnabled"] = true; 151 m_features["MeshRezEnabled"] = true;
156 m_features["MeshUploadEnabled"] = true; 152 m_features["MeshUploadEnabled"] = true;
157 m_features["MeshXferEnabled"] = true; 153 m_features["MeshXferEnabled"] = true;
154
158 m_features["PhysicsMaterialsEnabled"] = true; 155 m_features["PhysicsMaterialsEnabled"] = true;
159 156
160 OSDMap typesMap = new OSDMap(); 157 OSDMap typesMap = new OSDMap();
@@ -173,6 +170,10 @@ namespace OpenSim.Region.ClientStack.Linden
173 else 170 else
174 extrasMap = new OSDMap(); 171 extrasMap = new OSDMap();
175 172
173 extrasMap["AvatarSkeleton"] = true;
174 extrasMap["AnimationSet"] = true;
175
176 // TODO: Take these out of here into their respective modules, like map-server-url
176 if (m_SearchURL != string.Empty) 177 if (m_SearchURL != string.Empty)
177 extrasMap["search-server-url"] = m_SearchURL; 178 extrasMap["search-server-url"] = m_SearchURL;
178 if (!string.IsNullOrEmpty(m_DestinationGuideURL)) 179 if (!string.IsNullOrEmpty(m_DestinationGuideURL))
@@ -250,7 +251,7 @@ namespace OpenSim.Region.ClientStack.Linden
250 251
251 //Send back data 252 //Send back data
252 Hashtable responsedata = new Hashtable(); 253 Hashtable responsedata = new Hashtable();
253 responsedata["int_response_code"] = 200; 254 responsedata["int_response_code"] = 200;
254 responsedata["content_type"] = "text/plain"; 255 responsedata["content_type"] = "text/plain";
255 responsedata["keepalive"] = false; 256 responsedata["keepalive"] = false;
256 257
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs
index dd4a691..6ffed4d 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs
@@ -52,6 +52,7 @@ using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52 52
53namespace OpenSim.Region.ClientStack.Linden.Caps.Tests 53namespace OpenSim.Region.ClientStack.Linden.Caps.Tests
54{ 54{
55 /*
55 [TestFixture] 56 [TestFixture]
56 public class WebFetchInvDescModuleTests : OpenSimTestCase 57 public class WebFetchInvDescModuleTests : OpenSimTestCase
57 { 58 {
@@ -150,10 +151,11 @@ namespace OpenSim.Region.ClientStack.Linden.Caps.Tests
150 OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody); 151 OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody);
151 OSDArray foldersOsd = (OSDArray)responseOsd["folders"]; 152 OSDArray foldersOsd = (OSDArray)responseOsd["folders"];
152 OSDMap folderOsd = (OSDMap)foldersOsd[0]; 153 OSDMap folderOsd = (OSDMap)foldersOsd[0];
153 154
154 // A sanity check that the response has the expected number of descendents for a default inventory 155 // A sanity check that the response has the expected number of descendents for a default inventory
155 // TODO: Need a more thorough check. 156 // TODO: Need a more thorough check.
156 Assert.That((int)folderOsd["descendents"], Is.EqualTo(16)); 157 Assert.That((int)folderOsd["descendents"], Is.EqualTo(16));
157 } 158 }
158 } 159 }
160 */
159} \ No newline at end of file 161} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 8cdebcd..b406b37 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -63,23 +63,23 @@ namespace OpenSim.Region.ClientStack.Linden
63 private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. 63 private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule.
64 64
65 private Scene m_scene; 65 private Scene m_scene;
66 private bool m_persistBakedTextures;
67 66
68 private IBakedTextureModule m_BakedTextureModule; 67 private string m_URL;
69 68
70 public void Initialise(IConfigSource source) 69 public void Initialise(IConfigSource source)
71 { 70 {
72 IConfig appearanceConfig = source.Configs["Appearance"]; 71 IConfig config = source.Configs["ClientStack.LindenCaps"];
73 if (appearanceConfig != null) 72 if (config == null)
74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 73 return;
75 74
75 m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty);
76 76
77// IConfig appearanceConfig = source.Configs["Appearance"];
77 } 78 }
78 79
79 public void AddRegion(Scene s) 80 public void AddRegion(Scene s)
80 { 81 {
81 m_scene = s; 82 m_scene = s;
82
83 } 83 }
84 84
85 public void RemoveRegion(Scene s) 85 public void RemoveRegion(Scene s)
@@ -87,188 +87,28 @@ namespace OpenSim.Region.ClientStack.Linden
87 s.EventManager.OnRegisterCaps -= RegisterCaps; 87 s.EventManager.OnRegisterCaps -= RegisterCaps;
88 s.EventManager.OnNewPresence -= RegisterNewPresence; 88 s.EventManager.OnNewPresence -= RegisterNewPresence;
89 s.EventManager.OnRemovePresence -= DeRegisterPresence; 89 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null;
91 m_scene = null; 90 m_scene = null;
92 } 91 }
93 92
94
95
96 public void RegionLoaded(Scene s) 93 public void RegionLoaded(Scene s)
97 { 94 {
98 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 95 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
99 m_scene.EventManager.OnNewPresence += RegisterNewPresence; 96 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
100 m_scene.EventManager.OnRemovePresence += DeRegisterPresence; 97 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
101
102 } 98 }
103 99
104 private void DeRegisterPresence(UUID agentId) 100 private void DeRegisterPresence(UUID agentId)
105 { 101 {
106 ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence))
108 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 }
111
112 } 102 }
113 103
114 private void RegisterNewPresence(ScenePresence presence) 104 private void RegisterNewPresence(ScenePresence presence)
115 { 105 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 }
119
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
121 {
122 int maxCacheitemsLoop = cacheItems.Length;
123 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
124 {
125 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
126 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
127 }
128
129 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
130 if (cacheItems.Length > 0)
131 {
132// m_log.Debug("[Cacheitems]: " + cacheItems.Length);
133// for (int iter = 0; iter < maxCacheitemsLoop; iter++)
134// {
135// m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
136// cacheItems[iter].TextureID);
137// }
138
139 ScenePresence p = null;
140 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
141 {
142
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
144 if (existingitems == null)
145 {
146 if (m_BakedTextureModule != null)
147 {
148 WearableCacheItem[] savedcache = null;
149 try
150 {
151 if (p.Appearance.WearableCacheItemsDirty)
152 {
153 savedcache = m_BakedTextureModule.Get(p.UUID);
154 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false;
156 }
157
158 }
159 /*
160 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
161 * it jumps to the General Packet Exception Handler if you don't catch Exception!
162 *
163 catch (System.Net.Sockets.SocketException)
164 {
165 cacheItems = null;
166 }
167 catch (WebException)
168 {
169 cacheItems = null;
170 }
171 catch (InvalidOperationException)
172 {
173 cacheItems = null;
174 } */
175 catch (Exception)
176 {
177 // The service logs a sufficient error message.
178 }
179
180
181 if (savedcache != null)
182 existingitems = savedcache;
183 }
184 }
185 // Existing items null means it's a fully new appearance
186 if (existingitems == null)
187 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++)
190 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
192 {
193 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
194 if (face == null)
195 {
196 textureEntry.CreateFace(cacheItems[i].TextureIndex);
197 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue;
200 }
201 cacheItems[i].TextureID =face.TextureID;
202 if (m_scene.AssetService != null)
203 cacheItems[i].TextureAsset =
204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
205 }
206 else
207 {
208 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
209 }
210
211
212 }
213 }
214 else
215
216
217 {
218 // for each uploaded baked texture
219 for (int i = 0; i < maxCacheitemsLoop; i++)
220 {
221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
222 {
223 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
224 if (face == null)
225 {
226 textureEntry.CreateFace(cacheItems[i].TextureIndex);
227 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
228 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
229 continue;
230 }
231 cacheItems[i].TextureID =
232 face.TextureID;
233 }
234 else
235 {
236 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
237 }
238 }
239
240 for (int i = 0; i < maxCacheitemsLoop; i++)
241 {
242 if (cacheItems[i].TextureAsset == null)
243 {
244 cacheItems[i].TextureAsset =
245 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
246 }
247 }
248 }
249
250
251
252 p.Appearance.WearableCacheItems = cacheItems;
253
254
255
256 if (m_BakedTextureModule != null)
257 {
258 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
259 p.Appearance.WearableCacheItemsDirty = true;
260
261 }
262 }
263 }
264 } 106 }
265 107
266 public void PostInitialise() 108 public void PostInitialise()
267 { 109 {
268 } 110 }
269 111
270
271
272 public void Close() { } 112 public void Close() { }
273 113
274 public string Name { get { return "UploadBakedTextureModule"; } } 114 public string Name { get { return "UploadBakedTextureModule"; } }
@@ -280,23 +120,26 @@ namespace OpenSim.Region.ClientStack.Linden
280 120
281 public void RegisterCaps(UUID agentID, Caps caps) 121 public void RegisterCaps(UUID agentID, Caps caps)
282 { 122 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( 123 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
284 caps, m_scene.AssetService, m_persistBakedTextures); 124 if (m_URL == "localhost")
125 {
126 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
127 caps, m_scene.AssetService);
285 128
286 129 caps.RegisterHandler(
287
288 caps.RegisterHandler(
289 "UploadBakedTexture",
290 new RestStreamHandler(
291 "POST",
292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
293 avatarhandler.UploadBakedTexture,
294 "UploadBakedTexture", 130 "UploadBakedTexture",
295 agentID.ToString())); 131 new RestStreamHandler(
296 132 "POST",
297 133 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
298 134 avatarhandler.UploadBakedTexture,
135 "UploadBakedTexture",
136 agentID.ToString()));
299 137
138 }
139 else
140 {
141 caps.RegisterHandler("UploadBakedTexture", m_URL);
142 }
300 } 143 }
301 } 144 }
302} 145}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 025ffea..8d4e561 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -34,9 +34,7 @@ using log4net;
34using Nini.Config; 34using Nini.Config;
35using Mono.Addins; 35using Mono.Addins;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework; 37using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
40using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
@@ -45,6 +43,9 @@ using OpenSim.Framework.Capabilities;
45using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps; 44using Caps = OpenSim.Framework.Capabilities.Caps;
47using OpenSim.Capabilities.Handlers; 45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47
48using OpenMetaverse.StructuredData;
48 49
49namespace OpenSim.Region.ClientStack.Linden 50namespace OpenSim.Region.ClientStack.Linden
50{ 51{
@@ -63,7 +64,7 @@ namespace OpenSim.Region.ClientStack.Linden
63 public List<UUID> folders; 64 public List<UUID> folders;
64 } 65 }
65 66
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 68
68 /// <summary> 69 /// <summary>
69 /// Control whether requests will be processed asynchronously. 70 /// Control whether requests will be processed asynchronously.
@@ -92,14 +93,16 @@ namespace OpenSim.Region.ClientStack.Linden
92 private bool m_Enabled; 93 private bool m_Enabled;
93 94
94 private string m_fetchInventoryDescendents2Url; 95 private string m_fetchInventoryDescendents2Url;
95 private string m_webFetchInventoryDescendentsUrl; 96// private string m_webFetchInventoryDescendentsUrl;
96 97
97 private static FetchInvDescHandler m_webFetchHandler; 98 private static FetchInvDescHandler m_webFetchHandler;
98 99
99 private static Thread[] m_workerThreads = null; 100 private static Thread[] m_workerThreads = null;
100 101
101 private static DoubleQueue<aPollRequest> m_queue = 102 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
102 new DoubleQueue<aPollRequest>(); 103 new OpenSim.Framework.BlockingQueue<aPollRequest>();
104
105 private static int m_NumberScenes = 0;
103 106
104 #region ISharedRegionModule Members 107 #region ISharedRegionModule Members
105 108
@@ -117,9 +120,10 @@ namespace OpenSim.Region.ClientStack.Linden
117 return; 120 return;
118 121
119 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); 122 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
120 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); 123// m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
121 124
122 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) 125// if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
126 if (m_fetchInventoryDescendents2Url != string.Empty)
123 { 127 {
124 m_Enabled = true; 128 m_Enabled = true;
125 } 129 }
@@ -143,17 +147,7 @@ namespace OpenSim.Region.ClientStack.Linden
143 StatsManager.DeregisterStat(s_processedRequestsStat); 147 StatsManager.DeregisterStat(s_processedRequestsStat);
144 StatsManager.DeregisterStat(s_queuedRequestsStat); 148 StatsManager.DeregisterStat(s_queuedRequestsStat);
145 149
146 if (ProcessQueuedRequestsAsync) 150 m_NumberScenes--;
147 {
148 if (m_workerThreads != null)
149 {
150 foreach (Thread t in m_workerThreads)
151 Watchdog.AbortThread(t.ManagedThreadId);
152
153 m_workerThreads = null;
154 }
155 }
156
157 Scene = null; 151 Scene = null;
158 } 152 }
159 153
@@ -187,7 +181,7 @@ namespace OpenSim.Region.ClientStack.Linden
187 "httpfetch", 181 "httpfetch",
188 StatType.Pull, 182 StatType.Pull,
189 MeasuresOfInterest.AverageChangeOverTime, 183 MeasuresOfInterest.AverageChangeOverTime,
190 stat => { stat.Value = m_queue.Count; }, 184 stat => { stat.Value = m_queue.Count(); },
191 StatVerbosity.Debug); 185 StatVerbosity.Debug);
192 186
193 StatsManager.RegisterStat(s_processedRequestsStat); 187 StatsManager.RegisterStat(s_processedRequestsStat);
@@ -201,6 +195,8 @@ namespace OpenSim.Region.ClientStack.Linden
201 195
202 Scene.EventManager.OnRegisterCaps += RegisterCaps; 196 Scene.EventManager.OnRegisterCaps += RegisterCaps;
203 197
198 m_NumberScenes++;
199
204 int nworkers = 2; // was 2 200 int nworkers = 2; // was 2
205 if (ProcessQueuedRequestsAsync && m_workerThreads == null) 201 if (ProcessQueuedRequestsAsync && m_workerThreads == null)
206 { 202 {
@@ -211,7 +207,7 @@ namespace OpenSim.Region.ClientStack.Linden
211 m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, 207 m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests,
212 String.Format("InventoryWorkerThread{0}", i), 208 String.Format("InventoryWorkerThread{0}", i),
213 ThreadPriority.Normal, 209 ThreadPriority.Normal,
214 false, 210 true,
215 true, 211 true,
216 null, 212 null,
217 int.MaxValue); 213 int.MaxValue);
@@ -223,7 +219,23 @@ namespace OpenSim.Region.ClientStack.Linden
223 { 219 {
224 } 220 }
225 221
226 public void Close() { } 222 public void Close()
223 {
224 if (!m_Enabled)
225 return;
226
227 if (ProcessQueuedRequestsAsync)
228 {
229 if (m_NumberScenes <= 0 && m_workerThreads != null)
230 {
231 m_log.DebugFormat("[WebFetchInvDescModule] Closing");
232 foreach (Thread t in m_workerThreads)
233 Watchdog.AbortThread(t.ManagedThreadId);
234
235 m_workerThreads = null;
236 }
237 }
238 }
227 239
228 public string Name { get { return "WebFetchInvDescModule"; } } 240 public string Name { get { return "WebFetchInvDescModule"; } }
229 241
@@ -312,16 +324,17 @@ namespace OpenSim.Region.ClientStack.Linden
312 { 324 {
313 if (!reqinfo.folders.Contains(folderID)) 325 if (!reqinfo.folders.Contains(folderID))
314 { 326 {
315 //TODO: Port COF handling from Avination 327 if (sp.COF != UUID.Zero && sp.COF == folderID)
328 highPriority = true;
316 reqinfo.folders.Add(folderID); 329 reqinfo.folders.Add(folderID);
317 } 330 }
318 } 331 }
319 } 332 }
320 333
321 if (highPriority) 334 if (highPriority)
322 m_queue.EnqueueHigh(reqinfo); 335 m_queue.PriorityEnqueue(reqinfo);
323 else 336 else
324 m_queue.EnqueueLow(reqinfo); 337 m_queue.Enqueue(reqinfo);
325 }; 338 };
326 339
327 NoEvents = (x, y) => 340 NoEvents = (x, y) =>
@@ -347,6 +360,9 @@ namespace OpenSim.Region.ClientStack.Linden
347 360
348 public void Process(aPollRequest requestinfo) 361 public void Process(aPollRequest requestinfo)
349 { 362 {
363 if(m_module == null || m_module.Scene == null || m_module.Scene.ShuttingDown)
364 return;
365
350 UUID requestID = requestinfo.reqID; 366 UUID requestID = requestinfo.reqID;
351 367
352 Hashtable response = new Hashtable(); 368 Hashtable response = new Hashtable();
@@ -365,7 +381,8 @@ namespace OpenSim.Region.ClientStack.Linden
365 m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); 381 m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054");
366 responses[requestID] = response; 382 responses[requestID] = response;
367 } 383 }
368 384 requestinfo.folders.Clear();
385 requestinfo.request.Clear();
369 WebFetchInvDescModule.ProcessedRequestsCount++; 386 WebFetchInvDescModule.ProcessedRequestsCount++;
370 } 387 }
371 } 388 }
@@ -422,31 +439,25 @@ namespace OpenSim.Region.ClientStack.Linden
422// } 439// }
423// } 440// }
424 441
425 private void DoInventoryRequests() 442 private static void DoInventoryRequests()
426 { 443 {
427 while (true) 444 while (true)
428 { 445 {
446 aPollRequest poolreq = m_queue.Dequeue(4500);
429 Watchdog.UpdateThread(); 447 Watchdog.UpdateThread();
430 448
431 WaitProcessQueuedInventoryRequest(); 449 if (poolreq != null && poolreq.thepoll != null)
432 }
433 }
434
435 public void WaitProcessQueuedInventoryRequest()
436 {
437 aPollRequest poolreq = m_queue.Dequeue();
438
439 if (poolreq != null && poolreq.thepoll != null)
440 {
441 try
442 {
443 poolreq.thepoll.Process(poolreq);
444 }
445 catch (Exception e)
446 { 450 {
447 m_log.ErrorFormat( 451 try
448 "[INVENTORY]: Failed to process queued inventory request {0} for {1} in {2}. Exception {3}", 452 {
449 poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", Scene.Name, e); 453 poolreq.thepoll.Process(poolreq);
454 }
455 catch (Exception e)
456 {
457 m_log.ErrorFormat(
458 "[INVENTORY]: Failed to process queued inventory request {0} for {1}. Exception {2}",
459 poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", e);
460 }
450 } 461 }
451 } 462 }
452 } 463 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 4d0568d..0a6785c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -98,7 +98,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
98 } 98 }
99 99
100 /// <summary> 100 /// <summary>
101 /// Sends packets for this texture to a client until packetsToSend is 101 /// Sends packets for this texture to a client until packetsToSend is
102 /// hit or the transfer completes 102 /// hit or the transfer completes
103 /// </summary> 103 /// </summary>
104 /// <param name="client">Reference to the client that the packets are destined for</param> 104 /// <param name="client">Reference to the client that the packets are destined for</param>
@@ -198,7 +198,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
198 m_currentPacket = m_stopPacket; 198 m_currentPacket = m_stopPacket;
199 return; 199 return;
200 } 200 }
201 201
202 if (DiscardLevel >= 0 || m_stopPacket == 0) 202 if (DiscardLevel >= 0 || m_stopPacket == 0)
203 { 203 {
204 // This shouldn't happen, but if it does, we really can't proceed 204 // This shouldn't happen, but if it does, we really can't proceed
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 m_stopPacket = TexturePacketCount(); 234 m_stopPacket = TexturePacketCount();
235 } 235 }
236 236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
237 m_currentPacket = StartPacket; 240 m_currentPacket = StartPacket;
238 } 241 }
239 } 242 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index b17b822..2ff6ced 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -62,7 +62,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 /// Handles new client connections 62 /// Handles new client connections
63 /// Constructor takes a single Packet and authenticates everything 63 /// Constructor takes a single Packet and authenticates everything
64 /// </summary> 64 /// </summary>
65 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IStatsCollector 65 public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IStatsCollector, IClientIPEndpoint
66 { 66 {
67 /// <value> 67 /// <value>
68 /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details. 68 /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details.
@@ -80,6 +80,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 public event ChatMessage OnChatFromClient; 80 public event ChatMessage OnChatFromClient;
81 public event RezObject OnRezObject; 81 public event RezObject OnRezObject;
82 public event DeRezObject OnDeRezObject; 82 public event DeRezObject OnDeRezObject;
83 public event RezRestoreToWorld OnRezRestoreToWorld;
83 public event ModifyTerrain OnModifyTerrain; 84 public event ModifyTerrain OnModifyTerrain;
84 public event Action<IClientAPI> OnRegionHandShakeReply; 85 public event Action<IClientAPI> OnRegionHandShakeReply;
85 public event GenericCall1 OnRequestWearables; 86 public event GenericCall1 OnRequestWearables;
@@ -100,6 +101,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
100 public event AvatarPickerRequest OnAvatarPickerRequest; 101 public event AvatarPickerRequest OnAvatarPickerRequest;
101 public event StartAnim OnStartAnim; 102 public event StartAnim OnStartAnim;
102 public event StopAnim OnStopAnim; 103 public event StopAnim OnStopAnim;
104 public event ChangeAnim OnChangeAnim;
103 public event Action<IClientAPI> OnRequestAvatarsData; 105 public event Action<IClientAPI> OnRequestAvatarsData;
104 public event LinkObjects OnLinkObjects; 106 public event LinkObjects OnLinkObjects;
105 public event DelinkObjects OnDelinkObjects; 107 public event DelinkObjects OnDelinkObjects;
@@ -127,6 +129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
127 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; 129 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
128 public event UpdatePrimFlags OnUpdatePrimFlags; 130 public event UpdatePrimFlags OnUpdatePrimFlags;
129 public event UpdatePrimTexture OnUpdatePrimTexture; 131 public event UpdatePrimTexture OnUpdatePrimTexture;
132 public event ClientChangeObject onClientChangeObject;
130 public event UpdateVector OnUpdatePrimGroupPosition; 133 public event UpdateVector OnUpdatePrimGroupPosition;
131 public event UpdateVector OnUpdatePrimSinglePosition; 134 public event UpdateVector OnUpdatePrimSinglePosition;
132 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 135 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
@@ -156,6 +159,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
156 public event RequestTaskInventory OnRequestTaskInventory; 159 public event RequestTaskInventory OnRequestTaskInventory;
157 public event UpdateInventoryItem OnUpdateInventoryItem; 160 public event UpdateInventoryItem OnUpdateInventoryItem;
158 public event CopyInventoryItem OnCopyInventoryItem; 161 public event CopyInventoryItem OnCopyInventoryItem;
162 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
159 public event MoveInventoryItem OnMoveInventoryItem; 163 public event MoveInventoryItem OnMoveInventoryItem;
160 public event RemoveInventoryItem OnRemoveInventoryItem; 164 public event RemoveInventoryItem OnRemoveInventoryItem;
161 public event RemoveInventoryFolder OnRemoveInventoryFolder; 165 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -250,7 +254,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
250 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 254 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
251 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 255 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
252 public event ClassifiedDelete OnClassifiedDelete; 256 public event ClassifiedDelete OnClassifiedDelete;
253 public event ClassifiedDelete OnClassifiedGodDelete; 257 public event ClassifiedGodDelete OnClassifiedGodDelete;
254 public event EventNotificationAddRequest OnEventNotificationAddRequest; 258 public event EventNotificationAddRequest OnEventNotificationAddRequest;
255 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 259 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
256 public event EventGodDelete OnEventGodDelete; 260 public event EventGodDelete OnEventGodDelete;
@@ -281,10 +285,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
281 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 285 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
282 public event SimWideDeletesDelegate OnSimWideDeletes; 286 public event SimWideDeletesDelegate OnSimWideDeletes;
283 public event SendPostcard OnSendPostcard; 287 public event SendPostcard OnSendPostcard;
288 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
284 public event MuteListEntryUpdate OnUpdateMuteListEntry; 289 public event MuteListEntryUpdate OnUpdateMuteListEntry;
285 public event MuteListEntryRemove OnRemoveMuteListEntry; 290 public event MuteListEntryRemove OnRemoveMuteListEntry;
286 public event GodlikeMessage onGodlikeMessage; 291 public event GodlikeMessage onGodlikeMessage;
287 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 292 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
293 public event GenericCall2 OnUpdateThrottles;
288 294
289#pragma warning disable 0067 295#pragma warning disable 0067
290 public event GenericMessage OnGenericMessage; 296 public event GenericMessage OnGenericMessage;
@@ -319,6 +325,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
319 /// </summary> 325 /// </summary>
320 public LLImageManager ImageManager { get; private set; } 326 public LLImageManager ImageManager { get; private set; }
321 327
328 public JobEngine m_asyncPacketProcess;
322 private readonly LLUDPServer m_udpServer; 329 private readonly LLUDPServer m_udpServer;
323 private readonly LLUDPClient m_udpClient; 330 private readonly LLUDPClient m_udpClient;
324 private readonly UUID m_sessionId; 331 private readonly UUID m_sessionId;
@@ -333,26 +340,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 private PriorityQueue m_entityProps; 340 private PriorityQueue m_entityProps;
334 private Prioritizer m_prioritizer; 341 private Prioritizer m_prioritizer;
335 private bool m_disableFacelights = false; 342 private bool m_disableFacelights = false;
336 private volatile bool m_justEditedTerrain = false; 343
337 /// <value> 344 // needs optimazation
338 /// List used in construction of data blocks for an object update packet. This is to stop us having to 345 private HashSet<SceneObjectGroup> GroupsInView = new HashSet<SceneObjectGroup>();
339 /// continually recreate it. 346
340 /// </value> 347 private bool m_VelocityInterpolate = false;
341 protected List<ObjectUpdatePacket.ObjectDataBlock> m_fullUpdateDataBlocksBuilder; 348 private const uint MaxTransferBytesPerPacket = 600;
342 349
343 /// <value> 350 /// <value>
344 /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the 351 /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the
345 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 352 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
346 /// ownerless phantom. 353 /// ownerless phantom.
347 /// 354 ///
348 /// All manipulation of this set has to occur under a lock 355 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
349 /// 356 ///
350 /// </value> 357 /// </value>
351 protected HashSet<uint> m_killRecord; 358 protected List<uint> m_killRecord;
352 359
353// protected HashSet<uint> m_attachmentsSent; 360// protected HashSet<uint> m_attachmentsSent;
354 361
355 private int m_animationSequenceNumber = 1; 362 private bool m_deliverPackets = true;
363
356 private bool m_SendLogoutPacketWhenClosing = true; 364 private bool m_SendLogoutPacketWhenClosing = true;
357 365
358 /// <summary> 366 /// <summary>
@@ -371,7 +379,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
371 protected Scene m_scene; 379 protected Scene m_scene;
372 protected string m_firstName; 380 protected string m_firstName;
373 protected string m_lastName; 381 protected string m_lastName;
374 protected Thread m_clientThread;
375 protected Vector3 m_startpos; 382 protected Vector3 m_startpos;
376 protected UUID m_activeGroupID; 383 protected UUID m_activeGroupID;
377 protected string m_activeGroupName = String.Empty; 384 protected string m_activeGroupName = String.Empty;
@@ -398,18 +405,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
398 get { return m_startpos; } 405 get { return m_startpos; }
399 set { m_startpos = value; } 406 set { m_startpos = value; }
400 } 407 }
408 public bool DeliverPackets
409 {
410 get { return m_deliverPackets; }
411 set {
412 m_deliverPackets = value;
413 m_udpClient.m_deliverPackets = value;
414 }
415 }
401 public UUID AgentId { get { return m_agentId; } } 416 public UUID AgentId { get { return m_agentId; } }
402 public ISceneAgent SceneAgent { get; set; } 417 public ISceneAgent SceneAgent { get; set; }
403 public UUID ActiveGroupId { get { return m_activeGroupID; } private set { m_activeGroupID = value; } } 418 public UUID ActiveGroupId { get { return m_activeGroupID; } set { m_activeGroupID = value; } }
404 public string ActiveGroupName { get { return m_activeGroupName; } private set { m_activeGroupName = value; } } 419 public string ActiveGroupName { get { return m_activeGroupName; } set { m_activeGroupName = value; } }
405 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } private set { m_activeGroupPowers = value; } } 420 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } set { m_activeGroupPowers = value; } }
406 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 421 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
407 422
423 public int PingTimeMS
424 {
425 get
426 {
427 if (UDPClient != null)
428 return UDPClient.PingTimeMS;
429 return 0;
430 }
431 }
432
408 /// <summary> 433 /// <summary>
409 /// Entity update queues 434 /// Entity update queues
410 /// </summary> 435 /// </summary>
411 public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } } 436 public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } }
412 437
413 /// <summary> 438 /// <summary>
414 /// First name of the agent/avatar represented by the client 439 /// First name of the agent/avatar represented by the client
415 /// </summary> 440 /// </summary>
@@ -426,7 +451,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
426 public string Name { get { return FirstName + " " + LastName; } } 451 public string Name { get { return FirstName + " " + LastName; } }
427 452
428 public uint CircuitCode { get { return m_circuitCode; } } 453 public uint CircuitCode { get { return m_circuitCode; } }
429 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 454 public int NextAnimationSequenceNumber
455 {
456 get { return m_udpServer.NextAnimationSequenceNumber; }
457 }
430 458
431 /// <summary> 459 /// <summary>
432 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to 460 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
@@ -447,8 +475,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 set { m_disableFacelights = value; } 475 set { m_disableFacelights = value; }
448 } 476 }
449 477
478 public List<uint> SelectedObjects {get; private set;}
479
450 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 480 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
451 481
482
452 #endregion Properties 483 #endregion Properties
453 484
454// ~LLClientView() 485// ~LLClientView()
@@ -465,6 +496,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
465// DebugPacketLevel = 1; 496// DebugPacketLevel = 1;
466 497
467 CloseSyncLock = new Object(); 498 CloseSyncLock = new Object();
499 SelectedObjects = new List<uint>();
468 500
469 RegisterInterface<IClientIM>(this); 501 RegisterInterface<IClientIM>(this);
470 RegisterInterface<IClientInventory>(this); 502 RegisterInterface<IClientInventory>(this);
@@ -473,8 +505,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
473 m_scene = scene; 505 m_scene = scene;
474 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 506 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
475 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 507 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
476 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 508 m_killRecord = new List<uint>();
477 m_killRecord = new HashSet<uint>();
478// m_attachmentsSent = new HashSet<uint>(); 509// m_attachmentsSent = new HashSet<uint>();
479 510
480 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 511 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -498,18 +529,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
498 m_prioritizer = new Prioritizer(m_scene); 529 m_prioritizer = new Prioritizer(m_scene);
499 530
500 RegisterLocalPacketHandlers(); 531 RegisterLocalPacketHandlers();
501 532 string name = string.Format("AsyncInUDP-{0}",m_agentId.ToString());
533 m_asyncPacketProcess = new JobEngine(name, name, 10000);
502 IsActive = true; 534 IsActive = true;
503 } 535 }
504 536
505 #region Client Methods 537 #region Client Methods
506 538
539
540 /// <summary>
541 /// Close down the client view
542 /// </summary>
507 public void Close() 543 public void Close()
508 { 544 {
509 Close(false); 545 Close(true, false);
510 } 546 }
511 547
512 public void Close(bool force) 548 public void Close(bool sendStop, bool force)
513 { 549 {
514 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 550 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
515 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 551 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -519,14 +555,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
519 // there is some unidentified connection problem, not where we have issues due to deadlock 555 // there is some unidentified connection problem, not where we have issues due to deadlock
520 if (!IsActive && !force) 556 if (!IsActive && !force)
521 { 557 {
522 m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set", 558 m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set",
523 LogHeader, Name, m_scene.Name); 559 LogHeader, Name, m_scene.Name);
524 560
525 return; 561 return;
526 } 562 }
527 563
528 IsActive = false; 564 IsActive = false;
529 CloseWithoutChecks(); 565 CloseWithoutChecks(sendStop);
530 } 566 }
531 } 567 }
532 568
@@ -539,19 +575,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
539 /// 575 ///
540 /// Callers must lock ClosingSyncLock before calling. 576 /// Callers must lock ClosingSyncLock before calling.
541 /// </remarks> 577 /// </remarks>
542 public void CloseWithoutChecks() 578 public void CloseWithoutChecks(bool sendStop)
543 { 579 {
544 m_log.DebugFormat( 580 m_log.DebugFormat(
545 "[CLIENT]: Close has been called for {0} attached to scene {1}", 581 "[CLIENT]: Close has been called for {0} attached to scene {1}",
546 Name, m_scene.RegionInfo.RegionName); 582 Name, m_scene.RegionInfo.RegionName);
547 583
548 // Shutdown the image manager 584 if (sendStop)
549 ImageManager.Close(); 585 {
586 // Send the STOP packet
587 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
588 OutPacket(disable, ThrottleOutPacketType.Unknown);
589 }
590
550 591
551 // Fire the callback for this connection closing 592 // Fire the callback for this connection closing
552 if (OnConnectionClosed != null) 593 if (OnConnectionClosed != null)
553 OnConnectionClosed(this); 594 OnConnectionClosed(this);
554 595
596 m_asyncPacketProcess.Stop();
597
555 // Flush all of the packets out of the UDP server for this client 598 // Flush all of the packets out of the UDP server for this client
556 if (m_udpServer != null) 599 if (m_udpServer != null)
557 m_udpServer.Flush(m_udpClient); 600 m_udpServer.Flush(m_udpClient);
@@ -565,11 +608,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
565 //m_scene.CloseAllAgents(CircuitCode); 608 //m_scene.CloseAllAgents(CircuitCode);
566 609
567 // Disable UDP handling for this client 610 // Disable UDP handling for this client
611 m_udpClient.OnQueueEmpty -= HandleQueueEmpty;
612 m_udpClient.HasUpdates -= HandleHasUpdates;
613 m_udpClient.OnPacketStats -= PopulateStats;
568 m_udpClient.Shutdown(); 614 m_udpClient.Shutdown();
569 615
570 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 616 // Shutdown the image manager
571 //GC.Collect(); 617 ImageManager.Close();
572 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 618 ImageManager = null;
619
620 m_entityUpdates = new PriorityQueue(1);
621 m_entityProps = new PriorityQueue(1);
622 m_killRecord.Clear();
623 GroupsInView.Clear();
624
625 if(m_scene.GetNumberOfClients() == 0)
626 {
627 GC.Collect();
628 GC.WaitForPendingFinalizers();
629 GC.Collect();
630 }
573 } 631 }
574 632
575 public void Kick(string message) 633 public void Kick(string message)
@@ -648,36 +706,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
648 /// <returns>true if the handler was added. This is currently always the case.</returns> 706 /// <returns>true if the handler was added. This is currently always the case.</returns>
649 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) 707 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
650 { 708 {
651 return AddLocalPacketHandler(packetType, handler, doAsync, false);
652 }
653
654 /// <summary>
655 /// Add a handler for the given packet type.
656 /// </summary>
657 /// <param name="packetType"></param>
658 /// <param name="handler"></param>
659 /// <param name="doAsync">
660 /// If true, when the packet is received handle it on a different thread. Whether this is given direct to
661 /// a threadpool thread or placed in a queue depends on the inEngine parameter.
662 /// </param>
663 /// <param name="inEngine">
664 /// If async is false then this parameter is ignored.
665 /// If async is true and inEngine is false, then the packet is sent directly to a
666 /// threadpool thread.
667 /// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine.
668 /// This may result in slower handling but reduces the risk of overloading the simulator when there are many
669 /// simultaneous async requests.
670 /// </param>
671 /// <returns>true if the handler was added. This is currently always the case.</returns>
672 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine)
673 {
674 bool result = false; 709 bool result = false;
675 lock (m_packetHandlers) 710 lock (m_packetHandlers)
676 { 711 {
677 if (!m_packetHandlers.ContainsKey(packetType)) 712 if (!m_packetHandlers.ContainsKey(packetType))
678 { 713 {
679 m_packetHandlers.Add( 714 m_packetHandlers.Add(
680 packetType, new PacketProcessor() { method = handler, Async = doAsync, InEngine = inEngine }); 715 packetType, new PacketProcessor() { method = handler, Async = doAsync});
681 result = true; 716 result = true;
682 } 717 }
683 } 718 }
@@ -712,30 +747,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
712 PacketProcessor pprocessor; 747 PacketProcessor pprocessor;
713 if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor)) 748 if (m_packetHandlers.TryGetValue(packet.Type, out pprocessor))
714 { 749 {
715 ClientInfo cinfo = UDPClient.GetClientInfo();
716 750
717 //there is a local handler for this packet type 751 //there is a local handler for this packet type
718 if (pprocessor.Async) 752 if (pprocessor.Async)
719 { 753 {
720 if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString()))
721 cinfo.AsyncRequests[packet.Type.ToString()] = 0;
722 cinfo.AsyncRequests[packet.Type.ToString()]++;
723
724 object obj = new AsyncPacketProcess(this, pprocessor.method, packet); 754 object obj = new AsyncPacketProcess(this, pprocessor.method, packet);
725 755 m_asyncPacketProcess.QueueJob(packet.Type.ToString(), () => ProcessSpecificPacketAsync(obj));
726 if (pprocessor.InEngine)
727 m_udpServer.IpahEngine.QueueJob(packet.Type.ToString(), () => ProcessSpecificPacketAsync(obj));
728 else
729 Util.FireAndForget(ProcessSpecificPacketAsync, obj, packet.Type.ToString());
730
731 result = true; 756 result = true;
732 } 757 }
733 else 758 else
734 { 759 {
735 if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString()))
736 cinfo.SyncRequests[packet.Type.ToString()] = 0;
737 cinfo.SyncRequests[packet.Type.ToString()]++;
738
739 result = pprocessor.method(this, packet); 760 result = pprocessor.method(this, packet);
740 } 761 }
741 } 762 }
@@ -750,11 +771,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
750 } 771 }
751 if (found) 772 if (found)
752 { 773 {
753 ClientInfo cinfo = UDPClient.GetClientInfo();
754 if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString()))
755 cinfo.GenericRequests[packet.Type.ToString()] = 0;
756 cinfo.GenericRequests[packet.Type.ToString()]++;
757
758 result = method(this, packet); 774 result = method(this, packet);
759 } 775 }
760 } 776 }
@@ -774,7 +790,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
774 // Make sure that we see any exception caused by the asynchronous operation. 790 // Make sure that we see any exception caused by the asynchronous operation.
775 m_log.Error( 791 m_log.Error(
776 string.Format( 792 string.Format(
777 "[LLCLIENTVIEW]: Caught exception while processing {0} for {1} ", packetObject.Pack, Name), 793 "[LLCLIENTVIEW]: Caught exception while processing {0} for {1} ", packetObject.Pack, Name),
778 e); 794 e);
779 } 795 }
780 } 796 }
@@ -785,9 +801,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
785 801
786 public virtual void Start() 802 public virtual void Start()
787 { 803 {
804 m_asyncPacketProcess.Start();
788 m_scene.AddNewAgent(this, PresenceType.User); 805 m_scene.AddNewAgent(this, PresenceType.User);
789 806
790 RefreshGroupMembership(); 807// RefreshGroupMembership();
791 } 808 }
792 809
793 # endregion 810 # endregion
@@ -858,6 +875,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
858 875
859 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 876 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
860 { 877 {
878 m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue;
879// m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue;
880 m_thisAgentUpdateArgs.ControlFlags = 0;
881
861 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 882 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
862 mov.SimData.ChannelVersion = m_channelVersion; 883 mov.SimData.ChannelVersion = m_channelVersion;
863 mov.AgentData.SessionID = m_sessionId; 884 mov.AgentData.SessionID = m_sessionId;
@@ -893,14 +914,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
893 reply.ChatData.OwnerID = ownerID; 914 reply.ChatData.OwnerID = ownerID;
894 reply.ChatData.SourceID = fromAgentID; 915 reply.ChatData.SourceID = fromAgentID;
895 916
896 OutPacket(reply, ThrottleOutPacketType.Task); 917 OutPacket(reply, ThrottleOutPacketType.Unknown);
897 } 918 }
898 919
899 /// <summary> 920 /// <summary>
900 /// Send an instant message to this client 921 /// Send an instant message to this client
901 /// </summary> 922 /// </summary>
902 // 923 //
903 // Don't remove transaction ID! Groups and item gives need to set it!
904 public void SendInstantMessage(GridInstantMessage im) 924 public void SendInstantMessage(GridInstantMessage im)
905 { 925 {
906 if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID))) 926 if (((Scene)(m_scene)).Permissions.CanInstantMessage(new UUID(im.fromAgentID), new UUID(im.toAgentID)))
@@ -913,6 +933,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
913 msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName); 933 msg.MessageBlock.FromAgentName = Util.StringToBytes256(im.fromAgentName);
914 msg.MessageBlock.Dialog = im.dialog; 934 msg.MessageBlock.Dialog = im.dialog;
915 msg.MessageBlock.FromGroup = im.fromGroup; 935 msg.MessageBlock.FromGroup = im.fromGroup;
936 // this is odd
916 if (im.imSessionID == UUID.Zero.Guid) 937 if (im.imSessionID == UUID.Zero.Guid)
917 msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID); 938 msg.MessageBlock.ID = new UUID(im.fromAgentID) ^ new UUID(im.toAgentID);
918 else 939 else
@@ -926,32 +947,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
926 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 947 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
927 msg.MessageBlock.BinaryBucket = im.binaryBucket; 948 msg.MessageBlock.BinaryBucket = im.binaryBucket;
928 949
929 if (im.message.StartsWith("[grouptest]")) 950 OutPacket(msg, ThrottleOutPacketType.Task);
930 { // this block is test code for implementing group IM - delete when group IM is finished
931 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
932 if (eq != null)
933 {
934 im.dialog = 17;
935
936 //eq.ChatterboxInvitation(
937 // new UUID("00000000-68f9-1111-024e-222222111123"),
938 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
939 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
940
941 eq.ChatterboxInvitation(
942 new UUID("00000000-68f9-1111-024e-222222111123"),
943 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
944 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
945
946 eq.ChatterBoxSessionAgentListUpdates(
947 new UUID("00000000-68f9-1111-024e-222222111123"),
948 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
949 }
950
951 Console.WriteLine("SendInstantMessage: " + msg);
952 }
953 else
954 OutPacket(msg, ThrottleOutPacketType.Task);
955 } 951 }
956 } 952 }
957 953
@@ -1182,6 +1178,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1182 OutPacket(GATRP, ThrottleOutPacketType.Task); 1178 OutPacket(GATRP, ThrottleOutPacketType.Task);
1183 } 1179 }
1184 1180
1181
1182 public virtual bool CanSendLayerData()
1183 {
1184 int n = m_udpClient.GetPacketsQueuedCount(ThrottleOutPacketType.Land);
1185 if ( n > 128)
1186 return false;
1187 return true;
1188 }
1189
1185 /// <summary> 1190 /// <summary>
1186 /// Send the region heightmap to the client 1191 /// Send the region heightmap to the client
1187 /// This method is only called when not doing intellegent terrain patch sending and 1192 /// This method is only called when not doing intellegent terrain patch sending and
@@ -1192,6 +1197,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1192 public virtual void SendLayerData(float[] map) 1197 public virtual void SendLayerData(float[] map)
1193 { 1198 {
1194 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData"); 1199 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData");
1200
1201 // Send it sync, and async. It's not that much data
1202 // and it improves user experience just so much!
1203// DoSendLayerData(map);
1195 } 1204 }
1196 1205
1197 /// <summary> 1206 /// <summary>
@@ -1214,7 +1223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1214 //} 1223 //}
1215 1224
1216 // Send LayerData in a spiral pattern. Fun! 1225 // Send LayerData in a spiral pattern. Fun!
1217 SendLayerTopRight(map, 0, 0, map.SizeX/Constants.TerrainPatchSize-1, map.SizeY/Constants.TerrainPatchSize-1); 1226 SendLayerTopRight(map, 0, 0, map.SizeX / Constants.TerrainPatchSize - 1, map.SizeY / Constants.TerrainPatchSize - 1);
1218 } 1227 }
1219 catch (Exception e) 1228 catch (Exception e)
1220 { 1229 {
@@ -1250,27 +1259,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1250 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1); 1259 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1251 } 1260 }
1252 1261
1253 /// <summary>
1254 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1255 /// </summary>
1256 /// <param name="map">heightmap</param>
1257 /// <param name="px">X coordinate for patches 0..12</param>
1258 /// <param name="py">Y coordinate for patches 0..15</param>
1259 // private void SendLayerPacket(float[] map, int y, int x)
1260 // {
1261 // int[] patches = new int[4];
1262 // patches[0] = x + 0 + y * 16;
1263 // patches[1] = x + 1 + y * 16;
1264 // patches[2] = x + 2 + y * 16;
1265 // patches[3] = x + 3 + y * 16;
1266
1267 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches);
1268 // OutPacket(layerpack, ThrottleOutPacketType.Land);
1269 // }
1270 1262
1271 // Legacy form of invocation that passes around a bare data array. 1263 // Legacy form of invocation that passes around a bare data array.
1272 // Just ignore what was passed and use the real terrain info that is part of the scene. 1264 // Just ignore what was passed and use the real terrain info that is part of the scene.
1273 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI, 1265 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
1274 // there is a special form for specifying multiple terrain patches to send. 1266 // there is a special form for specifying multiple terrain patches to send.
1275 // The form is to pass 'px' as negative the number of patches to send and to 1267 // The form is to pass 'px' as negative the number of patches to send and to
1276 // pass the float array as pairs of patch X and Y coordinates. So, passing 'px' 1268 // pass the float array as pairs of patch X and Y coordinates. So, passing 'px'
@@ -1316,6 +1308,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1316 } 1308 }
1317 1309
1318 /// <summary> 1310 /// <summary>
1311
1319 /// Sends a terrain packet for the point specified. 1312 /// Sends a terrain packet for the point specified.
1320 /// This is a legacy call that has refarbed the terrain into a flat map of floats. 1313 /// This is a legacy call that has refarbed the terrain into a flat map of floats.
1321 /// We just use the terrain from the region we know about. 1314 /// We just use the terrain from the region we know about.
@@ -1334,32 +1327,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1334 { 1327 {
1335 try 1328 try
1336 { 1329 {
1337 /* test code using the terrain compressor in libOpenMetaverse 1330 byte landPacketType;
1338 int[] patchInd = new int[1]; 1331 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
1339 patchInd[0] = px + (py * Constants.TerrainPatchSize); 1332 landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
1340 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd); 1333 else
1341 */ 1334 landPacketType = (byte)TerrainPatch.LayerType.Land;
1342 // Many, many patches could have been passed to us. Since the patches will be compressed
1343 // into variable sized blocks, we cannot pre-compute how many will fit into one
1344 // packet. While some fancy packing algorithm is possible, 4 seems to always fit.
1345 int PatchesAssumedToFit = 4;
1346 for (int pcnt = 0; pcnt < px.Length; pcnt += PatchesAssumedToFit)
1347 {
1348 int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit);
1349 int[] xPatches = new int[remaining];
1350 int[] yPatches = new int[remaining];
1351 for (int ii = 0; ii < remaining; ii++)
1352 {
1353 xPatches[ii] = px[pcnt + ii];
1354 yPatches[ii] = py[pcnt + ii];
1355 }
1356 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches);
1357 // DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches);
1358
1359 SendTheLayerPacket(layerpack);
1360 }
1361 // LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, px, py);
1362 1335
1336 List<LayerDataPacket> packets = OpenSimTerrainCompressor.CreateLayerDataPackets(terrData, px, py, landPacketType);
1337 foreach(LayerDataPacket pkt in packets)
1338 OutPacket(pkt, ThrottleOutPacketType.Land);
1363 } 1339 }
1364 catch (Exception e) 1340 catch (Exception e)
1365 { 1341 {
@@ -1367,110 +1343,125 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1367 } 1343 }
1368 } 1344 }
1369 1345
1370 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a
1371 // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we
1372 // start skipping the queues until they're done editing the terrain. We also make them
1373 // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch
1374 // area invalidating previous packets for that area.
1375 1346
1376 // It's possible for an editing user to flood themselves with edited packets but the majority 1347 // wind caching
1377 // of use cases are such that only a tiny percentage of users will be editing the terrain. 1348 private static Dictionary<ulong,int> lastWindVersion = new Dictionary<ulong,int>();
1378 // Other, non-editing users will see the edits much slower. 1349 private static Dictionary<ulong,List<LayerDataPacket>> lastWindPackets =
1379 1350 new Dictionary<ulong,List<LayerDataPacket>>();
1380 // One last note on this topic, by the time users are going to be editing the terrain, it's
1381 // extremely likely that the sim will have rezzed already and therefore this is not likely going
1382 // to cause any additional issues with lost packets, objects or terrain patches.
1383 1351
1384 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we
1385 // only have one cache miss.
1386 private void SendTheLayerPacket(LayerDataPacket layerpack)
1387 {
1388 if (m_justEditedTerrain)
1389 {
1390 layerpack.Header.Reliable = false;
1391 OutPacket(layerpack, ThrottleOutPacketType.Unknown );
1392 }
1393 else
1394 {
1395 layerpack.Header.Reliable = true;
1396 OutPacket(layerpack, ThrottleOutPacketType.Land);
1397 }
1398 }
1399 1352
1400 /// <summary> 1353 /// <summary>
1401 /// Send the wind matrix to the client 1354 /// Send the wind matrix to the client
1402 /// </summary> 1355 /// </summary>
1403 /// <param name="windSpeeds">16x16 array of wind speeds</param> 1356 /// <param name="windSpeeds">16x16 array of wind speeds</param>
1404 public virtual void SendWindData(Vector2[] windSpeeds) 1357 public virtual void SendWindData(int version, Vector2[] windSpeeds)
1405 {
1406 Util.FireAndForget(DoSendWindData, windSpeeds, "LLClientView.SendWindData");
1407 }
1408
1409 /// <summary>
1410 /// Send the cloud matrix to the client
1411 /// </summary>
1412 /// <param name="windSpeeds">16x16 array of cloud densities</param>
1413 public virtual void SendCloudData(float[] cloudDensity)
1414 {
1415 Util.FireAndForget(DoSendCloudData, cloudDensity, "LLClientView.SendCloudData");
1416 }
1417
1418 /// <summary>
1419 /// Send wind layer information to the client.
1420 /// </summary>
1421 /// <param name="o"></param>
1422 private void DoSendWindData(object o)
1423 { 1358 {
1424 Vector2[] windSpeeds = (Vector2[])o; 1359// Vector2[] windSpeeds = (Vector2[])o;
1425 TerrainPatch[] patches = new TerrainPatch[2];
1426 patches[0] = new TerrainPatch { Data = new float[16 * 16] };
1427 patches[1] = new TerrainPatch { Data = new float[16 * 16] };
1428 1360
1429 for (int x = 0; x < 16 * 16; x++) 1361 ulong handle = this.Scene.RegionInfo.RegionHandle;
1362 bool isNewData;
1363 lock(lastWindPackets)
1430 { 1364 {
1431 patches[0].Data[x] = windSpeeds[x].X; 1365 if(!lastWindVersion.ContainsKey(handle) ||
1432 patches[1].Data[x] = windSpeeds[x].Y; 1366 !lastWindPackets.ContainsKey(handle))
1367 {
1368 lastWindVersion[handle] = 0;
1369 lastWindPackets[handle] = new List<LayerDataPacket>();
1370 isNewData = true;
1371 }
1372 else
1373 isNewData = lastWindVersion[handle] != version;
1433 } 1374 }
1434 1375
1435 byte layerType = (byte)TerrainPatch.LayerType.Wind; 1376 if(isNewData)
1436 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize) 1377 {
1437 layerType = (byte)TerrainPatch.LayerType.WindExtended; 1378 TerrainPatch[] patches = new TerrainPatch[2];
1379 patches[0] = new TerrainPatch { Data = new float[16 * 16] };
1380 patches[1] = new TerrainPatch { Data = new float[16 * 16] };
1381
1382 for (int x = 0; x < 16 * 16; x++)
1383 {
1384 patches[0].Data[x] = windSpeeds[x].X;
1385 patches[1].Data[x] = windSpeeds[x].Y;
1386 }
1387
1388 // neither we or viewers have extended wind
1389 byte layerType = (byte)TerrainPatch.LayerType.Wind;
1390
1391 LayerDataPacket layerpack =
1392 OpenSimTerrainCompressor.CreateLayerDataPacketStandardSize(
1393 patches, layerType);
1394 layerpack.Header.Zerocoded = true;
1395 lock(lastWindPackets)
1396 {
1397 lastWindPackets[handle].Clear();
1398 lastWindPackets[handle].Add(layerpack);
1399 lastWindVersion[handle] = version;
1400 }
1401 }
1438 1402
1439 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType); 1403 lock(lastWindPackets)
1440 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType, 1404 foreach(LayerDataPacket pkt in lastWindPackets[handle])
1441 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY); 1405 OutPacket(pkt, ThrottleOutPacketType.Wind);
1442 layerpack.Header.Zerocoded = true;
1443 OutPacket(layerpack, ThrottleOutPacketType.Wind);
1444 } 1406 }
1445 1407
1408 // cloud caching
1409 private static Dictionary<ulong,int> lastCloudVersion = new Dictionary<ulong,int>();
1410 private static Dictionary<ulong,List<LayerDataPacket>> lastCloudPackets =
1411 new Dictionary<ulong,List<LayerDataPacket>>();
1412
1446 /// <summary> 1413 /// <summary>
1447 /// Send cloud layer information to the client. 1414 /// Send the cloud matrix to the client
1448 /// </summary> 1415 /// </summary>
1449 /// <param name="o"></param> 1416 /// <param name="windSpeeds">16x16 array of cloud densities</param>
1450 private void DoSendCloudData(object o) 1417 public virtual void SendCloudData(int version, float[] cloudDensity)
1451 { 1418 {
1452 float[] cloudCover = (float[])o; 1419 ulong handle = this.Scene.RegionInfo.RegionHandle;
1453 TerrainPatch[] patches = new TerrainPatch[1]; 1420 bool isNewData;
1454 patches[0] = new TerrainPatch(); 1421 lock(lastWindPackets)
1455 patches[0].Data = new float[16 * 16];
1456
1457 for (int y = 0; y < 16; y++)
1458 { 1422 {
1459 for (int x = 0; x < 16; x++) 1423 if(!lastCloudVersion.ContainsKey(handle) ||
1424 !lastCloudPackets.ContainsKey(handle))
1460 { 1425 {
1461 patches[0].Data[y * 16 + x] = cloudCover[y * 16 + x]; 1426 lastCloudVersion[handle] = 0;
1427 lastCloudPackets[handle] = new List<LayerDataPacket>();
1428 isNewData = true;
1462 } 1429 }
1430 else
1431 isNewData = lastCloudVersion[handle] != version;
1463 } 1432 }
1464 1433
1465 byte layerType = (byte)TerrainPatch.LayerType.Cloud; 1434 if(isNewData)
1466 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize) 1435 {
1467 layerType = (byte)TerrainPatch.LayerType.CloudExtended; 1436 TerrainPatch[] patches = new TerrainPatch[1];
1437 patches[0] = new TerrainPatch();
1438 patches[0].Data = new float[16 * 16];
1439
1440 for (int y = 0; y < 16; y++)
1441 {
1442 for (int x = 0; x < 16; x++)
1443 {
1444 patches[0].Data[y * 16 + x] = cloudDensity[y * 16 + x];
1445 }
1446 }
1447 // neither we or viewers have extended clouds
1448 byte layerType = (byte)TerrainPatch.LayerType.Cloud;
1449
1450 LayerDataPacket layerpack =
1451 OpenSimTerrainCompressor.CreateLayerDataPacketStandardSize(
1452 patches, layerType);
1453 layerpack.Header.Zerocoded = true;
1454 lock(lastCloudPackets)
1455 {
1456 lastCloudPackets[handle].Clear();
1457 lastCloudPackets[handle].Add(layerpack);
1458 lastCloudVersion[handle] = version;
1459 }
1460 }
1468 1461
1469 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType); 1462 lock(lastCloudPackets)
1470 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType, 1463 foreach(LayerDataPacket pkt in lastCloudPackets[handle])
1471 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY); 1464 OutPacket(pkt, ThrottleOutPacketType.Cloud);
1472 layerpack.Header.Zerocoded = true;
1473 OutPacket(layerpack, ThrottleOutPacketType.Cloud);
1474 } 1465 }
1475 1466
1476 /// <summary> 1467 /// <summary>
@@ -1735,45 +1726,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1735 pc.PingID.OldestUnacked = 0; 1726 pc.PingID.OldestUnacked = 0;
1736 1727
1737 OutPacket(pc, ThrottleOutPacketType.Unknown); 1728 OutPacket(pc, ThrottleOutPacketType.Unknown);
1729 UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1738 } 1730 }
1739 1731
1740 public void SendKillObject(List<uint> localIDs) 1732 public void SendKillObject(List<uint> localIDs)
1741 { 1733 {
1742// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1734 // foreach (uint id in localIDs)
1735 // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1736
1737 // remove pending entities to reduce looping chances.
1738 lock (m_entityProps.SyncRoot)
1739 m_entityProps.Remove(localIDs);
1740 lock (m_entityUpdates.SyncRoot)
1741 m_entityUpdates.Remove(localIDs);
1743 1742
1744 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1743 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1745 // TODO: don't create new blocks if recycling an old packet 1744
1746 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; 1745 int perpacket = localIDs.Count;
1746 if(perpacket > 200)
1747 perpacket = 200;
1748
1749 int nsent = 0;
1750
1751 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[perpacket];
1747 for (int i = 0 ; i < localIDs.Count ; i++ ) 1752 for (int i = 0 ; i < localIDs.Count ; i++ )
1748 { 1753 {
1749 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock(); 1754 kill.ObjectData[nsent] = new KillObjectPacket.ObjectDataBlock();
1750 kill.ObjectData[i].ID = localIDs[i]; 1755 kill.ObjectData[nsent].ID = localIDs[i];
1751 }
1752 kill.Header.Reliable = true;
1753 kill.Header.Zerocoded = true;
1754 1756
1755 if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null) 1757 if(++nsent >= 200)
1756 {
1757 OutPacket(kill, ThrottleOutPacketType.Task);
1758 }
1759 else
1760 {
1761 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1762 // condition where a kill can be processed before an out-of-date update for the same object.
1763 // ProcessEntityUpdates() also takes the m_killRecord lock.
1764 lock (m_killRecord)
1765 { 1758 {
1766 foreach (uint localID in localIDs) 1759 kill.Header.Reliable = true;
1767 m_killRecord.Add(localID); 1760 kill.Header.Zerocoded = true;
1768
1769 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1770 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1771 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1772 // scene objects in a viewer until that viewer is relogged in.
1773 OutPacket(kill, ThrottleOutPacketType.Task); 1761 OutPacket(kill, ThrottleOutPacketType.Task);
1762
1763 perpacket = localIDs.Count - i - 1;
1764 if(perpacket == 0)
1765 break;
1766 if(perpacket > 200)
1767 perpacket = 200;
1768
1769 kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1770 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[perpacket];
1771 nsent = 0;
1774 } 1772 }
1775 } 1773 }
1776 } 1774
1775 if(nsent != 0)
1776 {
1777 kill.Header.Reliable = true;
1778 kill.Header.Zerocoded = true;
1779 OutPacket(kill, ThrottleOutPacketType.Task);
1780 }
1781 }
1777 1782
1778 /// <summary> 1783 /// <summary>
1779 /// Send information about the items contained in a folder to the client. 1784 /// Send information about the items contained in a folder to the client.
@@ -1895,7 +1900,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1895 newBlock.CreationDate = item.CreationDate; 1900 newBlock.CreationDate = item.CreationDate;
1896 newBlock.SalePrice = item.SalePrice; 1901 newBlock.SalePrice = item.SalePrice;
1897 newBlock.SaleType = item.SaleType; 1902 newBlock.SaleType = item.SaleType;
1898 newBlock.Flags = item.Flags; 1903 newBlock.Flags = item.Flags & 0x2000ff;
1899 1904
1900 newBlock.CRC = 1905 newBlock.CRC =
1901 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, 1906 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
@@ -2151,7 +2156,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2151 itemBlock.GroupID = item.GroupID; 2156 itemBlock.GroupID = item.GroupID;
2152 itemBlock.GroupOwned = item.GroupOwned; 2157 itemBlock.GroupOwned = item.GroupOwned;
2153 itemBlock.GroupMask = item.GroupPermissions; 2158 itemBlock.GroupMask = item.GroupPermissions;
2154 itemBlock.Flags = item.Flags; 2159 itemBlock.Flags = item.Flags & 0x2000ff;
2155 itemBlock.SalePrice = item.SalePrice; 2160 itemBlock.SalePrice = item.SalePrice;
2156 itemBlock.SaleType = item.SaleType; 2161 itemBlock.SaleType = item.SaleType;
2157 itemBlock.CreationDate = item.CreationDate; 2162 itemBlock.CreationDate = item.CreationDate;
@@ -2218,7 +2223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2218 bulkUpdate.ItemData[0].GroupID = item.GroupID; 2223 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2219 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; 2224 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2220 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; 2225 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2221 bulkUpdate.ItemData[0].Flags = item.Flags; 2226 bulkUpdate.ItemData[0].Flags = item.Flags & 0x2000ff;
2222 bulkUpdate.ItemData[0].SalePrice = item.SalePrice; 2227 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2223 bulkUpdate.ItemData[0].SaleType = item.SaleType; 2228 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2224 2229
@@ -2234,9 +2239,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2234 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2239 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2235 } 2240 }
2236 2241
2237 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2238 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2242 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2239 { 2243 {
2244 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2245 }
2246
2247 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2248 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2249 {
2240 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2250 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2241 2251
2242 UpdateCreateInventoryItemPacket InventoryReply 2252 UpdateCreateInventoryItemPacket InventoryReply
@@ -2246,6 +2256,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2246 // TODO: don't create new blocks if recycling an old packet 2256 // TODO: don't create new blocks if recycling an old packet
2247 InventoryReply.AgentData.AgentID = AgentId; 2257 InventoryReply.AgentData.AgentID = AgentId;
2248 InventoryReply.AgentData.SimApproved = true; 2258 InventoryReply.AgentData.SimApproved = true;
2259 InventoryReply.AgentData.TransactionID = transactionID;
2249 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2260 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2250 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2261 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2251 InventoryReply.InventoryData[0].ItemID = Item.ID; 2262 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2266,7 +2277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2266 InventoryReply.InventoryData[0].GroupID = Item.GroupID; 2277 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2267 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; 2278 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2268 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; 2279 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2269 InventoryReply.InventoryData[0].Flags = Item.Flags; 2280 InventoryReply.InventoryData[0].Flags = Item.Flags & 0x2000ff;
2270 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; 2281 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2271 InventoryReply.InventoryData[0].SaleType = Item.SaleType; 2282 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2272 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; 2283 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
@@ -2296,11 +2307,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2296 OutPacket(remove, ThrottleOutPacketType.Asset); 2307 OutPacket(remove, ThrottleOutPacketType.Asset);
2297 } 2308 }
2298 2309
2310/*
2311 private uint adjustControls(int input)
2312 {
2313 uint ret = (uint)input;
2314 uint masked = ret & 0x0f;
2315 masked <<= 19;
2316 ret |= masked;
2317 return ret;
2318 }
2319*/
2320
2299 public void SendTakeControls(int controls, bool passToAgent, bool TakeControls) 2321 public void SendTakeControls(int controls, bool passToAgent, bool TakeControls)
2300 { 2322 {
2301 ScriptControlChangePacket scriptcontrol = (ScriptControlChangePacket)PacketPool.Instance.GetPacket(PacketType.ScriptControlChange); 2323 ScriptControlChangePacket scriptcontrol = (ScriptControlChangePacket)PacketPool.Instance.GetPacket(PacketType.ScriptControlChange);
2302 ScriptControlChangePacket.DataBlock[] data = new ScriptControlChangePacket.DataBlock[1]; 2324 ScriptControlChangePacket.DataBlock[] data = new ScriptControlChangePacket.DataBlock[1];
2303 ScriptControlChangePacket.DataBlock ddata = new ScriptControlChangePacket.DataBlock(); 2325 ScriptControlChangePacket.DataBlock ddata = new ScriptControlChangePacket.DataBlock();
2326// ddata.Controls = adjustControls(controls);
2304 ddata.Controls = (uint)controls; 2327 ddata.Controls = (uint)controls;
2305 ddata.PassToAgent = passToAgent; 2328 ddata.PassToAgent = passToAgent;
2306 ddata.TakeControls = TakeControls; 2329 ddata.TakeControls = TakeControls;
@@ -2315,16 +2338,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2315 replytask.InventoryData.TaskID = taskID; 2338 replytask.InventoryData.TaskID = taskID;
2316 replytask.InventoryData.Serial = serial; 2339 replytask.InventoryData.Serial = serial;
2317 replytask.InventoryData.Filename = fileName; 2340 replytask.InventoryData.Filename = fileName;
2341// OutPacket(replytask, ThrottleOutPacketType.Task);
2318 OutPacket(replytask, ThrottleOutPacketType.Asset); 2342 OutPacket(replytask, ThrottleOutPacketType.Asset);
2319 } 2343 }
2320 2344
2321 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2345 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2322 { 2346 {
2347 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2348// if (isTaskInventory)
2349// type = ThrottleOutPacketType.Task;
2350
2323 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2351 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2324 sendXfer.XferID.ID = xferID; 2352 sendXfer.XferID.ID = xferID;
2325 sendXfer.XferID.Packet = packet; 2353 sendXfer.XferID.Packet = packet;
2326 sendXfer.DataPacket.Data = data; 2354 sendXfer.DataPacket.Data = data;
2327 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2355 OutPacket(sendXfer, type);
2328 } 2356 }
2329 2357
2330 public void SendAbortXferPacket(ulong xferID) 2358 public void SendAbortXferPacket(ulong xferID)
@@ -2415,6 +2443,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2415 OutPacket(alertPack, ThrottleOutPacketType.Task); 2443 OutPacket(alertPack, ThrottleOutPacketType.Task);
2416 } 2444 }
2417 2445
2446 public void SendAlertMessage(string message, string info)
2447 {
2448 AlertMessagePacket alertPack = (AlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AlertMessage);
2449 alertPack.AlertData = new AlertMessagePacket.AlertDataBlock();
2450 alertPack.AlertData.Message = Util.StringToBytes256(message);
2451 alertPack.AlertInfo = new AlertMessagePacket.AlertInfoBlock[1];
2452 alertPack.AlertInfo[0] = new AlertMessagePacket.AlertInfoBlock();
2453 alertPack.AlertInfo[0].Message = Util.StringToBytes256(info);
2454 alertPack.AlertInfo[0].ExtraParams = new Byte[0];
2455 OutPacket(alertPack, ThrottleOutPacketType.Task);
2456 }
2457
2418 /// <summary> 2458 /// <summary>
2419 /// Send an agent alert message to the client. 2459 /// Send an agent alert message to the client.
2420 /// </summary> 2460 /// </summary>
@@ -2471,14 +2511,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2471 // this is the username of the *owner* 2511 // this is the username of the *owner*
2472 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); 2512 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName);
2473 dialog.Data.LastName = Util.StringToBytes256(ownerLastName); 2513 dialog.Data.LastName = Util.StringToBytes256(ownerLastName);
2474 dialog.Data.Message = Util.StringToBytes1024(msg); 2514 dialog.Data.Message = Util.StringToBytes(msg,512);
2475 dialog.Data.ImageID = textureID; 2515 dialog.Data.ImageID = textureID;
2476 dialog.Data.ChatChannel = ch; 2516 dialog.Data.ChatChannel = ch;
2477 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length]; 2517 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[buttonlabels.Length];
2478 for (int i = 0; i < buttonlabels.Length; i++) 2518 for (int i = 0; i < buttonlabels.Length; i++)
2479 { 2519 {
2480 buttons[i] = new ScriptDialogPacket.ButtonsBlock(); 2520 buttons[i] = new ScriptDialogPacket.ButtonsBlock();
2481 buttons[i].ButtonLabel = Util.StringToBytes256(buttonlabels[i]); 2521 buttons[i].ButtonLabel = Util.StringToBytes(buttonlabels[i],24);
2482 } 2522 }
2483 dialog.Buttons = buttons; 2523 dialog.Buttons = buttons;
2484 2524
@@ -2514,6 +2554,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2514 OutPacket(sound, ThrottleOutPacketType.Task); 2554 OutPacket(sound, ThrottleOutPacketType.Task);
2515 } 2555 }
2516 2556
2557 public void SendTransferAbort(TransferRequestPacket transferRequest)
2558 {
2559 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2560 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2561 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2562 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2563 OutPacket(abort, ThrottleOutPacketType.Task);
2564 }
2565
2517 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2566 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2518 { 2567 {
2519 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2568 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2632,7 +2681,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2632 OutPacket(packet, ThrottleOutPacketType.Task); 2681 OutPacket(packet, ThrottleOutPacketType.Task);
2633 } 2682 }
2634 2683
2635 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, 2684 public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType,
2636 string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, 2685 string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL,
2637 UUID partnerID) 2686 UUID partnerID)
2638 { 2687 {
@@ -2644,7 +2693,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2644 else 2693 else
2645 avatarReply.PropertiesData.AboutText = Utils.EmptyBytes; 2694 avatarReply.PropertiesData.AboutText = Utils.EmptyBytes;
2646 avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn); 2695 avatarReply.PropertiesData.BornOn = Util.StringToBytes256(bornOn);
2647 avatarReply.PropertiesData.CharterMember = charterMember; 2696 avatarReply.PropertiesData.CharterMember = membershipType;
2648 if (flAbout != null) 2697 if (flAbout != null)
2649 avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout); 2698 avatarReply.PropertiesData.FLAboutText = Util.StringToBytes256(flAbout);
2650 else 2699 else
@@ -2730,8 +2779,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2730 OutPacket(offp, ThrottleOutPacketType.Task); 2779 OutPacket(offp, ThrottleOutPacketType.Task);
2731 } 2780 }
2732 2781
2733 public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, 2782 public void SendFindAgent(UUID HunterID, UUID PreyID, double GlobalX, double GlobalY)
2734 Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) 2783 {
2784 FindAgentPacket fap = new FindAgentPacket();
2785 fap.AgentBlock.Hunter = HunterID;
2786 fap.AgentBlock.Prey = PreyID;
2787 fap.AgentBlock.SpaceIP = 0;
2788
2789 fap.LocationBlock = new FindAgentPacket.LocationBlockBlock[1];
2790 fap.LocationBlock[0] = new FindAgentPacket.LocationBlockBlock();
2791 fap.LocationBlock[0].GlobalX = GlobalX;
2792 fap.LocationBlock[0].GlobalY = GlobalY;
2793
2794 OutPacket(fap, ThrottleOutPacketType.Task);
2795 }
2796
2797 public void SendSitResponse(UUID TargetID, Vector3 OffsetPos,
2798 Quaternion SitOrientation, bool autopilot,
2799 Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook)
2735 { 2800 {
2736 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket(); 2801 AvatarSitResponsePacket avatarSitResponse = new AvatarSitResponsePacket();
2737 avatarSitResponse.SitObject.ID = TargetID; 2802 avatarSitResponse.SitObject.ID = TargetID;
@@ -2763,46 +2828,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2763 2828
2764 public void SendGroupMembership(GroupMembershipData[] GroupMembership) 2829 public void SendGroupMembership(GroupMembershipData[] GroupMembership)
2765 { 2830 {
2766 m_groupPowers.Clear();
2767 2831
2768 AgentGroupDataUpdatePacket Groupupdate = new AgentGroupDataUpdatePacket(); 2832 UpdateGroupMembership(GroupMembership);
2769 AgentGroupDataUpdatePacket.GroupDataBlock[] Groups = new AgentGroupDataUpdatePacket.GroupDataBlock[GroupMembership.Length]; 2833 SendAgentGroupDataUpdate(AgentId,GroupMembership);
2770 for (int i = 0; i < GroupMembership.Length; i++) 2834 }
2771 {
2772 m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers;
2773 2835
2774 AgentGroupDataUpdatePacket.GroupDataBlock Group = new AgentGroupDataUpdatePacket.GroupDataBlock(); 2836 public void SendSelectedPartsProprieties(List<ISceneEntity> parts)
2775 Group.AcceptNotices = GroupMembership[i].AcceptNotices; 2837 {
2776 Group.Contribution = GroupMembership[i].Contribution; 2838/* not in use
2777 Group.GroupID = GroupMembership[i].GroupID; 2839 // udp part
2778 Group.GroupInsigniaID = GroupMembership[i].GroupPicture; 2840 ObjectPropertiesPacket packet =
2779 Group.GroupName = Util.StringToBytes256(GroupMembership[i].GroupName); 2841 (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
2780 Group.GroupPowers = GroupMembership[i].GroupPowers; 2842 ObjectPropertiesPacket.ObjectDataBlock[] ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[parts.Count];
2781 Groups[i] = Group;
2782 2843
2844 int i = 0;
2845 foreach(SceneObjectPart sop in parts)
2846 ObjectData[i++] = CreateObjectPropertiesBlock(sop);
2783 2847
2784 } 2848 packet.ObjectData = ObjectData;
2785 Groupupdate.GroupData = Groups; 2849 packet.Header.Zerocoded = true;
2786 Groupupdate.AgentData = new AgentGroupDataUpdatePacket.AgentDataBlock(); 2850 // udp send splits this mega packets correctly
2787 Groupupdate.AgentData.AgentID = AgentId; 2851 // mb later will avoid that to reduce gc stress
2788 OutPacket(Groupupdate, ThrottleOutPacketType.Task); 2852 OutPacket(packet, ThrottleOutPacketType.Task, true);
2789 2853
2790 try 2854 // caps physics part
2791 { 2855 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2792 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); 2856 if(eq == null)
2793 if (eq != null) 2857 return;
2794 { 2858
2795 eq.GroupMembership(Groupupdate, this.AgentId); 2859 OSDArray array = new OSDArray();
2796 } 2860 foreach(SceneObjectPart sop in parts)
2797 }
2798 catch (Exception ex)
2799 { 2861 {
2800 m_log.Error("Unable to send group membership data via eventqueue - exception: " + ex.ToString()); 2862 OSDMap physinfo = new OSDMap(6);
2801 m_log.Warn("sending group membership data via UDP"); 2863 physinfo["LocalID"] = sop.LocalId;
2802 OutPacket(Groupupdate, ThrottleOutPacketType.Task); 2864 physinfo["Density"] = sop.Density;
2865 physinfo["Friction"] = sop.Friction;
2866 physinfo["GravityMultiplier"] = sop.GravityModifier;
2867 physinfo["Restitution"] = sop.Restitution;
2868 physinfo["PhysicsShapeType"] = (int)sop.PhysicsShapeType;
2869 array.Add(physinfo);
2803 } 2870 }
2871
2872 OSDMap llsdBody = new OSDMap(1);
2873 llsdBody.Add("ObjectData", array);
2874
2875 eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId);
2876*/
2804 } 2877 }
2805 2878
2879
2806 public void SendPartPhysicsProprieties(ISceneEntity entity) 2880 public void SendPartPhysicsProprieties(ISceneEntity entity)
2807 { 2881 {
2808 SceneObjectPart part = (SceneObjectPart)entity; 2882 SceneObjectPart part = (SceneObjectPart)entity;
@@ -2819,6 +2893,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2819 float friction = part.Friction; 2893 float friction = part.Friction;
2820 float bounce = part.Restitution; 2894 float bounce = part.Restitution;
2821 float gravmod = part.GravityModifier; 2895 float gravmod = part.GravityModifier;
2896
2822 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2897 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2823 } 2898 }
2824 } 2899 }
@@ -2826,7 +2901,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2826 { 2901 {
2827 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString()); 2902 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString());
2828 } 2903 }
2829 part.UpdatePhysRequired = false;
2830 } 2904 }
2831 } 2905 }
2832 2906
@@ -2883,6 +2957,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2883 2957
2884 public void SendAsset(AssetRequestToClient req) 2958 public void SendAsset(AssetRequestToClient req)
2885 { 2959 {
2960 if (req.AssetInf == null)
2961 {
2962 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset is null",
2963 LogHeader);
2964 return;
2965 }
2966
2886 if (req.AssetInf.Data == null) 2967 if (req.AssetInf.Data == null)
2887 { 2968 {
2888 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null", 2969 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null",
@@ -2890,7 +2971,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2890 return; 2971 return;
2891 } 2972 }
2892 2973
2893 //m_log.Debug("sending asset " + req.RequestAssetID); 2974 bool isWearable = false;
2975
2976 isWearable = ((AssetType) req.AssetInf.Type ==
2977 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2978
2979
2980 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2981
2982
2983 //if (isWearable)
2984 // m_log.Debug((AssetType)req.AssetInf.Type);
2985
2894 TransferInfoPacket Transfer = new TransferInfoPacket(); 2986 TransferInfoPacket Transfer = new TransferInfoPacket();
2895 Transfer.TransferInfo.ChannelType = 2; 2987 Transfer.TransferInfo.ChannelType = 2;
2896 Transfer.TransferInfo.Status = 0; 2988 Transfer.TransferInfo.Status = 0;
@@ -2912,7 +3004,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2912 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 3004 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2913 Transfer.TransferInfo.TransferID = req.TransferRequestID; 3005 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2914 Transfer.Header.Zerocoded = true; 3006 Transfer.Header.Zerocoded = true;
2915 OutPacket(Transfer, ThrottleOutPacketType.Asset); 3007 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2916 3008
2917 if (req.NumPackets == 1) 3009 if (req.NumPackets == 1)
2918 { 3010 {
@@ -2923,12 +3015,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2923 TransferPacket.TransferData.Data = req.AssetInf.Data; 3015 TransferPacket.TransferData.Data = req.AssetInf.Data;
2924 TransferPacket.TransferData.Status = 1; 3016 TransferPacket.TransferData.Status = 1;
2925 TransferPacket.Header.Zerocoded = true; 3017 TransferPacket.Header.Zerocoded = true;
2926 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 3018 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2927 } 3019 }
2928 else 3020 else
2929 { 3021 {
2930 int processedLength = 0; 3022 int processedLength = 0;
2931 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 3023// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
3024
3025 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2932 int packetNumber = 0; 3026 int packetNumber = 0;
2933 3027
2934 while (processedLength < req.AssetInf.Data.Length) 3028 while (processedLength < req.AssetInf.Data.Length)
@@ -2954,7 +3048,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2954 TransferPacket.TransferData.Status = 1; 3048 TransferPacket.TransferData.Status = 1;
2955 } 3049 }
2956 TransferPacket.Header.Zerocoded = true; 3050 TransferPacket.Header.Zerocoded = true;
2957 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 3051 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2958 3052
2959 processedLength += chunkSize; 3053 processedLength += chunkSize;
2960 packetNumber++; 3054 packetNumber++;
@@ -2990,23 +3084,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2990 3084
2991 public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y) 3085 public void SendParcelInfo(RegionInfo info, LandData land, UUID parcelID, uint x, uint y)
2992 { 3086 {
2993 float dwell = 0.0f;
2994 IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
2995 if (dwellModule != null)
2996 dwell = dwellModule.GetDwell(land.GlobalID);
2997 ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply); 3087 ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply);
2998 reply.AgentData.AgentID = m_agentId; 3088 reply.AgentData.AgentID = m_agentId;
2999 reply.Data.ParcelID = parcelID; 3089 reply.Data.ParcelID = parcelID;
3000 reply.Data.OwnerID = land.OwnerID; 3090 reply.Data.OwnerID = land.OwnerID;
3001 reply.Data.Name = Utils.StringToBytes(land.Name); 3091 reply.Data.Name = Utils.StringToBytes(land.Name);
3002 reply.Data.Desc = Utils.StringToBytes(land.Description); 3092 if (land.Description != null && land.Description != String.Empty)
3093 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
3094 else
3095 reply.Data.Desc = new Byte[0];
3003 reply.Data.ActualArea = land.Area; 3096 reply.Data.ActualArea = land.Area;
3004 reply.Data.BillableArea = land.Area; // TODO: what is this? 3097 reply.Data.BillableArea = land.Area; // TODO: what is this?
3005 3098
3006 // Bit 0: Mature, bit 7: on sale, other bits: no idea 3099 reply.Data.Flags = (byte)Util.ConvertAccessLevelToMaturity((byte)info.AccessLevel);
3007 reply.Data.Flags = (byte)( 3100 if((land.Flags & (uint)ParcelFlags.ForSale) != 0)
3008 (info.AccessLevel > 13 ? (1 << 0) : 0) + 3101 reply.Data.Flags |= (byte)((1 << 7));
3009 ((land.Flags & (uint)ParcelFlags.ForSale) != 0 ? (1 << 7) : 0));
3010 3102
3011 Vector3 pos = land.UserLocation; 3103 Vector3 pos = land.UserLocation;
3012 if (pos.Equals(Vector3.Zero)) 3104 if (pos.Equals(Vector3.Zero))
@@ -3018,7 +3110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3018 reply.Data.GlobalZ = pos.Z; 3110 reply.Data.GlobalZ = pos.Z;
3019 reply.Data.SimName = Utils.StringToBytes(info.RegionName); 3111 reply.Data.SimName = Utils.StringToBytes(info.RegionName);
3020 reply.Data.SnapshotID = land.SnapshotID; 3112 reply.Data.SnapshotID = land.SnapshotID;
3021 reply.Data.Dwell = dwell; 3113 reply.Data.Dwell = land.Dwell;
3022 reply.Data.SalePrice = land.SalePrice; 3114 reply.Data.SalePrice = land.SalePrice;
3023 reply.Data.AuctionID = (int)land.AuctionID; 3115 reply.Data.AuctionID = (int)land.AuctionID;
3024 3116
@@ -3385,7 +3477,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3385 AgentData.Add(AgentDataMap); 3477 AgentData.Add(AgentDataMap);
3386 llsd.Add("AgentData", AgentData); 3478 llsd.Add("AgentData", AgentData);
3387 OSDArray GroupData = new OSDArray(data.Length); 3479 OSDArray GroupData = new OSDArray(data.Length);
3388 OSDArray NewGroupData = new OSDArray(data.Length); 3480// OSDArray NewGroupData = new OSDArray(data.Length);
3389 foreach (GroupMembershipData m in data) 3481 foreach (GroupMembershipData m in data)
3390 { 3482 {
3391 OSDMap GroupDataMap = new OSDMap(6); 3483 OSDMap GroupDataMap = new OSDMap(6);
@@ -3396,12 +3488,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3396 GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID)); 3488 GroupDataMap.Add("GroupID", OSD.FromUUID(m.GroupID));
3397 GroupDataMap.Add("GroupName", OSD.FromString(m.GroupName)); 3489 GroupDataMap.Add("GroupName", OSD.FromString(m.GroupName));
3398 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(m.GroupPicture)); 3490 GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(m.GroupPicture));
3399 NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(m.ListInProfile)); 3491// NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(m.ListInProfile));
3400 GroupData.Add(GroupDataMap); 3492 GroupData.Add(GroupDataMap);
3401 NewGroupData.Add(NewGroupDataMap); 3493// NewGroupData.Add(NewGroupDataMap);
3402 } 3494 }
3403 llsd.Add("GroupData", GroupData); 3495 llsd.Add("GroupData", GroupData);
3404 llsd.Add("NewGroupData", NewGroupData); 3496 // llsd.Add("NewGroupData", NewGroupData);
3405 3497
3406 IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>(); 3498 IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>();
3407 if (eq != null) 3499 if (eq != null)
@@ -3410,6 +3502,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3410 } 3502 }
3411 } 3503 }
3412 3504
3505 public void SendAgentGroupDataUpdate(UUID avatarID, GroupMembershipData[] data)
3506 {
3507 if(avatarID != AgentId)
3508 m_log.Debug("[CLIENT]: SendAgentGroupDataUpdate avatarID != AgentId");
3509
3510 IEventQueue eq = this.Scene.RequestModuleInterface<IEventQueue>();
3511 if(eq != null)
3512 {
3513 eq.GroupMembershipData(avatarID,data);
3514 }
3515 else
3516 {
3517 // use UDP if no caps
3518 AgentGroupDataUpdatePacket Groupupdate = new AgentGroupDataUpdatePacket();
3519 AgentGroupDataUpdatePacket.GroupDataBlock[] Groups = new AgentGroupDataUpdatePacket.GroupDataBlock[data.Length];
3520 for (int i = 0; i < data.Length; i++)
3521 {
3522 AgentGroupDataUpdatePacket.GroupDataBlock Group = new AgentGroupDataUpdatePacket.GroupDataBlock();
3523 Group.AcceptNotices = data[i].AcceptNotices;
3524 Group.Contribution = data[i].Contribution;
3525 Group.GroupID = data[i].GroupID;
3526 Group.GroupInsigniaID = data[i].GroupPicture;
3527 Group.GroupName = Util.StringToBytes256(data[i].GroupName);
3528 Group.GroupPowers = data[i].GroupPowers;
3529 Groups[i] = Group;
3530 }
3531 Groupupdate.GroupData = Groups;
3532 Groupupdate.AgentData = new AgentGroupDataUpdatePacket.AgentDataBlock();
3533 Groupupdate.AgentData.AgentID = avatarID;
3534 OutPacket(Groupupdate, ThrottleOutPacketType.Task);
3535 }
3536 }
3537
3413 public void SendJoinGroupReply(UUID groupID, bool success) 3538 public void SendJoinGroupReply(UUID groupID, bool success)
3414 { 3539 {
3415 JoinGroupReplyPacket p = (JoinGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.JoinGroupReply); 3540 JoinGroupReplyPacket p = (JoinGroupReplyPacket)PacketPool.Instance.GetPacket(PacketType.JoinGroupReply);
@@ -3649,6 +3774,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3649 OutPacket(useCachedMuteList, ThrottleOutPacketType.Task); 3774 OutPacket(useCachedMuteList, ThrottleOutPacketType.Task);
3650 } 3775 }
3651 3776
3777 public void SendEmpytMuteList()
3778 {
3779 GenericMessagePacket gmp = new GenericMessagePacket();
3780
3781 gmp.AgentData.AgentID = AgentId;
3782 gmp.AgentData.SessionID = m_sessionId;
3783 gmp.AgentData.TransactionID = UUID.Zero;
3784
3785 gmp.MethodData.Method = Util.StringToBytes256("emptymutelist");
3786 gmp.ParamList = new GenericMessagePacket.ParamListBlock[1];
3787 gmp.ParamList[0] = new GenericMessagePacket.ParamListBlock();
3788 gmp.ParamList[0].Parameter = new byte[0];
3789
3790 OutPacket(gmp, ThrottleOutPacketType.Task);
3791 }
3792
3652 public void SendMuteListUpdate(string filename) 3793 public void SendMuteListUpdate(string filename)
3653 { 3794 {
3654 MuteListUpdatePacket muteListUpdate = (MuteListUpdatePacket)PacketPool.Instance.GetPacket(PacketType.MuteListUpdate); 3795 MuteListUpdatePacket muteListUpdate = (MuteListUpdatePacket)PacketPool.Instance.GetPacket(PacketType.MuteListUpdate);
@@ -3706,24 +3847,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3706 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3847 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3707 AgentWearablesUpdatePacket.WearableDataBlock awb; 3848 AgentWearablesUpdatePacket.WearableDataBlock awb;
3708 int idx = 0; 3849 int idx = 0;
3709 for (int i = 0; i < wearables.Length; i++)
3710 {
3711 for (int j = 0; j < wearables[i].Count; j++)
3712 {
3713 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3714 awb.WearableType = (byte)i;
3715 awb.AssetID = wearables[i][j].AssetID;
3716 awb.ItemID = wearables[i][j].ItemID;
3717 aw.WearableData[idx] = awb;
3718 idx++;
3719 3850
3720// m_log.DebugFormat( 3851 for (int i = 0; i < wearables.Length; i++)
3721// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3852 {
3722// awb.ItemID, awb.AssetID, i, Name); 3853 for (int j = 0; j < wearables[i].Count; j++)
3723 } 3854 {
3724 } 3855 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3856 awb.WearableType = (byte) i;
3857 awb.AssetID = wearables[i][j].AssetID;
3858 awb.ItemID = wearables[i][j].ItemID;
3859 aw.WearableData[idx] = awb;
3860 idx++;
3861
3862 // m_log.DebugFormat(
3863 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3864 // awb.ItemID, awb.AssetID, i, Name);
3865 }
3866 }
3725 3867
3726 OutPacket(aw, ThrottleOutPacketType.Task); 3868 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3727 } 3869 }
3728 3870
3729 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3871 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3749,8 +3891,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3749 avp.Sender.ID = agentID; 3891 avp.Sender.ID = agentID;
3750 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; 3892 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3751 avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0]; 3893 avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0];
3894
3895// this need be use in future ?
3896// avp.AppearanceData[0].AppearanceVersion = 0;
3897// avp.AppearanceData[0].CofVersion = 0;
3898
3752 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3899 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3753 OutPacket(avp, ThrottleOutPacketType.Task); 3900 OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3754 } 3901 }
3755 3902
3756 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) 3903 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
@@ -3778,7 +3925,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3778 ani.AnimationSourceList[i].ObjectID = objectIDs[i]; 3925 ani.AnimationSourceList[i].ObjectID = objectIDs[i];
3779 } 3926 }
3780 ani.Header.Reliable = false; 3927 ani.Header.Reliable = false;
3781 OutPacket(ani, ThrottleOutPacketType.Task); 3928 OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3782 } 3929 }
3783 3930
3784 #endregion 3931 #endregion
@@ -3788,26 +3935,70 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3788 /// <summary> 3935 /// <summary>
3789 /// Send an ObjectUpdate packet with information about an avatar 3936 /// Send an ObjectUpdate packet with information about an avatar
3790 /// </summary> 3937 /// </summary>
3791 public void SendAvatarDataImmediate(ISceneEntity avatar) 3938 public void SendEntityFullUpdateImmediate(ISceneEntity ent)
3792 { 3939 {
3793// m_log.DebugFormat( 3940// m_log.DebugFormat(
3794// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}", 3941// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}",
3795// avatar.Name, avatar.UUID, Name, AgentId); 3942// avatar.Name, avatar.UUID, Name, AgentId);
3796 3943
3797 ScenePresence presence = avatar as ScenePresence; 3944 if (ent == null)
3798 if (presence == null)
3799 return; 3945 return;
3800 3946
3801 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3947 ObjectUpdatePacket objupdate = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3802 objupdate.Header.Zerocoded = true; 3948 objupdate.Header.Zerocoded = true;
3803 3949
3804 objupdate.RegionData.RegionHandle = presence.RegionHandle; 3950 objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
3805 objupdate.RegionData.TimeDilation = ushort.MaxValue;
3806
3807 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; 3951 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3808 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3809 3952
3810 OutPacket(objupdate, ThrottleOutPacketType.Task); 3953 if(ent is ScenePresence)
3954 {
3955 ScenePresence presence = ent as ScenePresence;
3956 objupdate.RegionData.RegionHandle = presence.RegionHandle;
3957 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3958 }
3959 else if(ent is SceneObjectPart)
3960 {
3961 SceneObjectPart part = ent as SceneObjectPart;
3962 objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3963 objupdate.ObjectData[0] = CreatePrimUpdateBlock(part, (ScenePresence)SceneAgent);
3964 }
3965
3966 OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3967
3968 // We need to record the avatar local id since the root prim of an attachment points to this.
3969// m_attachmentsSent.Add(avatar.LocalId);
3970 }
3971
3972 public void SendEntityTerseUpdateImmediate(ISceneEntity ent)
3973 {
3974// m_log.DebugFormat(
3975// "[LLCLIENTVIEW]: Sending immediate object update for avatar {0} {1} to {2} {3}",
3976// avatar.Name, avatar.UUID, Name, AgentId);
3977
3978 if (ent == null)
3979 return;
3980
3981 ImprovedTerseObjectUpdatePacket objupdate =
3982 (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3983 objupdate.Header.Zerocoded = true;
3984
3985 objupdate.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
3986 objupdate.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
3987
3988 if(ent is ScenePresence)
3989 {
3990 ScenePresence presence = ent as ScenePresence;
3991 objupdate.RegionData.RegionHandle = presence.RegionHandle;
3992 objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent, false);
3993 }
3994 else if(ent is SceneObjectPart)
3995 {
3996 SceneObjectPart part = ent as SceneObjectPart;
3997 objupdate.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3998 objupdate.ObjectData[0] = CreateImprovedTerseBlock(ent, false);
3999 }
4000
4001 OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3811 4002
3812 // We need to record the avatar local id since the root prim of an attachment points to this. 4003 // We need to record the avatar local id since the root prim of an attachment points to this.
3813// m_attachmentsSent.Add(avatar.LocalId); 4004// m_attachmentsSent.Add(avatar.LocalId);
@@ -3859,13 +4050,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3859 4050
3860 #region Primitive Packet/Data Sending Methods 4051 #region Primitive Packet/Data Sending Methods
3861 4052
3862
3863 /// <summary> 4053 /// <summary>
3864 /// Generate one of the object update packets based on PrimUpdateFlags 4054 /// Generate one of the object update packets based on PrimUpdateFlags
3865 /// and broadcast the packet to clients 4055 /// and broadcast the packet to clients
3866 /// </summary> 4056 /// </summary>
3867 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 4057 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3868 { 4058 {
4059/*
3869 if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 4060 if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3870 { 4061 {
3871 ImprovedTerseObjectUpdatePacket packet 4062 ImprovedTerseObjectUpdatePacket packet
@@ -3876,21 +4067,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3876 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; 4067 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
3877 packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false); 4068 packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false);
3878 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 4069 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4070 return;
3879 } 4071 }
3880 else 4072*/
4073 if (entity is SceneObjectPart)
3881 { 4074 {
3882 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 4075 SceneObjectPart p = (SceneObjectPart)entity;
3883 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 4076 SceneObjectGroup g = p.ParentGroup;
3884 4077 if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId)
3885 lock (m_entityUpdates.SyncRoot) 4078 return; // Don't send updates for other people's HUDs
3886 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 4079
4080 if((updateFlags ^ PrimUpdateFlags.SendInTransit) == 0)
4081 {
4082 List<uint> partIDs = (new List<uint> {p.LocalId});
4083 lock (m_entityProps.SyncRoot)
4084 m_entityProps.Remove(partIDs);
4085 lock (m_entityUpdates.SyncRoot)
4086 m_entityUpdates.Remove(partIDs);
4087 return;
4088 }
3887 } 4089 }
4090
4091 //double priority = m_prioritizer.GetUpdatePriority(this, entity);
4092 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
4093
4094 lock (m_entityUpdates.SyncRoot)
4095 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags));
3888 } 4096 }
3889 4097
3890 /// <summary> 4098 /// <summary>
3891 /// Requeue an EntityUpdate when it was not acknowledged by the client. 4099 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3892 /// We will update the priority and put it in the correct queue, merging update flags 4100 /// We will update the priority and put it in the correct queue, merging update flags
3893 /// with any other updates that may be queued for the same entity. 4101 /// with any other updates that may be queued for the same entity.
3894 /// The original update time is used for the merged update. 4102 /// The original update time is used for the merged update.
3895 /// </summary> 4103 /// </summary>
3896 private void ResendPrimUpdate(EntityUpdate update) 4104 private void ResendPrimUpdate(EntityUpdate update)
@@ -3904,9 +4112,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3904 } 4112 }
3905 4113
3906 /// <summary> 4114 /// <summary>
3907 /// Requeue a list of EntityUpdates when they were not acknowledged by the client. 4115 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3908 /// We will update the priority and put it in the correct queue, merging update flags 4116 /// We will update the priority and put it in the correct queue, merging update flags
3909 /// with any other updates that may be queued for the same entity. 4117 /// with any other updates that may be queued for the same entity.
3910 /// The original update time is used for the merged update. 4118 /// The original update time is used for the merged update.
3911 /// </summary> 4119 /// </summary>
3912 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket) 4120 private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket)
@@ -3919,7 +4127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3919 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); 4127 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3920 4128
3921 // Count this as a resent packet since we are going to requeue all of the updates contained in it 4129 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3922 Interlocked.Increment(ref m_udpClient.PacketsResent); 4130 Interlocked.Increment(ref m_udpClient.PacketsResent);
3923 4131
3924 // We're not going to worry about interlock yet since its not currently critical that this total count 4132 // We're not going to worry about interlock yet since its not currently critical that this total count
3925 // is 100% correct 4133 // is 100% correct
@@ -3929,335 +4137,515 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3929 ResendPrimUpdate(update); 4137 ResendPrimUpdate(update);
3930 } 4138 }
3931 4139
3932// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 4140 private List<ObjectUpdatePacket.ObjectDataBlock> objectUpdateBlocks = new List<ObjectUpdatePacket.ObjectDataBlock>();
3933// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>(); 4141 private List<ObjectUpdateCompressedPacket.ObjectDataBlock> compressedUpdateBlocks = new List<ObjectUpdateCompressedPacket.ObjectDataBlock>();
3934// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 4142 private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> terseUpdateBlocks = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
3935// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 4143 private List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> terseAgentUpdateBlocks = new List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
3936//
3937// OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3938// OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3939// OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3940// OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3941
3942 4144
3943 private void ProcessEntityUpdates(int maxUpdates) 4145 private void ProcessEntityUpdates(int maxUpdatesBytes)
3944 { 4146 {
3945 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3946 OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3947 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3948 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3949
3950 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 4147 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3951 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 4148 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3952 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 4149 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3953 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 4150 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3954 4151
3955// objectUpdateBlocks.Value.Clear();
3956// compressedUpdateBlocks.Value.Clear();
3957// terseUpdateBlocks.Value.Clear();
3958// terseAgentUpdateBlocks.Value.Clear();
3959// objectUpdates.Value.Clear();
3960// compressedUpdates.Value.Clear();
3961// terseUpdates.Value.Clear();
3962// terseAgentUpdates.Value.Clear();
3963
3964 // Check to see if this is a flush 4152 // Check to see if this is a flush
3965 if (maxUpdates <= 0) 4153 if (maxUpdatesBytes <= 0)
3966 { 4154 {
3967 maxUpdates = Int32.MaxValue; 4155 maxUpdatesBytes = Int32.MaxValue;
3968 } 4156 }
3969 4157
3970 int updatesThisCall = 0; 4158 EntityUpdate update;
4159 Int32 timeinqueue; // this is just debugging code & can be dropped later
4160
4161 bool doCulling = m_scene.ObjectsCullingByDistance;
4162 float cullingrange = 64.0f;
4163 HashSet<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>();
4164// Vector3 mycamera = Vector3.Zero;
4165 Vector3 mypos = Vector3.Zero;
4166 ScenePresence mysp = (ScenePresence)SceneAgent;
4167
4168 bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance;
4169 // we should have a presence
4170 if(mysp == null)
4171 return;
3971 4172
3972 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 4173 if(doCulling)
3973 // condition where a kill can be processed before an out-of-date update for the same object.
3974 lock (m_killRecord)
3975 { 4174 {
3976 float avgTimeDilation = 1.0f; 4175 cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f;
3977 IEntityUpdate iupdate; 4176// mycamera = mysp.CameraPosition;
3978 Int32 timeinqueue; // this is just debugging code & can be dropped later 4177 mypos = mysp.AbsolutePosition;
4178 }
3979 4179
3980 while (updatesThisCall < maxUpdates) 4180 while (maxUpdatesBytes > 0)
4181 {
4182 lock (m_entityUpdates.SyncRoot)
3981 { 4183 {
3982 lock (m_entityUpdates.SyncRoot) 4184 if(orderedDequeue)
3983 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) 4185 {
4186 if (!m_entityUpdates.TryOrderedDequeue(out update, out timeinqueue))
3984 break; 4187 break;
4188 }
4189 else
4190 {
4191 if (!m_entityUpdates.TryDequeue(out update, out timeinqueue))
4192 break;
4193 }
4194 }
3985 4195
3986 EntityUpdate update = (EntityUpdate)iupdate; 4196 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3987
3988 avgTimeDilation += update.TimeDilation;
3989 avgTimeDilation *= 0.5f;
3990 4197
3991 if (update.Entity is SceneObjectPart) 4198 if(updateFlags.HasFlag(PrimUpdateFlags.Kill))
4199 {
4200 m_killRecord.Add(update.Entity.LocalId);
4201 maxUpdatesBytes -= 30;
4202 continue;
4203 }
4204
4205 if (update.Entity is SceneObjectPart)
4206 {
4207 SceneObjectPart part = (SceneObjectPart)update.Entity;
4208 SceneObjectGroup grp = part.ParentGroup;
4209 if (grp.inTransit && !update.Flags.HasFlag(PrimUpdateFlags.SendInTransit))
4210 continue;
4211/* debug
4212 if (update.Flags.HasFlag(PrimUpdateFlags.SendInTransit))
4213 {
4214
4215
4216 }
4217*/
4218 if (grp.IsDeleted)
3992 { 4219 {
3993 SceneObjectPart part = (SceneObjectPart)update.Entity; 4220 // Don't send updates for objects that have been marked deleted.
3994 4221 // Instead send another kill object, because the first one may have gotten
3995 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 4222 // into a race condition
3996 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 4223 if (part == grp.RootPart && !m_killRecord.Contains(grp.LocalId))
3997 // safety measure.
3998 //
3999 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
4000 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
4001 // updates and kills on different threads with different scheduling strategies, hence this protection.
4002 //
4003 // This doesn't appear to apply to child prims - a client will happily ignore these updates
4004 // after the root prim has been deleted.
4005 if (m_killRecord.Contains(part.LocalId))
4006 { 4224 {
4007 // m_log.WarnFormat( 4225 m_killRecord.Add(grp.LocalId);
4008 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 4226 maxUpdatesBytes -= 30;
4009 // part.LocalId, Name); 4227 }
4228 continue;
4229 }
4230
4231 if (grp.IsAttachment)
4232 { // Someone else's HUD, why are we getting these?
4233 if (grp.OwnerID != AgentId && grp.HasPrivateAttachmentPoint)
4234 continue;
4235 ScenePresence sp;
4236 // Owner is not in the sim, don't update it to
4237 // anyone
4238 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
4010 continue; 4239 continue;
4011 } 4240
4012 4241 List<SceneObjectGroup> atts = sp.GetAttachments();
4013 if (part.ParentGroup.IsAttachment && m_disableFacelights) 4242 bool found = false;
4243 foreach (SceneObjectGroup att in atts)
4014 { 4244 {
4015 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 4245 if (att == grp)
4016 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
4017 { 4246 {
4018 part.Shape.LightEntry = false; 4247 found = true;
4248 break;
4019 } 4249 }
4020 } 4250 }
4021 4251
4022 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 4252 // It's an attachment of a valid avatar, but
4023 { 4253 // doesn't seem to be attached, skip
4024 // Ensure that mesh has at least 8 valid faces 4254 if (!found)
4025 part.Shape.ProfileBegin = 12500; 4255 continue;
4026 part.Shape.ProfileEnd = 0; 4256
4027 part.Shape.ProfileHollow = 27500; 4257 // On vehicle crossing, the attachments are received
4028 } 4258 // while the avatar is still a child. Don't send
4029 } 4259 // updates here because the LocalId has not yet
4030 4260 // been updated and the viewer will derender the
4031 #region UpdateFlags to packet type conversion 4261 // attachments until the avatar becomes root.
4032 4262 if (sp.IsChildAgent)
4033 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; 4263 continue;
4034 4264
4035 bool canUseCompressed = true;
4036 bool canUseImproved = true;
4037
4038 // Compressed object updates only make sense for LL primitives
4039 if (!(update.Entity is SceneObjectPart))
4040 {
4041 canUseCompressed = false;
4042 }
4043
4044 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4045 {
4046 canUseCompressed = false;
4047 canUseImproved = false;
4048 } 4265 }
4049 else 4266
4267 if (grp.IsAttachment && m_disableFacelights)
4050 { 4268 {
4051 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 4269 if (grp.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
4052 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || 4270 grp.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
4053 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
4054 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4055 {
4056 canUseCompressed = false;
4057 }
4058
4059 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
4060 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
4061 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
4062 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
4063 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
4064 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
4065 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
4066 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
4067 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
4068 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
4069 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
4070 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
4071 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
4072 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4073 { 4271 {
4074 canUseImproved = false; 4272 part.Shape.LightEntry = false;
4075 } 4273 }
4076 } 4274 }
4077 4275
4078 #endregion UpdateFlags to packet type conversion 4276 if(doCulling && !grp.IsAttachment)
4079
4080 #region Block Construction
4081
4082 // TODO: Remove this once we can build compressed updates
4083 canUseCompressed = false;
4084
4085 if (!canUseImproved && !canUseCompressed)
4086 { 4277 {
4087 ObjectUpdatePacket.ObjectDataBlock updateBlock; 4278 if(GroupsNeedFullUpdate.Contains(grp))
4279 continue;
4088 4280
4089 if (update.Entity is ScenePresence) 4281 bool inview = false;
4090 { 4282 lock(GroupsInView)
4091 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity); 4283 inview = GroupsInView.Contains(grp);
4092 } 4284
4093 else 4285 if(!inview)
4094 { 4286 {
4095 SceneObjectPart part = (SceneObjectPart)update.Entity; 4287 float bradius = grp.GetBoundsRadius();
4096 updateBlock = CreatePrimUpdateBlock(part, AgentId); 4288 Vector3 partpos = grp.AbsolutePosition + grp.getBoundsCenter();
4097 4289// float dcam = (partpos - mycamera).LengthSquared();
4098 // If the part has become a private hud since the update was scheduled then we do not 4290 float dpos = (partpos - mypos).LengthSquared();
4099 // want to send it to other avatars. 4291// if(dcam < dpos)
4100 if (part.ParentGroup.IsAttachment 4292// dpos = dcam;
4101 && part.ParentGroup.HasPrivateAttachmentPoint 4293 dpos = (float)Math.Sqrt(dpos) - bradius;
4102 && part.ParentGroup.AttachedAvatar != AgentId) 4294 if(dpos > cullingrange)
4103 continue; 4295 continue;
4104 4296
4105 // If the part has since been deleted, then drop the update. In the case of attachments, 4297 GroupsNeedFullUpdate.Add(grp);
4106 // this is to avoid spurious updates to other viewers since post-processing of attachments 4298 continue;
4107 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4108 // of the test above).
4109 //
4110 // Actual deletions (kills) happen in another method.
4111 if (part.ParentGroup.IsDeleted)
4112 continue;
4113 } 4299 }
4300 }
4301 }
4302 else if (update.Entity is ScenePresence)
4303 {
4304 ScenePresence presence = (ScenePresence)update.Entity;
4305 if (presence.IsDeleted)
4306 continue;
4307 // If ParentUUID is not UUID.Zero and ParentID is 0, this
4308 // avatar is in the process of crossing regions while
4309 // sat on an object. In this state, we don't want any
4310 // updates because they will visually orbit the avatar.
4311 // Update will be forced once crossing is completed anyway.
4312 if (presence.ParentUUID != UUID.Zero && presence.ParentID == 0)
4313 continue;
4314 }
4315
4316 #region UpdateFlags to packet type conversion
4317
4318 bool canUseCompressed = true;
4319 bool canUseImproved = true;
4320
4321
4322 // Compressed object updates only make sense for LL primitives
4323 if (!(update.Entity is SceneObjectPart))
4324 {
4325 canUseCompressed = false;
4326 }
4114 4327
4115 objectUpdateBlocks.Value.Add(updateBlock); 4328 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4116 objectUpdates.Value.Add(update); 4329 {
4330 canUseCompressed = false;
4331 canUseImproved = false;
4332 }
4333 else
4334 {
4335 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
4336 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
4337 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
4338 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4339 {
4340 canUseCompressed = false;
4117 } 4341 }
4118 else if (!canUseImproved) 4342
4343 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
4344 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
4345 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
4346 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
4347 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
4348 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
4349 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
4350 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
4351 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
4352 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
4353 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
4354 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
4355 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
4356 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4119 { 4357 {
4120 SceneObjectPart part = (SceneObjectPart)update.Entity; 4358 canUseImproved = false;
4121 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock 4359 }
4122 = CreateCompressedUpdateBlock(part, updateFlags); 4360 }
4123 4361
4124 // If the part has since been deleted, then drop the update. In the case of attachments, 4362 #endregion UpdateFlags to packet type conversion
4125 // this is to avoid spurious updates to other viewers since post-processing of attachments
4126 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4127 // of the test above).
4128 //
4129 // Actual deletions (kills) happen in another method.
4130 if (part.ParentGroup.IsDeleted)
4131 continue;
4132 4363
4133 compressedUpdateBlocks.Value.Add(compressedBlock); 4364 #region Block Construction
4134 compressedUpdates.Value.Add(update); 4365
4366 // TODO: Remove this once we can build compressed updates
4367 canUseCompressed = false;
4368
4369 if (!canUseImproved && !canUseCompressed)
4370 {
4371 ObjectUpdatePacket.ObjectDataBlock ablock;
4372 if (update.Entity is ScenePresence)
4373 ablock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
4374 else
4375 ablock = CreatePrimUpdateBlock((SceneObjectPart)update.Entity, mysp);
4376 objectUpdateBlocks.Add(ablock);
4377 objectUpdates.Value.Add(update);
4378 maxUpdatesBytes -= ablock.Length;
4379
4380 }
4381 else if (!canUseImproved)
4382 {
4383 ObjectUpdateCompressedPacket.ObjectDataBlock ablock =
4384 CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags);
4385 compressedUpdateBlocks.Add(ablock);
4386 compressedUpdates.Value.Add(update);
4387 maxUpdatesBytes -= ablock.Length;
4388 }
4389 else
4390 {
4391 ImprovedTerseObjectUpdatePacket.ObjectDataBlock ablock;
4392 if (update.Entity is ScenePresence)
4393 {
4394 // ALL presence updates go into a special list
4395 ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4396 terseAgentUpdateBlocks.Add(ablock);
4397 terseAgentUpdates.Value.Add(update);
4135 } 4398 }
4136 else 4399 else
4137 { 4400 {
4138 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4401 // Everything else goes here
4139 { 4402 ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4140 // Self updates go into a special list 4403 terseUpdateBlocks.Add(ablock);
4141 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 4404 terseUpdates.Value.Add(update);
4142 terseAgentUpdates.Value.Add(update); 4405 }
4143 } 4406 maxUpdatesBytes -= ablock.Length;
4144 else 4407 }
4145 {
4146 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
4147 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
4148 4408
4149 // Everything else goes here 4409 #endregion Block Construction
4150 if (update.Entity is SceneObjectPart) 4410 }
4151 {
4152 SceneObjectPart part = (SceneObjectPart)update.Entity;
4153
4154 // If the part has become a private hud since the update was scheduled then we do not
4155 // want to send it to other avatars.
4156 if (part.ParentGroup.IsAttachment
4157 && part.ParentGroup.HasPrivateAttachmentPoint
4158 && part.ParentGroup.AttachedAvatar != AgentId)
4159 continue;
4160
4161 // If the part has since been deleted, then drop the update. In the case of attachments,
4162 // this is to avoid spurious updates to other viewers since post-processing of attachments
4163 // has to change the IsAttachment flag for various reasons (which will end up in a pass
4164 // of the test above).
4165 //
4166 // Actual deletions (kills) happen in another method.
4167 if (part.ParentGroup.IsDeleted)
4168 continue;
4169 }
4170 4411
4171 terseUpdateBlocks.Value.Add(terseUpdateBlock); 4412 #region Packet Sending
4172 terseUpdates.Value.Add(update);
4173 }
4174 }
4175 4413
4176 ++updatesThisCall; 4414 ushort timeDilation;
4177
4178 #endregion Block Construction
4179 }
4180
4181 #region Packet Sending
4182 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4183 4415
4184 if (terseAgentUpdateBlocks.IsValueCreated) 4416 if(!IsActive)
4185 { 4417 return;
4186 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4418
4419 timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
4187 4420
4188 ImprovedTerseObjectUpdatePacket packet 4421 if (terseAgentUpdateBlocks.Count > 0)
4189 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4422 {
4423 ImprovedTerseObjectUpdatePacket packet
4424 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4425 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4426 packet.RegionData.TimeDilation = timeDilation;
4427 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseAgentUpdateBlocks.Count];
4190 4428
4191 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4429 for (int i = 0; i < terseAgentUpdateBlocks.Count; i++)
4192 packet.RegionData.TimeDilation = timeDilation; 4430 packet.ObjectData[i] = terseAgentUpdateBlocks[i];
4193 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4194 4431
4195 for (int i = 0; i < blocks.Count; i++) 4432 terseAgentUpdateBlocks.Clear();
4196 packet.ObjectData[i] = blocks[i]; 4433
4197 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4434 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); });
4198 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4435 }
4199 } 4436
4437 if (objectUpdateBlocks.Count > 0)
4438 {
4439 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4440 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4441 packet.RegionData.TimeDilation = timeDilation;
4442 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[objectUpdateBlocks.Count];
4443
4444 for (int i = 0; i < objectUpdateBlocks.Count; i++)
4445 packet.ObjectData[i] = objectUpdateBlocks[i];
4446
4447 objectUpdateBlocks.Clear();
4448
4449 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4450 }
4451
4452 if (compressedUpdateBlocks.Count > 0)
4453 {
4454 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4455 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4456 packet.RegionData.TimeDilation = timeDilation;
4457 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[compressedUpdateBlocks.Count];
4458
4459 for (int i = 0; i < compressedUpdateBlocks.Count; i++)
4460 packet.ObjectData[i] = compressedUpdateBlocks[i];
4461
4462 compressedUpdateBlocks.Clear();
4200 4463
4201 if (objectUpdateBlocks.IsValueCreated) 4464 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4465 }
4466
4467 if (terseUpdateBlocks.Count > 0)
4468 {
4469 ImprovedTerseObjectUpdatePacket packet
4470 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4471 PacketType.ImprovedTerseObjectUpdate);
4472 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4473 packet.RegionData.TimeDilation = timeDilation;
4474 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseUpdateBlocks.Count];
4475
4476 for (int i = 0; i < terseUpdateBlocks.Count; i++)
4477 packet.ObjectData[i] = terseUpdateBlocks[i];
4478
4479 terseUpdateBlocks.Clear();
4480
4481 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4482 }
4483
4484 #endregion Packet Sending
4485
4486 #region Handle deleted objects
4487 if (m_killRecord.Count > 0)
4488 {
4489 SendKillObject(m_killRecord);
4490 m_killRecord.Clear();
4491 }
4492
4493 if(GroupsNeedFullUpdate.Count > 0)
4494 {
4495 foreach(SceneObjectGroup grp in GroupsNeedFullUpdate)
4202 { 4496 {
4203 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 4497 foreach(SceneObjectPart p in grp.Parts)
4204 4498 SendEntityUpdate(p,PrimUpdateFlags.CancelKill);
4205 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 4499 lock(GroupsInView)
4206 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4500 GroupsInView.Add(grp);
4207 packet.RegionData.TimeDilation = timeDilation;
4208 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4209
4210 for (int i = 0; i < blocks.Count; i++)
4211 packet.ObjectData[i] = blocks[i];
4212 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4213 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4214 } 4501 }
4215 4502 }
4216 if (compressedUpdateBlocks.IsValueCreated) 4503 #endregion
4504 }
4505
4506 // hack.. dont use
4507/*
4508 public void SendPartFullUpdate(ISceneEntity ent, uint? parentID)
4509 {
4510 if (ent is SceneObjectPart)
4511 {
4512 SceneObjectPart part = (SceneObjectPart)ent;
4513 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4514 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4515 packet.RegionData.TimeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
4516 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
4517
4518 ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, mysp);
4519 if (parentID.HasValue)
4217 { 4520 {
4218 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; 4521 blk.ParentID = parentID.Value;
4219
4220 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4221 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4222 packet.RegionData.TimeDilation = timeDilation;
4223 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4224
4225 for (int i = 0; i < blocks.Count; i++)
4226 packet.ObjectData[i] = blocks[i];
4227 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4228 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4229 } 4522 }
4230 4523
4231 if (terseUpdateBlocks.IsValueCreated) 4524 packet.ObjectData[0] = blk;
4232 {
4233 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4234
4235 ImprovedTerseObjectUpdatePacket packet
4236 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4237 PacketType.ImprovedTerseObjectUpdate);
4238 4525
4239 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4526 OutPacket(packet, ThrottleOutPacketType.Task, true);
4240 packet.RegionData.TimeDilation = timeDilation;
4241 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4242
4243 for (int i = 0; i < blocks.Count; i++)
4244 packet.ObjectData[i] = blocks[i];
4245 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4246 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4247 }
4248 } 4527 }
4249 4528
4250// m_log.DebugFormat( 4529// m_log.DebugFormat(
4251// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}", 4530// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}",
4252// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name); 4531// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name);
4253// 4532//
4254 #endregion Packet Sending
4255 } 4533 }
4256 4534*/
4257 public void ReprioritizeUpdates() 4535 public void ReprioritizeUpdates()
4258 { 4536 {
4259 lock (m_entityUpdates.SyncRoot) 4537 lock (m_entityUpdates.SyncRoot)
4260 m_entityUpdates.Reprioritize(UpdatePriorityHandler); 4538 m_entityUpdates.Reprioritize(UpdatePriorityHandler);
4539 CheckGroupsInView();
4540 }
4541
4542 private bool CheckGroupsInViewBusy = false;
4543
4544 public void CheckGroupsInView()
4545 {
4546 bool doCulling = m_scene.ObjectsCullingByDistance;
4547 if(!doCulling)
4548 return;
4549
4550 if(CheckGroupsInViewBusy)
4551 return;
4552
4553 CheckGroupsInViewBusy = true;
4554
4555 float cullingrange = 64.0f;
4556// Vector3 mycamera = Vector3.Zero;
4557 Vector3 mypos = Vector3.Zero;
4558 ScenePresence mysp = (ScenePresence)SceneAgent;
4559 if(mysp != null && !mysp.IsDeleted)
4560 {
4561 cullingrange = mysp.DrawDistance + m_scene.ReprioritizationDistance + 16f;
4562// mycamera = mysp.CameraPosition;
4563 mypos = mysp.AbsolutePosition;
4564 }
4565 else
4566 {
4567 CheckGroupsInViewBusy= false;
4568 return;
4569 }
4570
4571 HashSet<SceneObjectGroup> NewGroupsInView = new HashSet<SceneObjectGroup>();
4572 HashSet<SceneObjectGroup> GroupsNeedFullUpdate = new HashSet<SceneObjectGroup>();
4573 List<SceneObjectGroup> kills = new List<SceneObjectGroup>();
4574
4575 EntityBase[] entities = m_scene.Entities.GetEntities();
4576 foreach (EntityBase e in entities)
4577 {
4578 if(!IsActive)
4579 return;
4580
4581 if (e != null && e is SceneObjectGroup)
4582 {
4583 SceneObjectGroup grp = (SceneObjectGroup)e;
4584 if(grp.IsDeleted || grp.IsAttachment)
4585 continue;
4586
4587 float bradius = grp.GetBoundsRadius();
4588 Vector3 grppos = grp.AbsolutePosition + grp.getBoundsCenter();
4589// float dcam = (grppos - mycamera).LengthSquared();
4590 float dpos = (grppos - mypos).LengthSquared();
4591// if(dcam < dpos)
4592// dpos = dcam;
4593
4594 dpos = (float)Math.Sqrt(dpos) - bradius;
4595
4596 bool inview;
4597 lock(GroupsInView)
4598 inview = GroupsInView.Contains(grp);
4599
4600 if(dpos > cullingrange)
4601 {
4602 if(inview)
4603 kills.Add(grp);
4604 }
4605 else
4606 {
4607 if(!inview)
4608 GroupsNeedFullUpdate.Add(grp);
4609 NewGroupsInView.Add(grp);
4610 }
4611 }
4612 }
4613
4614 lock(GroupsInView)
4615 GroupsInView = NewGroupsInView;
4616
4617 if (kills.Count > 0)
4618 {
4619 List<uint> partIDs = new List<uint>();
4620 foreach(SceneObjectGroup grp in kills)
4621 {
4622 SendEntityUpdate(grp.RootPart,PrimUpdateFlags.Kill);
4623 foreach(SceneObjectPart p in grp.Parts)
4624 {
4625 if(p != grp.RootPart)
4626 partIDs.Add(p.LocalId);
4627 }
4628 }
4629 kills.Clear();
4630 if(partIDs.Count > 0)
4631 {
4632 lock (m_entityProps.SyncRoot)
4633 m_entityProps.Remove(partIDs);
4634 lock (m_entityUpdates.SyncRoot)
4635 m_entityUpdates.Remove(partIDs);
4636 }
4637 }
4638
4639 if(GroupsNeedFullUpdate.Count > 0)
4640 {
4641 foreach(SceneObjectGroup grp in GroupsNeedFullUpdate)
4642 {
4643 foreach(SceneObjectPart p in grp.Parts)
4644 SendEntityUpdate(p,PrimUpdateFlags.CancelKill);
4645 }
4646 }
4647
4648 CheckGroupsInViewBusy = false;
4261 } 4649 }
4262 4650
4263 private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity) 4651 private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity)
@@ -4285,63 +4673,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4285 // of updates converted to packets. Since we don't want packets 4673 // of updates converted to packets. Since we don't want packets
4286 // to sit in the queue with old data, only convert enough updates 4674 // to sit in the queue with old data, only convert enough updates
4287 // to packets that can be sent in 200ms. 4675 // to packets that can be sent in 200ms.
4288 private Int32 m_LastQueueFill = 0; 4676// private Int32 m_LastQueueFill = 0;
4289 private Int32 m_maxUpdates = 0; 4677// private Int32 m_maxUpdates = 0;
4290 4678
4291 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) 4679 void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
4292 { 4680 {
4293// if (!m_udpServer.IsRunningOutbound) 4681 if(m_scene == null)
4294// return; 4682 return;
4295 4683
4296 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4684 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4297 { 4685 {
4298// if (!m_udpServer.IsRunningOutbound) 4686 int maxUpdateBytes = m_udpClient.GetCatBytesCanSend(ThrottleOutPacketType.Task, 30);
4299// return;
4300 4687
4301 if (m_maxUpdates == 0 || m_LastQueueFill == 0)
4302 {
4303 m_maxUpdates = m_udpServer.PrimUpdatesPerCallback;
4304 }
4305 else
4306 {
4307 if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
4308 m_maxUpdates += 5;
4309 else
4310 m_maxUpdates = m_maxUpdates >> 1;
4311 }
4312 m_maxUpdates = Util.Clamp<Int32>(m_maxUpdates,10,500);
4313 m_LastQueueFill = Util.EnvironmentTickCount();
4314
4315 if (m_entityUpdates.Count > 0) 4688 if (m_entityUpdates.Count > 0)
4316 ProcessEntityUpdates(m_maxUpdates); 4689 ProcessEntityUpdates(maxUpdateBytes);
4317 4690
4318 if (m_entityProps.Count > 0) 4691 if (m_entityProps.Count > 0)
4319 ProcessEntityPropertyRequests(m_maxUpdates); 4692 ProcessEntityPropertyRequests(maxUpdateBytes);
4320 } 4693 }
4321 4694
4322 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) 4695 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4323 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); 4696 ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit);
4324 } 4697 }
4325 4698
4326 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories) 4699 internal bool HandleHasUpdates(ThrottleOutPacketTypeFlags categories)
4327 { 4700 {
4328 bool hasUpdates = false;
4329
4330 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) 4701 if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
4331 { 4702 {
4332 if (m_entityUpdates.Count > 0) 4703 if (m_entityUpdates.Count > 0)
4333 hasUpdates = true; 4704 return true;
4334 else if (m_entityProps.Count > 0) 4705 if (m_entityProps.Count > 0)
4335 hasUpdates = true; 4706 return true;
4336 } 4707 }
4337 4708
4338 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) 4709 if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0)
4339 { 4710 {
4340 if (ImageManager.HasUpdates()) 4711 if (ImageManager.HasUpdates())
4341 hasUpdates = true; 4712 return true;
4342 } 4713 }
4343 4714
4344 return hasUpdates; 4715 return false;
4345 } 4716 }
4346 4717
4347 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) 4718 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID)
@@ -4443,13 +4814,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4443 OutPacket(pack, ThrottleOutPacketType.Task); 4814 OutPacket(pack, ThrottleOutPacketType.Task);
4444 } 4815 }
4445 4816
4446 private class ObjectPropertyUpdate : IEntityUpdate 4817 private class ObjectPropertyUpdate : EntityUpdate
4447 { 4818 {
4448 internal bool SendFamilyProps; 4819 internal bool SendFamilyProps;
4449 internal bool SendObjectProps; 4820 internal bool SendObjectProps;
4450 4821
4451 public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) 4822 public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj)
4452 : base(entity,flags) 4823 : base(entity,(PrimUpdateFlags)flags)
4453 { 4824 {
4454 SendFamilyProps = sendfam; 4825 SendFamilyProps = sendfam;
4455 SendObjectProps = sendobj; 4826 SendObjectProps = sendobj;
@@ -4462,7 +4833,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4462 base.Update(update); 4833 base.Update(update);
4463 } 4834 }
4464 } 4835 }
4465 4836
4466 public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) 4837 public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags)
4467 { 4838 {
4468 uint priority = 0; // time based ordering only 4839 uint priority = 0; // time based ordering only
@@ -4496,7 +4867,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4496 foreach (ObjectPropertyUpdate update in updates) 4867 foreach (ObjectPropertyUpdate update in updates)
4497 ResendPropertyUpdate(update); 4868 ResendPropertyUpdate(update);
4498 } 4869 }
4499 4870
4500 public void SendObjectPropertiesReply(ISceneEntity entity) 4871 public void SendObjectPropertiesReply(ISceneEntity entity)
4501 { 4872 {
4502 uint priority = 0; // time based ordering only 4873 uint priority = 0; // time based ordering only
@@ -4504,29 +4875,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4504 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); 4875 m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true));
4505 } 4876 }
4506 4877
4507 private void ProcessEntityPropertyRequests(int maxUpdates) 4878 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> objectFamilyBlocks = new
4879 List<ObjectPropertiesFamilyPacket.ObjectDataBlock>();
4880 List<ObjectPropertiesPacket.ObjectDataBlock> objectPropertiesBlocks =
4881 new List<ObjectPropertiesPacket.ObjectDataBlock>();
4882 List<SceneObjectPart> needPhysics = new List<SceneObjectPart>();
4883
4884 private void ProcessEntityPropertyRequests(int maxUpdateBytes)
4508 { 4885 {
4509 OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>> objectFamilyBlocks = 4886// OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates =
4510 new OpenSim.Framework.Lazy<List<ObjectPropertiesFamilyPacket.ObjectDataBlock>>(); 4887// new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4511 4888
4512 OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = 4889// OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates =
4513 new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); 4890// new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4514 4891
4515 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates = 4892 bool orderedDequeue = m_scene.UpdatePrioritizationScheme == UpdatePrioritizationSchemes.SimpleAngularDistance;
4516 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4517 4893
4518 OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates = 4894 EntityUpdate iupdate;
4519 new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>();
4520
4521 IEntityUpdate iupdate;
4522 Int32 timeinqueue; // this is just debugging code & can be dropped later 4895 Int32 timeinqueue; // this is just debugging code & can be dropped later
4523 4896
4524 int updatesThisCall = 0; 4897 while (maxUpdateBytes > 0)
4525 while (updatesThisCall < m_maxUpdates)
4526 { 4898 {
4527 lock (m_entityProps.SyncRoot) 4899 lock (m_entityProps.SyncRoot)
4528 if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) 4900 {
4529 break; 4901 if(orderedDequeue)
4902 {
4903 if (!m_entityProps.TryOrderedDequeue(out iupdate, out timeinqueue))
4904 break;
4905 }
4906 else
4907 {
4908 if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue))
4909 break;
4910 }
4911 }
4530 4912
4531 ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; 4913 ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate;
4532 if (update.SendFamilyProps) 4914 if (update.SendFamilyProps)
@@ -4535,8 +4917,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4535 { 4917 {
4536 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4918 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4537 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); 4919 ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
4538 objectFamilyBlocks.Value.Add(objPropDB); 4920 objectFamilyBlocks.Add(objPropDB);
4539 familyUpdates.Value.Add(update); 4921// familyUpdates.Value.Add(update);
4922 maxUpdateBytes -= objPropDB.Length;
4540 } 4923 }
4541 } 4924 }
4542 4925
@@ -4545,84 +4928,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4545 if (update.Entity is SceneObjectPart) 4928 if (update.Entity is SceneObjectPart)
4546 { 4929 {
4547 SceneObjectPart sop = (SceneObjectPart)update.Entity; 4930 SceneObjectPart sop = (SceneObjectPart)update.Entity;
4931 needPhysics.Add(sop);
4548 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); 4932 ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
4549 objectPropertiesBlocks.Value.Add(objPropDB); 4933 objectPropertiesBlocks.Add(objPropDB);
4550 propertyUpdates.Value.Add(update); 4934// propertyUpdates.Value.Add(update);
4935 maxUpdateBytes -= objPropDB.Length;
4551 } 4936 }
4552 } 4937 }
4553
4554 updatesThisCall++;
4555 } 4938 }
4556
4557 4939
4558 // Int32 ppcnt = 0; 4940 if (objectPropertiesBlocks.Count > 0)
4559 // Int32 pbcnt = 0;
4560
4561 if (objectPropertiesBlocks.IsValueCreated)
4562 { 4941 {
4563 List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value;
4564 List<ObjectPropertyUpdate> updates = propertyUpdates.Value;
4565
4566 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 4942 ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
4567 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; 4943 packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count];
4568 for (int i = 0; i < blocks.Count; i++) 4944 for (int i = 0; i < objectPropertiesBlocks.Count; i++)
4569 packet.ObjectData[i] = blocks[i]; 4945 packet.ObjectData[i] = objectPropertiesBlocks[i];
4570 4946
4947
4948 objectPropertiesBlocks.Clear();
4571 packet.Header.Zerocoded = true; 4949 packet.Header.Zerocoded = true;
4572 4950
4573 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4951 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4574 // of the object rather than the properties when the packet was created 4952 // of the object rather than the properties when the packet was created
4575 OutPacket(packet, ThrottleOutPacketType.Task, true, 4953 // HACK : Remove intelligent resending until it's fixed in core
4576 delegate(OutgoingPacket oPacket) 4954 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4577 { 4955 // delegate(OutgoingPacket oPacket)
4578 ResendPropertyUpdates(updates, oPacket); 4956 // {
4579 }); 4957 // ResendPropertyUpdates(propertyUpdates.Value, oPacket);
4958 // });
4959 OutPacket(packet, ThrottleOutPacketType.Task, true);
4580 4960
4581 // pbcnt += blocks.Count; 4961 // pbcnt += blocks.Count;
4582 // ppcnt++; 4962 // ppcnt++;
4583 } 4963 }
4584 4964
4585 // Int32 fpcnt = 0; 4965 // Int32 fpcnt = 0;
4586 // Int32 fbcnt = 0; 4966 // Int32 fbcnt = 0;
4587 4967
4588 if (objectFamilyBlocks.IsValueCreated) 4968 if (objectFamilyBlocks.Count > 0)
4589 { 4969 {
4590 List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value;
4591
4592 // one packet per object block... uggh... 4970 // one packet per object block... uggh...
4593 for (int i = 0; i < blocks.Count; i++) 4971 for (int i = 0; i < objectFamilyBlocks.Count; i++)
4594 { 4972 {
4595 ObjectPropertiesFamilyPacket packet = 4973 ObjectPropertiesFamilyPacket packet =
4596 (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); 4974 (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
4597 4975
4598 packet.ObjectData = blocks[i]; 4976 packet.ObjectData = objectFamilyBlocks[i];
4599 packet.Header.Zerocoded = true; 4977 packet.Header.Zerocoded = true;
4600 4978
4601 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4979 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4602 // of the object rather than the properties when the packet was created 4980 // of the object rather than the properties when the packet was created
4603 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4981// List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4604 updates.Add(familyUpdates.Value[i]); 4982// updates.Add(familyUpdates.Value[i]);
4605 OutPacket(packet, ThrottleOutPacketType.Task, true, 4983 // HACK : Remove intelligent resending until it's fixed in core
4606 delegate(OutgoingPacket oPacket) 4984 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4607 { 4985 // delegate(OutgoingPacket oPacket)
4608 ResendPropertyUpdates(updates, oPacket); 4986 // {
4609 }); 4987 // ResendPropertyUpdates(updates, oPacket);
4988 // });
4989 OutPacket(packet, ThrottleOutPacketType.Task, true);
4610 4990
4611 // fpcnt++; 4991 // fpcnt++;
4612 // fbcnt++; 4992 // fbcnt++;
4613 } 4993 }
4614 4994 objectFamilyBlocks.Clear();
4995 }
4996
4997 if(needPhysics.Count > 0)
4998 {
4999 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
5000 if(eq != null)
5001 {
5002 OSDArray array = new OSDArray();
5003 foreach(SceneObjectPart sop in needPhysics)
5004 {
5005 OSDMap physinfo = new OSDMap(6);
5006 physinfo["LocalID"] = sop.LocalId;
5007 physinfo["Density"] = sop.Density;
5008 physinfo["Friction"] = sop.Friction;
5009 physinfo["GravityMultiplier"] = sop.GravityModifier;
5010 physinfo["Restitution"] = sop.Restitution;
5011 physinfo["PhysicsShapeType"] = (int)sop.PhysicsShapeType;
5012 array.Add(physinfo);
5013 }
5014
5015 OSDMap llsdBody = new OSDMap(1);
5016 llsdBody.Add("ObjectData", array);
5017
5018 eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId);
5019 }
5020 needPhysics.Clear();
4615 } 5021 }
4616 5022
4617 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); 5023 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt);
4618 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); 5024 // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt);
4619 } 5025 }
4620 5026
4621 private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) 5027 private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, PrimUpdateFlags requestFlags)
4622 { 5028 {
4623 ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); 5029 ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock();
4624 5030
4625 block.RequestFlags = requestFlags; 5031 block.RequestFlags = (uint)requestFlags;
4626 block.ObjectID = sop.UUID; 5032 block.ObjectID = sop.UUID;
4627 if (sop.OwnerID == sop.GroupID) 5033 if (sop.OwnerID == sop.GroupID)
4628 block.OwnerID = UUID.Zero; 5034 block.OwnerID = UUID.Zero;
@@ -4640,13 +5046,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4640 block.SaleType = sop.ObjectSaleType; 5046 block.SaleType = sop.ObjectSaleType;
4641 block.SalePrice = sop.SalePrice; 5047 block.SalePrice = sop.SalePrice;
4642 block.Category = sop.Category; 5048 block.Category = sop.Category;
4643 block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? 5049 block.LastOwnerID = sop.LastOwnerID;
4644 block.Name = Util.StringToBytes256(sop.Name); 5050 block.Name = Util.StringToBytes256(sop.Name);
4645 block.Description = Util.StringToBytes256(sop.Description); 5051 block.Description = Util.StringToBytes256(sop.Description);
4646 5052
4647 return block; 5053 return block;
4648 } 5054 }
4649 5055
4650 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) 5056 private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop)
4651 { 5057 {
4652 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); 5058 //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
@@ -4672,7 +5078,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4672 block.FolderID = UUID.Zero; // sog.FromFolderID ?? 5078 block.FolderID = UUID.Zero; // sog.FromFolderID ??
4673 block.FromTaskID = UUID.Zero; // ??? 5079 block.FromTaskID = UUID.Zero; // ???
4674 block.InventorySerial = (short)sop.InventorySerial; 5080 block.InventorySerial = (short)sop.InventorySerial;
4675 5081
4676 SceneObjectPart root = sop.ParentGroup.RootPart; 5082 SceneObjectPart root = sop.ParentGroup.RootPart;
4677 5083
4678 block.TouchName = Util.StringToBytes256(root.TouchName); 5084 block.TouchName = Util.StringToBytes256(root.TouchName);
@@ -4684,7 +5090,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4684// { 5090// {
4685// using (BinaryWriter binWriter = new BinaryWriter(memStream)) 5091// using (BinaryWriter binWriter = new BinaryWriter(memStream))
4686// { 5092// {
4687// for (int i = 0; i < sop.GetNumberOfSides(); i++) 5093// for (int i = 0; i < sop.GetNumberOfSides(); i++)
4688// { 5094// {
4689// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i]; 5095// Primitive.TextureEntryFace teFace = sop.Shape.Textures.FaceTextures[i];
4690// 5096//
@@ -4701,7 +5107,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4701// block.TextureID = memStream.ToArray(); 5107// block.TextureID = memStream.ToArray();
4702// } 5108// }
4703// } 5109// }
4704 5110
4705 block.TextureID = new byte[0]; // TextureID ??? 5111 block.TextureID = new byte[0]; // TextureID ???
4706 block.SitName = Util.StringToBytes256(root.SitName); 5112 block.SitName = Util.StringToBytes256(root.SitName);
4707 block.OwnerMask = root.OwnerMask; 5113 block.OwnerMask = root.OwnerMask;
@@ -4728,52 +5134,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4728 } 5134 }
4729 5135
4730 public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID) 5136 public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID)
4731
4732 { 5137 {
4733 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); 5138 int TotalnumberIDs = Data.Length;
4734 packet.AgentData.TransactionID = UUID.Random(); 5139 int numberIDs;
4735 packet.AgentData.AgentID = AgentId; 5140 int IDIndex = 0;
4736 packet.AgentData.SessionID = SessionId;
4737 packet.MethodData.Invoice = invoice;
4738 packet.MethodData.Method = Utils.StringToBytes("setaccess");
4739 5141
4740 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + Data.Length]; 5142 do
4741
4742 for (int i = 0; i < (6 + Data.Length); i++)
4743 { 5143 {
4744 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); 5144 if(TotalnumberIDs > 63)
4745 } 5145 numberIDs = 63;
4746 int j = 0; 5146 else
5147 numberIDs = TotalnumberIDs;
4747 5148
4748 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; 5149 TotalnumberIDs -= numberIDs;
4749 returnblock[j].Parameter = Utils.StringToBytes(code.ToString()); j++;
4750 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4751 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4752 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4753 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4754 5150
4755 j = 2; // Agents 5151 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4756 if ((code & 2) != 0) 5152 packet.AgentData.TransactionID = UUID.Random();
4757 j = 3; // Groups 5153 packet.AgentData.AgentID = AgentId;
4758 if ((code & 8) != 0) 5154 packet.AgentData.SessionID = SessionId;
4759 j = 5; // Managers 5155 packet.MethodData.Invoice = invoice;
5156 packet.MethodData.Method = Utils.StringToBytes("setaccess");
4760 5157
4761 returnblock[j].Parameter = Utils.StringToBytes(Data.Length.ToString()); 5158 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + numberIDs];
4762 j = 6;
4763 5159
4764 for (int i = 0; i < Data.Length; i++) 5160 for (int i = 0; i < (6 + numberIDs); i++)
4765 { 5161 {
4766 returnblock[j].Parameter = Data[i].GetBytes(); j++; 5162 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock();
4767 } 5163 }
4768 packet.ParamList = returnblock; 5164
4769 packet.Header.Reliable = true; 5165 returnblock[0].Parameter = Utils.StringToBytes(estateID.ToString());
4770 OutPacket(packet, ThrottleOutPacketType.Task); 5166 returnblock[1].Parameter = Utils.StringToBytes(code.ToString());
5167
5168 if((code & 1) != 0) // allowagents
5169 returnblock[2].Parameter = Utils.StringToBytes(numberIDs.ToString());
5170 else
5171 returnblock[2].Parameter = Utils.StringToBytes("0");
5172
5173 if((code & 2) != 0) // groups
5174 returnblock[3].Parameter = Utils.StringToBytes(numberIDs.ToString());
5175 else
5176 returnblock[3].Parameter = Utils.StringToBytes("0");
5177
5178 if((code & 4) != 0) // bans
5179 returnblock[4].Parameter = Utils.StringToBytes(numberIDs.ToString());
5180 else
5181 returnblock[4].Parameter = Utils.StringToBytes("0");
5182
5183 if((code & 8) != 0) // managers
5184 returnblock[5].Parameter = Utils.StringToBytes(numberIDs.ToString());
5185 else
5186 returnblock[5].Parameter = Utils.StringToBytes("0");
5187
5188 int j = 6;
5189
5190 for (int i = 0; i < numberIDs; i++)
5191 {
5192 returnblock[j].Parameter = Data[IDIndex].GetBytes();
5193 j++;
5194 IDIndex++;
5195 }
5196 packet.ParamList = returnblock;
5197 packet.Header.Reliable = true;
5198 OutPacket(packet, ThrottleOutPacketType.Task);
5199 } while (TotalnumberIDs > 0);
4771 } 5200 }
4772 5201
4773 public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID) 5202 public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID)
4774 { 5203 {
4775 List<UUID> BannedUsers = new List<UUID>(); 5204 List<UUID> BannedUsers = new List<UUID>();
4776
4777 for (int i = 0; i < bl.Length; i++) 5205 for (int i = 0; i < bl.Length; i++)
4778 { 5206 {
4779 if (bl[i] == null) 5207 if (bl[i] == null)
@@ -4781,44 +5209,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4781 if (bl[i].BannedUserID == UUID.Zero) 5209 if (bl[i].BannedUserID == UUID.Zero)
4782 continue; 5210 continue;
4783 BannedUsers.Add(bl[i].BannedUserID); 5211 BannedUsers.Add(bl[i].BannedUserID);
4784
4785 if (BannedUsers.Count >= 50 || (i == (bl.Length - 1) && BannedUsers.Count > 0))
4786 {
4787 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4788 packet.AgentData.TransactionID = UUID.Random();
4789 packet.AgentData.AgentID = AgentId;
4790 packet.AgentData.SessionID = SessionId;
4791 packet.MethodData.Invoice = invoice;
4792 packet.MethodData.Method = Utils.StringToBytes("setaccess");
4793
4794 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count];
4795
4796 int j;
4797 for (j = 0; j < (6 + BannedUsers.Count); j++)
4798 {
4799 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
4800 }
4801 j = 0;
4802
4803 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4804 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
4805 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4806 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4807 returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++;
4808 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4809
4810 foreach (UUID banned in BannedUsers)
4811 {
4812 returnblock[j].Parameter = banned.GetBytes(); j++;
4813 }
4814 packet.ParamList = returnblock;
4815 packet.Header.Reliable = true;
4816 OutPacket(packet, ThrottleOutPacketType.Task);
4817
4818 BannedUsers.Clear();
4819 }
4820 } 5212 }
4821 5213 SendEstateList(invoice, 4, BannedUsers.ToArray(), estateID);
4822 } 5214 }
4823 5215
4824 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) 5216 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
@@ -4864,7 +5256,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4864 public void SendEstateCovenantInformation(UUID covenant) 5256 public void SendEstateCovenantInformation(UUID covenant)
4865 { 5257 {
4866// m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name); 5258// m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name);
4867 5259
4868 EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket(); 5260 EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket();
4869 EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock(); 5261 EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock();
4870 edata.CovenantID = covenant; 5262 edata.CovenantID = covenant;
@@ -4881,7 +5273,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4881 { 5273 {
4882// m_log.DebugFormat( 5274// m_log.DebugFormat(
4883// "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant); 5275// "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant);
4884 5276
4885 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); 5277 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4886 packet.MethodData.Invoice = invoice; 5278 packet.MethodData.Invoice = invoice;
4887 packet.AgentData.TransactionID = UUID.Random(); 5279 packet.AgentData.TransactionID = UUID.Random();
@@ -4939,17 +5331,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4939 packet.ParcelData.Data = data; 5331 packet.ParcelData.Data = data;
4940 packet.ParcelData.SequenceID = sequence_id; 5332 packet.ParcelData.SequenceID = sequence_id;
4941 packet.Header.Zerocoded = true; 5333 packet.Header.Zerocoded = true;
4942 OutPacket(packet, ThrottleOutPacketType.Task); 5334// OutPacket(packet, ThrottleOutPacketType.Task);
5335 OutPacket(packet, ThrottleOutPacketType.Land);
4943 } 5336 }
4944 5337
4945 public void SendLandProperties( 5338 public void SendLandProperties(
4946 int sequence_id, bool snap_selection, int request_result, ILandObject lo, 5339 int sequence_id, bool snap_selection, int request_result, ILandObject lo,
4947 float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) 5340 float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags)
4948 { 5341 {
4949// m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name); 5342// m_log.DebugFormat("[LLCLIENTVIEW]: Sending land properties for {0} to {1}", lo.LandData.GlobalID, Name);
4950 5343
4951 LandData landData = lo.LandData; 5344 LandData landData = lo.LandData;
4952 5345
4953 ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage(); 5346 ParcelPropertiesMessage updateMessage = new ParcelPropertiesMessage();
4954 5347
4955 updateMessage.AABBMax = landData.AABBMax; 5348 updateMessage.AABBMax = landData.AABBMax;
@@ -4962,7 +5355,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4962 updateMessage.Category = landData.Category; 5355 updateMessage.Category = landData.Category;
4963 updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate); 5356 updateMessage.ClaimDate = Util.ToDateTime(landData.ClaimDate);
4964 updateMessage.ClaimPrice = landData.ClaimPrice; 5357 updateMessage.ClaimPrice = landData.ClaimPrice;
4965 updateMessage.GroupID = landData.GroupID; 5358 updateMessage.GroupID = landData.GroupID;
4966 updateMessage.IsGroupOwned = landData.IsGroupOwned; 5359 updateMessage.IsGroupOwned = landData.IsGroupOwned;
4967 updateMessage.LandingType = (LandingType) landData.LandingType; 5360 updateMessage.LandingType = (LandingType) landData.LandingType;
4968 updateMessage.LocalID = landData.LocalID; 5361 updateMessage.LocalID = landData.LocalID;
@@ -4983,7 +5376,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4983 updateMessage.Name = landData.Name; 5376 updateMessage.Name = landData.Name;
4984 updateMessage.OtherCleanTime = landData.OtherCleanTime; 5377 updateMessage.OtherCleanTime = landData.OtherCleanTime;
4985 updateMessage.OtherCount = 0; //TODO: Unimplemented 5378 updateMessage.OtherCount = 0; //TODO: Unimplemented
4986 updateMessage.OwnerID = landData.OwnerID; 5379 updateMessage.OwnerID = landData.OwnerID;
4987 updateMessage.ParcelFlags = (ParcelFlags) landData.Flags; 5380 updateMessage.ParcelFlags = (ParcelFlags) landData.Flags;
4988 updateMessage.ParcelPrimBonus = simObjectBonusFactor; 5381 updateMessage.ParcelPrimBonus = simObjectBonusFactor;
4989 updateMessage.PassHours = landData.PassHours; 5382 updateMessage.PassHours = landData.PassHours;
@@ -4998,20 +5391,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4998 5391
4999 updateMessage.RentPrice = 0; 5392 updateMessage.RentPrice = 0;
5000 updateMessage.RequestResult = (ParcelResult) request_result; 5393 updateMessage.RequestResult = (ParcelResult) request_result;
5001 updateMessage.SalePrice = landData.SalePrice; 5394 updateMessage.SalePrice = landData.SalePrice;
5002 updateMessage.SelfCount = 0; //TODO: Unimplemented 5395 updateMessage.SelfCount = 0; //TODO: Unimplemented
5003 updateMessage.SequenceID = sequence_id; 5396 updateMessage.SequenceID = sequence_id;
5004 5397
5005 if (landData.SimwideArea > 0) 5398 if (landData.SimwideArea > 0)
5006 { 5399 {
5007 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 5400 updateMessage.SimWideMaxPrims = lo.GetSimulatorMaxPrimCount();
5008 updateMessage.SimWideMaxPrims = simulatorCapacity;
5009 } 5401 }
5010 else 5402 else
5011 { 5403 {
5012 updateMessage.SimWideMaxPrims = 0; 5404 updateMessage.SimWideMaxPrims = 0;
5013 } 5405 }
5014 5406
5015 updateMessage.SnapSelection = snap_selection; 5407 updateMessage.SnapSelection = snap_selection;
5016 updateMessage.SnapshotID = landData.SnapshotID; 5408 updateMessage.SnapshotID = landData.SnapshotID;
5017 updateMessage.Status = (ParcelStatus) landData.Status; 5409 updateMessage.Status = (ParcelStatus) landData.Status;
@@ -5025,23 +5417,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5025 updateMessage.MediaLoop = landData.MediaLoop; 5417 updateMessage.MediaLoop = landData.MediaLoop;
5026 updateMessage.ObscureMusic = landData.ObscureMusic; 5418 updateMessage.ObscureMusic = landData.ObscureMusic;
5027 updateMessage.ObscureMedia = landData.ObscureMedia; 5419 updateMessage.ObscureMedia = landData.ObscureMedia;
5028 5420
5421 updateMessage.SeeAVs = landData.SeeAVs;
5422 updateMessage.AnyAVSounds = landData.AnyAVSounds;
5423 updateMessage.GroupAVSounds = landData.GroupAVSounds;
5424
5029 IPrimCounts pc = lo.PrimCounts; 5425 IPrimCounts pc = lo.PrimCounts;
5030 updateMessage.OwnerPrims = pc.Owner; 5426 updateMessage.OwnerPrims = pc.Owner;
5031 updateMessage.GroupPrims = pc.Group; 5427 updateMessage.GroupPrims = pc.Group;
5032 updateMessage.OtherPrims = pc.Others; 5428 updateMessage.OtherPrims = pc.Others;
5033 updateMessage.SelectedPrims = pc.Selected; 5429 updateMessage.SelectedPrims = pc.Selected;
5034 updateMessage.TotalPrims = pc.Total; 5430 updateMessage.TotalPrims = pc.Total;
5035 updateMessage.SimWideTotalPrims = pc.Simulator; 5431 updateMessage.SimWideTotalPrims = pc.Simulator;
5036 5432
5433 //m_log.DebugFormat("[YYY]: SimWideMaxPrims={0} OwnerPrims={1} TotalPrims={2} SimWideTotalPrims={3} MaxPrims={4}",
5434 // updateMessage.SimWideMaxPrims, updateMessage.OwnerPrims, updateMessage.TotalPrims, updateMessage.SimWideTotalPrims, updateMessage.MaxPrims);
5037 try 5435 try
5038 { 5436 {
5039 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); 5437 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
5040 if (eq != null) 5438 if (eq != null)
5041 { 5439 {
5042 eq.ParcelProperties(updateMessage, this.AgentId); 5440 eq.ParcelProperties(updateMessage, this.AgentId);
5043 } 5441 }
5044 else 5442 else
5045 { 5443 {
5046 m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data."); 5444 m_log.Warn("[LLCLIENTVIEW]: No EQ Interface when sending parcel data.");
5047 } 5445 }
@@ -5078,7 +5476,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5078 public void SendForceClientSelectObjects(List<uint> ObjectIDs) 5476 public void SendForceClientSelectObjects(List<uint> ObjectIDs)
5079 { 5477 {
5080// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); 5478// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count);
5081 5479
5082 bool firstCall = true; 5480 bool firstCall = true;
5083 const int MAX_OBJECTS_PER_PACKET = 251; 5481 const int MAX_OBJECTS_PER_PACKET = 251;
5084 ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); 5482 ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
@@ -5133,14 +5531,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5133 5531
5134 if (notifyCount > 0) 5532 if (notifyCount > 0)
5135 { 5533 {
5136 if (notifyCount > 32) 5534// if (notifyCount > 32)
5137 { 5535// {
5138 m_log.InfoFormat( 5536// m_log.InfoFormat(
5139 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 5537// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
5140 + " - a developer might want to investigate whether this is a hard limit", 32); 5538// + " - a developer might want to investigate whether this is a hard limit", 32);
5141 5539//
5142 notifyCount = 32; 5540// notifyCount = 32;
5143 } 5541// }
5144 5542
5145 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 5543 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
5146 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 5544 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -5178,6 +5576,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5178 #endregion 5576 #endregion
5179 5577
5180 #region Helper Methods 5578 #region Helper Methods
5579 private void ClampVectorForUint(ref Vector3 v, float max)
5580 {
5581 float a,b;
5582
5583 a = Math.Abs(v.X);
5584 b = Math.Abs(v.Y);
5585 if(b > a)
5586 a = b;
5587 b= Math.Abs(v.Z);
5588 if(b > a)
5589 a = b;
5590
5591 if (a > max)
5592 {
5593 a = max / a;
5594 v.X *= a;
5595 v.Y *= a;
5596 v.Z *= a;
5597 }
5598 }
5181 5599
5182 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture) 5600 protected ImprovedTerseObjectUpdatePacket.ObjectDataBlock CreateImprovedTerseBlock(ISceneEntity entity, bool sendTexture)
5183 { 5601 {
@@ -5191,45 +5609,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5191 Quaternion rotation; 5609 Quaternion rotation;
5192 byte[] textureEntry; 5610 byte[] textureEntry;
5193 5611
5194 if (entity is ScenePresence) 5612 if (avatar)
5195 { 5613 {
5196 ScenePresence presence = (ScenePresence)entity; 5614 ScenePresence presence = (ScenePresence)entity;
5197 5615
5198// m_log.DebugFormat(
5199// "[LLCLIENTVIEW]: Sending terse update to {0} with pos {1}, vel {2} in {3}",
5200// Name, presence.OffsetPosition, presence.Velocity, m_scene.Name);
5201
5202 attachPoint = presence.State;
5203 collisionPlane = presence.CollisionPlane;
5204 position = presence.OffsetPosition; 5616 position = presence.OffsetPosition;
5205 velocity = presence.Velocity; 5617 velocity = presence.Velocity;
5206 acceleration = Vector3.Zero; 5618 acceleration = Vector3.Zero;
5207
5208 // Interestingly, sending this to non-zero will cause the client's avatar to start moving & accelerating
5209 // in that direction, even though we don't model this on the server. Implementing this in the future
5210 // may improve movement smoothness.
5211// acceleration = new Vector3(1, 0, 0);
5212
5213 angularVelocity = presence.AngularVelocity;
5214
5215 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5216 // it rotates around.
5217 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5218 // excessive up and down movements of the camera when looking up and down.
5219 // See http://opensimulator.org/mantis/view.php?id=3274
5220 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5221 // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change
5222 // the rotation in this case.
5223 rotation = presence.Rotation; 5619 rotation = presence.Rotation;
5224 5620 // tpvs can only see rotations around Z in some cases
5225 if (!presence.IsSatOnObject) 5621 if(!presence.Flying && !presence.IsSatOnObject)
5226 { 5622 {
5227 rotation.X = 0; 5623 rotation.X = 0f;
5228 rotation.Y = 0; 5624 rotation.Y = 0f;
5625 rotation.Normalize();
5229 } 5626 }
5627 angularVelocity = presence.AngularVelocity;
5628
5629// m_log.DebugFormat(
5630// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5631
5632 attachPoint = presence.State;
5633 collisionPlane = presence.CollisionPlane;
5230 5634
5231 if (sendTexture) 5635 if (sendTexture)
5636 {
5232 textureEntry = presence.Appearance.Texture.GetBytes(); 5637 textureEntry = presence.Appearance.Texture.GetBytes();
5638 }
5233 else 5639 else
5234 textureEntry = null; 5640 textureEntry = null;
5235 } 5641 }
@@ -5287,11 +5693,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5287 pos += 12; 5693 pos += 12;
5288 5694
5289 // Velocity 5695 // Velocity
5696 ClampVectorForUint(ref velocity, 128f);
5290 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2; 5697 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.X, -128.0f, 128.0f), data, pos); pos += 2;
5291 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2; 5698 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Y, -128.0f, 128.0f), data, pos); pos += 2;
5292 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2; 5699 Utils.UInt16ToBytes(Utils.FloatToUInt16(velocity.Z, -128.0f, 128.0f), data, pos); pos += 2;
5293 5700
5294 // Acceleration 5701 // Acceleration
5702 ClampVectorForUint(ref acceleration, 64f);
5295 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2; 5703 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.X, -64.0f, 64.0f), data, pos); pos += 2;
5296 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2; 5704 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Y, -64.0f, 64.0f), data, pos); pos += 2;
5297 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2; 5705 Utils.UInt16ToBytes(Utils.FloatToUInt16(acceleration.Z, -64.0f, 64.0f), data, pos); pos += 2;
@@ -5303,13 +5711,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5303 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2; 5711 Utils.UInt16ToBytes(Utils.FloatToUInt16(rotation.W, -1.0f, 1.0f), data, pos); pos += 2;
5304 5712
5305 // Angular Velocity 5713 // Angular Velocity
5714 ClampVectorForUint(ref angularVelocity, 64f);
5306 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2; 5715 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.X, -64.0f, 64.0f), data, pos); pos += 2;
5307 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; 5716 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
5308 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; 5717 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
5309 5718
5310 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block 5719 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
5311 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(); 5720 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
5312 5721
5313 block.Data = data; 5722 block.Data = data;
5314 5723
5315 if (textureEntry != null && textureEntry.Length > 0) 5724 if (textureEntry != null && textureEntry.Length > 0)
@@ -5333,34 +5742,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5333 5742
5334 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5743 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5335 { 5744 {
5745 Vector3 offsetPosition = data.OffsetPosition;
5746 Quaternion rotation = data.Rotation;
5747 uint parentID = data.ParentID;
5748
5336// m_log.DebugFormat( 5749// m_log.DebugFormat(
5337// "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name); 5750// "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name);
5338 5751
5339 byte[] objectData = new byte[76]; 5752 byte[] objectData = new byte[76];
5340 5753
5341 data.CollisionPlane.ToBytes(objectData, 0); 5754 Vector3 velocity = new Vector3(0, 0, 0);
5342 data.OffsetPosition.ToBytes(objectData, 16); 5755 Vector3 acceleration = new Vector3(0, 0, 0);
5343 data.Velocity.ToBytes(objectData, 28); 5756 // tpvs can only see rotations around Z in some cases
5344// data.Acceleration.ToBytes(objectData, 40); 5757 if(!data.Flying && !data.IsSatOnObject)
5345
5346 // Whilst not in mouselook, an avatar will transmit only the Z rotation as this is the only axis
5347 // it rotates around.
5348 // In mouselook, X and Y co-ordinate will also be sent but when used in Rotation, these cause unwanted
5349 // excessive up and down movements of the camera when looking up and down.
5350 // See http://opensimulator.org/mantis/view.php?id=3274
5351 // This does not affect head movement, since this is controlled entirely by camera movement rather than
5352 // body rotation. We still need to transmit X and Y for sitting avatars but mouselook does not change
5353 // the rotation in this case.
5354 Quaternion rot = data.Rotation;
5355
5356 if (!data.IsSatOnObject)
5357 { 5758 {
5358 rot.X = 0; 5759 rotation.X = 0f;
5359 rot.Y = 0; 5760 rotation.Y = 0f;
5360 } 5761 }
5762 rotation.Normalize();
5361 5763
5362 rot.ToBytes(objectData, 52); 5764 data.CollisionPlane.ToBytes(objectData, 0);
5363 //data.AngularVelocity.ToBytes(objectData, 64); 5765 offsetPosition.ToBytes(objectData, 16);
5766 velocity.ToBytes(objectData, 28);
5767 acceleration.ToBytes(objectData, 40);
5768 rotation.ToBytes(objectData, 52);
5769 data.AngularVelocity.ToBytes(objectData, 64);
5364 5770
5365 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5771 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5366 5772
@@ -5386,7 +5792,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5386 update.PCode = (byte)PCode.Avatar; 5792 update.PCode = (byte)PCode.Avatar;
5387 update.ProfileCurve = 1; 5793 update.ProfileCurve = 1;
5388 update.PSBlock = Utils.EmptyBytes; 5794 update.PSBlock = Utils.EmptyBytes;
5389 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5795 update.Scale = data.Appearance.AvatarSize;
5796// update.Scale.Z -= 0.2f;
5797
5390 update.Text = Utils.EmptyBytes; 5798 update.Text = Utils.EmptyBytes;
5391 update.TextColor = new byte[4]; 5799 update.TextColor = new byte[4];
5392 5800
@@ -5397,46 +5805,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5397 update.TextureEntry = Utils.EmptyBytes; 5805 update.TextureEntry = Utils.EmptyBytes;
5398// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5806// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5399 5807
5808/* all this flags seem related to prims and not avatars. This allow for wrong viewer side move of a avatar in prim edition mode (anv mantis 854)
5400 update.UpdateFlags = (uint)( 5809 update.UpdateFlags = (uint)(
5401 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5810 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5402 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5811 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5403 PrimFlags.ObjectOwnerModify); 5812 PrimFlags.ObjectOwnerModify);
5813*/
5814 update.UpdateFlags = 0;
5404 5815
5405 return update; 5816 return update;
5406 } 5817 }
5407 5818
5408 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID) 5819// protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart data, UUID recipientID)
5820 protected ObjectUpdatePacket.ObjectDataBlock CreatePrimUpdateBlock(SceneObjectPart part, ScenePresence sp)
5409 { 5821 {
5410 byte[] objectData = new byte[60]; 5822 byte[] objectData = new byte[60];
5411 data.RelativePosition.ToBytes(objectData, 0); 5823 part.RelativePosition.ToBytes(objectData, 0);
5412 data.Velocity.ToBytes(objectData, 12); 5824 part.Velocity.ToBytes(objectData, 12);
5413 data.Acceleration.ToBytes(objectData, 24); 5825 part.Acceleration.ToBytes(objectData, 24);
5414 try 5826
5415 { 5827 Quaternion rotation = part.RotationOffset;
5416 data.RotationOffset.ToBytes(objectData, 36); 5828 rotation.Normalize();
5417 } 5829 rotation.ToBytes(objectData, 36);
5418 catch (Exception e) 5830 part.AngularVelocity.ToBytes(objectData, 48);
5419 {
5420 m_log.Warn("[LLClientView]: exception converting quaternion to bytes, using Quaternion.Identity. Exception: " + e.ToString());
5421 OpenMetaverse.Quaternion.Identity.ToBytes(objectData, 36);
5422 }
5423 data.AngularVelocity.ToBytes(objectData, 48);
5424 5831
5425 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5832 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5426 update.ClickAction = (byte)data.ClickAction; 5833 update.ClickAction = (byte)part.ClickAction;
5427 update.CRC = 0; 5834 update.CRC = 0;
5428 update.ExtraParams = data.Shape.ExtraParams ?? Utils.EmptyBytes; 5835 update.ExtraParams = part.Shape.ExtraParams ?? Utils.EmptyBytes;
5429 update.FullID = data.UUID; 5836 update.FullID = part.UUID;
5430 update.ID = data.LocalId; 5837 update.ID = part.LocalId;
5431 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated 5838 //update.JointAxisOrAnchor = Vector3.Zero; // These are deprecated
5432 //update.JointPivot = Vector3.Zero; 5839 //update.JointPivot = Vector3.Zero;
5433 //update.JointType = 0; 5840 //update.JointType = 0;
5434 update.Material = data.Material; 5841 update.Material = part.Material;
5435 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim 5842/*
5436
5437 if (data.ParentGroup.IsAttachment) 5843 if (data.ParentGroup.IsAttachment)
5438 { 5844 {
5439 update.NameValue 5845 update.NameValue
5440 = Util.StringToBytes256( 5846 = Util.StringToBytes256(
5441 string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID)); 5847 string.Format("AttachItemID STRING RW SV {0}", data.ParentGroup.FromItemID));
5442 5848
@@ -5458,50 +5864,91 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5458 // case for attachments may contain conflicting values that can end up crashing the viewer. 5864 // case for attachments may contain conflicting values that can end up crashing the viewer.
5459 update.State = data.ParentGroup.RootPart.Shape.State; 5865 update.State = data.ParentGroup.RootPart.Shape.State;
5460 } 5866 }
5867*/
5868
5869 if (part.ParentGroup.IsAttachment)
5870 {
5871 if (part.IsRoot)
5872 {
5873 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + part.ParentGroup.FromItemID);
5874 }
5875 else
5876 update.NameValue = Utils.EmptyBytes;
5877
5878 int st = (int)part.ParentGroup.AttachmentPoint;
5879 update.State = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ;
5880 }
5881 else
5882 {
5883 update.NameValue = Utils.EmptyBytes;
5884 update.State = part.Shape.State; // not sure about this
5885 }
5461 5886
5462 update.ObjectData = objectData; 5887 update.ObjectData = objectData;
5463 update.ParentID = data.ParentID; 5888 update.ParentID = part.ParentID;
5464 update.PathBegin = data.Shape.PathBegin; 5889 update.PathBegin = part.Shape.PathBegin;
5465 update.PathCurve = data.Shape.PathCurve; 5890 update.PathCurve = part.Shape.PathCurve;
5466 update.PathEnd = data.Shape.PathEnd; 5891 update.PathEnd = part.Shape.PathEnd;
5467 update.PathRadiusOffset = data.Shape.PathRadiusOffset; 5892 update.PathRadiusOffset = part.Shape.PathRadiusOffset;
5468 update.PathRevolutions = data.Shape.PathRevolutions; 5893 update.PathRevolutions = part.Shape.PathRevolutions;
5469 update.PathScaleX = data.Shape.PathScaleX; 5894 update.PathScaleX = part.Shape.PathScaleX;
5470 update.PathScaleY = data.Shape.PathScaleY; 5895 update.PathScaleY = part.Shape.PathScaleY;
5471 update.PathShearX = data.Shape.PathShearX; 5896 update.PathShearX = part.Shape.PathShearX;
5472 update.PathShearY = data.Shape.PathShearY; 5897 update.PathShearY = part.Shape.PathShearY;
5473 update.PathSkew = data.Shape.PathSkew; 5898 update.PathSkew = part.Shape.PathSkew;
5474 update.PathTaperX = data.Shape.PathTaperX; 5899 update.PathTaperX = part.Shape.PathTaperX;
5475 update.PathTaperY = data.Shape.PathTaperY; 5900 update.PathTaperY = part.Shape.PathTaperY;
5476 update.PathTwist = data.Shape.PathTwist; 5901 update.PathTwist = part.Shape.PathTwist;
5477 update.PathTwistBegin = data.Shape.PathTwistBegin; 5902 update.PathTwistBegin = part.Shape.PathTwistBegin;
5478 update.PCode = data.Shape.PCode; 5903 update.PCode = part.Shape.PCode;
5479 update.ProfileBegin = data.Shape.ProfileBegin; 5904 update.ProfileBegin = part.Shape.ProfileBegin;
5480 update.ProfileCurve = data.Shape.ProfileCurve; 5905 update.ProfileCurve = part.Shape.ProfileCurve;
5481 update.ProfileEnd = data.Shape.ProfileEnd; 5906
5482 update.ProfileHollow = data.Shape.ProfileHollow; 5907 ushort profileBegin = part.Shape.ProfileBegin;
5483 update.PSBlock = data.ParticleSystem ?? Utils.EmptyBytes; 5908 ushort profileHollow = part.Shape.ProfileHollow;
5484 update.TextColor = data.GetTextColor().GetBytes(false); 5909
5485 update.TextureAnim = data.TextureAnimation ?? Utils.EmptyBytes; 5910 if(part.Shape.SculptType == (byte)SculptType.Mesh) // filter out hack
5486 update.TextureEntry = data.Shape.TextureEntry ?? Utils.EmptyBytes; 5911 {
5487 update.Scale = data.Shape.Scale; 5912 update.ProfileCurve = (byte)(part.Shape.ProfileCurve & 0x0f);
5488 update.Text = Util.StringToBytes256(data.Text); 5913 // fix old values that confused viewers
5489 update.MediaURL = Util.StringToBytes256(data.MediaUrl); 5914 if(profileBegin == 1)
5915 profileBegin = 9375;
5916 if(profileHollow == 1)
5917 profileHollow = 27500;
5918 // fix torus hole size Y that also confuse some viewers
5919 if(update.ProfileCurve == (byte)ProfileShape.Circle && update.PathScaleY < 150)
5920 update.PathScaleY = 150;
5921 }
5922 else
5923 {
5924 update.ProfileCurve = part.Shape.ProfileCurve;
5925 }
5926
5927 update.ProfileHollow = profileHollow;
5928 update.ProfileBegin = profileBegin;
5929 update.ProfileEnd = part.Shape.ProfileEnd;
5930 update.PSBlock = part.ParticleSystem ?? Utils.EmptyBytes;
5931 update.TextColor = part.GetTextColor().GetBytes(false);
5932 update.TextureAnim = part.TextureAnimation ?? Utils.EmptyBytes;
5933 update.TextureEntry = part.Shape.TextureEntry ?? Utils.EmptyBytes;
5934 update.Scale = part.Shape.Scale;
5935 update.Text = Util.StringToBytes(part.Text, 255);
5936 update.MediaURL = Util.StringToBytes(part.MediaUrl, 255);
5490 5937
5491 #region PrimFlags 5938 #region PrimFlags
5492 5939
5493 PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(recipientID, data.UUID); 5940 PrimFlags flags = (PrimFlags)m_scene.Permissions.GenerateClientFlags(part, sp);
5494 5941
5495 // Don't send the CreateSelected flag to everyone 5942 // Don't send the CreateSelected flag to everyone
5496 flags &= ~PrimFlags.CreateSelected; 5943 flags &= ~PrimFlags.CreateSelected;
5497 5944
5498 if (recipientID == data.OwnerID) 5945 if (sp.UUID == part.OwnerID)
5499 { 5946 {
5500 if (data.CreateSelected) 5947 if (part.CreateSelected)
5501 { 5948 {
5502 // Only send this flag once, then unset it 5949 // Only send this flag once, then unset it
5503 flags |= PrimFlags.CreateSelected; 5950 flags |= PrimFlags.CreateSelected;
5504 data.CreateSelected = false; 5951 part.CreateSelected = false;
5505 } 5952 }
5506 } 5953 }
5507 5954
@@ -5513,21 +5960,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5513 5960
5514 #endregion PrimFlags 5961 #endregion PrimFlags
5515 5962
5516 if (data.Sound != UUID.Zero) 5963 if (part.Sound != UUID.Zero)
5517 { 5964 {
5518 update.Sound = data.Sound; 5965 update.Sound = part.Sound;
5519 update.OwnerID = data.OwnerID; 5966 update.OwnerID = part.OwnerID;
5520 update.Gain = (float)data.SoundGain; 5967 update.Gain = (float)part.SoundGain;
5521 update.Radius = (float)data.SoundRadius; 5968 update.Radius = (float)part.SoundRadius;
5522 update.Flags = data.SoundFlags; 5969 update.Flags = part.SoundFlags;
5523 } 5970 }
5524 5971
5525 switch ((PCode)data.Shape.PCode) 5972 switch ((PCode)part.Shape.PCode)
5526 { 5973 {
5527 case PCode.Grass: 5974 case PCode.Grass:
5528 case PCode.Tree: 5975 case PCode.Tree:
5529 case PCode.NewTree: 5976 case PCode.NewTree:
5530 update.Data = new byte[] { data.Shape.State }; 5977 update.Data = new byte[] { part.Shape.State };
5531 break; 5978 break;
5532 default: 5979 default:
5533 update.Data = Utils.EmptyBytes; 5980 update.Data = Utils.EmptyBytes;
@@ -5556,14 +6003,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5556 OutPacket(packet, ThrottleOutPacketType.Task); 6003 OutPacket(packet, ThrottleOutPacketType.Task);
5557 } 6004 }
5558 6005
5559 public ulong GetGroupPowers(UUID groupID) 6006 public Dictionary<UUID, ulong> GetGroupPowers()
5560 { 6007 {
5561 if (groupID == ActiveGroupId) 6008 lock(m_groupPowers)
5562 return ActiveGroupPowers; 6009 {
6010 return new Dictionary<UUID, ulong>(m_groupPowers);
6011 }
6012 }
5563 6013
5564 if (m_groupPowers.ContainsKey(groupID)) 6014 public void SetGroupPowers(Dictionary<UUID, ulong> powers)
5565 return m_groupPowers[groupID]; 6015 {
6016 lock(m_groupPowers)
6017 {
6018 m_groupPowers.Clear();
6019 m_groupPowers = powers;
6020 }
6021 }
5566 6022
6023 public ulong GetGroupPowers(UUID groupID)
6024 {
6025 lock(m_groupPowers)
6026 {
6027 if (m_groupPowers.ContainsKey(groupID))
6028 return m_groupPowers[groupID];
6029 }
5567 return 0; 6030 return 0;
5568 } 6031 }
5569 6032
@@ -5579,18 +6042,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5579 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 6042 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5580 // for each AgentUpdate packet. 6043 // for each AgentUpdate packet.
5581 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 6044 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5582 6045
5583 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 6046 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
6047 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
6048 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5584 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 6049 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5585 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 6050 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5586 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 6051 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
5587 AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false); 6052 AddLocalPacketHandler(PacketType.ParcelBuy, HandleParcelBuyRequest, false);
5588 AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest); 6053 AddLocalPacketHandler(PacketType.UUIDGroupNameRequest, HandleUUIDGroupNameRequest);
5589 AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest); 6054 AddLocalPacketHandler(PacketType.ObjectGroup, HandleObjectGroupRequest);
5590 AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage, true, true); 6055 AddLocalPacketHandler(PacketType.GenericMessage, HandleGenericMessage);
5591 AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest, true, true); 6056 AddLocalPacketHandler(PacketType.AvatarPropertiesRequest, HandleAvatarPropertiesRequest);
5592 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer); 6057 AddLocalPacketHandler(PacketType.ChatFromViewer, HandleChatFromViewer);
5593 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate, true, true); 6058 AddLocalPacketHandler(PacketType.AvatarPropertiesUpdate, HandlerAvatarPropertiesUpdate);
5594 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply); 6059 AddLocalPacketHandler(PacketType.ScriptDialogReply, HandlerScriptDialogReply);
5595 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage); 6060 AddLocalPacketHandler(PacketType.ImprovedInstantMessage, HandlerImprovedInstantMessage);
5596 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship); 6061 AddLocalPacketHandler(PacketType.AcceptFriendship, HandlerAcceptFriendship);
@@ -5598,6 +6063,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5598 AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship); 6063 AddLocalPacketHandler(PacketType.TerminateFriendship, HandlerTerminateFriendship);
5599 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); 6064 AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject);
5600 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); 6065 AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject);
6066 AddLocalPacketHandler(PacketType.RezRestoreToWorld, HandlerRezRestoreToWorld);
5601 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); 6067 AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand);
5602 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); 6068 AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false);
5603 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); 6069 AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest);
@@ -5732,6 +6198,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5732 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 6198 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5733 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 6199 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5734 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 6200 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
6201 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5735 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 6202 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5736 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 6203 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5737 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 6204 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5775,8 +6242,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5775 AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete); 6242 AddLocalPacketHandler(PacketType.PickDelete, HandlePickDelete);
5776 AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete); 6243 AddLocalPacketHandler(PacketType.PickGodDelete, HandlePickGodDelete);
5777 AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate); 6244 AddLocalPacketHandler(PacketType.PickInfoUpdate, HandlePickInfoUpdate);
5778 AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate, true, true); 6245 AddLocalPacketHandler(PacketType.AvatarNotesUpdate, HandleAvatarNotesUpdate);
5779 AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate, true, true); 6246 AddLocalPacketHandler(PacketType.AvatarInterestsUpdate, HandleAvatarInterestsUpdate);
5780 AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights); 6247 AddLocalPacketHandler(PacketType.GrantUserRights, HandleGrantUserRights);
5781 AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery); 6248 AddLocalPacketHandler(PacketType.PlacesQuery, HandlePlacesQuery);
5782 AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry); 6249 AddLocalPacketHandler(PacketType.UpdateMuteListEntry, HandleUpdateMuteListEntry);
@@ -5798,7 +6265,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5798 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 6265 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5799 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 6266 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5800 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 6267 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5801 6268 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
6269 AddLocalPacketHandler(PacketType.RevokePermissions, HandleRevokePermissions);
5802 AddGenericPacketHandler("autopilot", HandleAutopilot); 6270 AddGenericPacketHandler("autopilot", HandleAutopilot);
5803 } 6271 }
5804 6272
@@ -5809,7 +6277,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5809 #region Scene/Avatar 6277 #region Scene/Avatar
5810 6278
5811 // Threshold for body rotation to be a significant agent update 6279 // Threshold for body rotation to be a significant agent update
5812 private const float QDELTA = 0.000001f; 6280 // use the abs of cos
6281 private const float QDELTABody = 1.0f - 0.00005f;
6282 private const float QDELTAHead = 1.0f - 0.00005f;
5813 // Threshold for camera rotation to be a significant agent update 6283 // Threshold for camera rotation to be a significant agent update
5814 private const float VDELTA = 0.01f; 6284 private const float VDELTA = 0.01f;
5815 6285
@@ -5832,27 +6302,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5832 /// <param name='x'></param> 6302 /// <param name='x'></param>
5833 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) 6303 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5834 { 6304 {
5835 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); 6305 if(
5836 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); 6306 (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5837 6307// || ((x.ControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0 &&
5838 bool movementSignificant = 6308// (x.ControlFlags & 0x3f8dfff) != 0) // we need to rotate the av on fly
5839 (qdelta1 > QDELTA) // significant if body rotation above threshold 6309 || x.ControlFlags != (byte)AgentManager.ControlFlags.NONE// actually all movement controls need to pass
5840 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5841 // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold
5842 || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
5843 || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands
5844 || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed
5845 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed 6310 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5846 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed 6311 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5847 ; 6312 || (Math.Abs(x.Far - m_thisAgentUpdateArgs.Far) >= 32) // significant if far distance changed
5848 //if (movementSignificant) 6313 )
5849 //{ 6314 return true;
5850 //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", 6315
5851 // qdelta1, qdelta2); 6316 float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation));
5852 //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", 6317 //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation));
5853 // x.ControlFlags, x.Flags, x.Far, x.State); 6318
5854 //} 6319 if(
5855 return movementSignificant; 6320 qdelta1 < QDELTABody // significant if body rotation above(below cos) threshold
6321 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
6322 // || qdelta2 < QDELTAHead // significant if head rotation above(below cos) threshold
6323 )
6324 return true;
6325
6326 return false;
5856 } 6327 }
5857 6328
5858 /// <summary> 6329 /// <summary>
@@ -5863,78 +6334,95 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5863 /// <param name='x'></param> 6334 /// <param name='x'></param>
5864 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) 6335 private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5865 { 6336 {
5866 float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); 6337 if(Math.Abs(x.CameraCenter.X - m_thisAgentUpdateArgs.CameraCenter.X) > VDELTA ||
5867 float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); 6338 Math.Abs(x.CameraCenter.Y - m_thisAgentUpdateArgs.CameraCenter.Y) > VDELTA ||
5868 float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); 6339 Math.Abs(x.CameraCenter.Z - m_thisAgentUpdateArgs.CameraCenter.Z) > VDELTA ||
5869 float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis);
5870 6340
5871 bool cameraSignificant = 6341 Math.Abs(x.CameraAtAxis.X - m_thisAgentUpdateArgs.CameraAtAxis.X) > VDELTA ||
5872 (vdelta1 > VDELTA) || 6342 Math.Abs(x.CameraAtAxis.Y - m_thisAgentUpdateArgs.CameraAtAxis.Y) > VDELTA ||
5873 (vdelta2 > VDELTA) || 6343// Math.Abs(x.CameraAtAxis.Z - m_thisAgentUpdateArgs.CameraAtAxis.Z) > VDELTA ||
5874 (vdelta3 > VDELTA) ||
5875 (vdelta4 > VDELTA)
5876 ;
5877 6344
5878 //if (cameraSignificant) 6345 Math.Abs(x.CameraLeftAxis.X - m_thisAgentUpdateArgs.CameraLeftAxis.X) > VDELTA ||
5879 //{ 6346 Math.Abs(x.CameraLeftAxis.Y - m_thisAgentUpdateArgs.CameraLeftAxis.Y) > VDELTA ||
5880 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", 6347// Math.Abs(x.CameraLeftAxis.Z - m_thisAgentUpdateArgs.CameraLeftAxis.Z) > VDELTA ||
5881 // x.CameraAtAxis, x.CameraCenter);
5882 //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}",
5883 // x.CameraLeftAxis, x.CameraUpAxis);
5884 //}
5885 6348
5886 return cameraSignificant; 6349 Math.Abs(x.CameraUpAxis.X - m_thisAgentUpdateArgs.CameraUpAxis.X) > VDELTA ||
5887 } 6350 Math.Abs(x.CameraUpAxis.Y - m_thisAgentUpdateArgs.CameraUpAxis.Y) > VDELTA
6351// Math.Abs(x.CameraLeftAxis.Z - m_thisAgentUpdateArgs.CameraLeftAxis.Z) > VDELTA ||
6352 )
6353 return true;
5888 6354
5889 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 6355 return false;
5890 { 6356 }
5891 // We got here, which means that something in agent update was significant
5892 6357
6358 private bool HandleAgentUpdate(IClientAPI sender, Packet packet)
6359 {
5893 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; 6360 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5894 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 6361 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5895 6362
5896 if (x.AgentID != AgentId || x.SessionID != SessionId) 6363 if (x.AgentID != AgentId || x.SessionID != SessionId)
6364 {
6365 PacketPool.Instance.ReturnPacket(packet);
5897 return false; 6366 return false;
6367 }
6368
6369 uint seq = packet.Header.Sequence;
6370
6371 TotalAgentUpdates++;
6372 // dont let ignored updates pollute this throttles
6373 if(SceneAgent == null || SceneAgent.IsChildAgent ||
6374 SceneAgent.IsInTransit || seq <= m_thisAgentUpdateArgs.lastpacketSequence )
6375 {
6376 // throttle reset is done at MoveAgentIntoRegion()
6377 // called by scenepresence on completemovement
6378 PacketPool.Instance.ReturnPacket(packet);
6379 return true;
6380 }
6381
6382 m_thisAgentUpdateArgs.lastpacketSequence = seq;
5898 6383
5899 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5900 // to see what exactly changed
5901 bool movement = CheckAgentMovementUpdateSignificance(x); 6384 bool movement = CheckAgentMovementUpdateSignificance(x);
5902 bool camera = CheckAgentCameraUpdateSignificance(x); 6385 bool camera = CheckAgentCameraUpdateSignificance(x);
5903 6386
5904 m_thisAgentUpdateArgs.AgentID = x.AgentID;
5905 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5906 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5907 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5908 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5909 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5910 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5911 m_thisAgentUpdateArgs.Far = x.Far;
5912 m_thisAgentUpdateArgs.Flags = x.Flags;
5913 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5914 m_thisAgentUpdateArgs.SessionID = x.SessionID;
5915 m_thisAgentUpdateArgs.State = x.State;
5916
5917 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5918 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5919 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5920
5921 // Was there a significant movement/state change? 6387 // Was there a significant movement/state change?
5922 if (movement) 6388 if (movement)
5923 { 6389 {
6390 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
6391 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
6392 m_thisAgentUpdateArgs.Far = x.Far;
6393 m_thisAgentUpdateArgs.Flags = x.Flags;
6394 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
6395 m_thisAgentUpdateArgs.State = x.State;
6396
6397 m_thisAgentUpdateArgs.NeedsCameraCollision = !camera;
6398
6399 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
6400 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
6401
5924 if (handlerPreAgentUpdate != null) 6402 if (handlerPreAgentUpdate != null)
5925 OnPreAgentUpdate(this, m_thisAgentUpdateArgs); 6403 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5926 6404
5927 if (handlerAgentUpdate != null) 6405 if (handlerAgentUpdate != null)
5928 OnAgentUpdate(this, m_thisAgentUpdateArgs); 6406 OnAgentUpdate(this, m_thisAgentUpdateArgs);
6407
5929 } 6408 }
6409
5930 // Was there a significant camera(s) change? 6410 // Was there a significant camera(s) change?
5931 if (camera) 6411 if (camera)
6412 {
6413 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
6414 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
6415 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
6416 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
6417
6418 m_thisAgentUpdateArgs.NeedsCameraCollision = true;
6419
6420 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
6421
5932 if (handlerAgentCameraUpdate != null) 6422 if (handlerAgentCameraUpdate != null)
5933 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); 6423 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5934 6424
5935 handlerAgentUpdate = null; 6425 }
5936 handlerPreAgentUpdate = null;
5937 handlerAgentCameraUpdate = null;
5938 6426
5939 PacketPool.Instance.ReturnPacket(packet); 6427 PacketPool.Instance.ReturnPacket(packet);
5940 6428
@@ -5967,6 +6455,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5967 ParcelGodMarkAsContentPacket ParcelGodMarkAsContent = 6455 ParcelGodMarkAsContentPacket ParcelGodMarkAsContent =
5968 (ParcelGodMarkAsContentPacket)Packet; 6456 (ParcelGodMarkAsContentPacket)Packet;
5969 6457
6458 if(SessionId != ParcelGodMarkAsContent.AgentData.SessionID || AgentId != ParcelGodMarkAsContent.AgentData.AgentID)
6459 return false;
6460
5970 ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark; 6461 ParcelGodMark ParcelGodMarkAsContentHandler = OnParcelGodMark;
5971 if (ParcelGodMarkAsContentHandler != null) 6462 if (ParcelGodMarkAsContentHandler != null)
5972 { 6463 {
@@ -5982,6 +6473,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5982 { 6473 {
5983 FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet; 6474 FreezeUserPacket FreezeUser = (FreezeUserPacket)Packet;
5984 6475
6476 if(SessionId != FreezeUser.AgentData.SessionID || AgentId != FreezeUser.AgentData.AgentID)
6477 return false;
6478
5985 FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser; 6479 FreezeUserUpdate FreezeUserHandler = OnParcelFreezeUser;
5986 if (FreezeUserHandler != null) 6480 if (FreezeUserHandler != null)
5987 { 6481 {
@@ -5999,6 +6493,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5999 EjectUserPacket EjectUser = 6493 EjectUserPacket EjectUser =
6000 (EjectUserPacket)Packet; 6494 (EjectUserPacket)Packet;
6001 6495
6496 if(SessionId != EjectUser.AgentData.SessionID || AgentId != EjectUser.AgentData.AgentID)
6497 return false;
6498
6002 EjectUserUpdate EjectUserHandler = OnParcelEjectUser; 6499 EjectUserUpdate EjectUserHandler = OnParcelEjectUser;
6003 if (EjectUserHandler != null) 6500 if (EjectUserHandler != null)
6004 { 6501 {
@@ -6016,6 +6513,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6016 ParcelBuyPassPacket ParcelBuyPass = 6513 ParcelBuyPassPacket ParcelBuyPass =
6017 (ParcelBuyPassPacket)Packet; 6514 (ParcelBuyPassPacket)Packet;
6018 6515
6516 if(SessionId != ParcelBuyPass.AgentData.SessionID || AgentId != ParcelBuyPass.AgentData.AgentID)
6517 return false;
6518
6019 ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass; 6519 ParcelBuyPass ParcelBuyPassHandler = OnParcelBuyPass;
6020 if (ParcelBuyPassHandler != null) 6520 if (ParcelBuyPassHandler != null)
6021 { 6521 {
@@ -6048,8 +6548,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6048 6548
6049 private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack) 6549 private bool HandleUUIDGroupNameRequest(IClientAPI sender, Packet Pack)
6050 { 6550 {
6051 UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack; 6551 ScenePresence sp = (ScenePresence)SceneAgent;
6552 if(sp == null || sp.IsDeleted || (sp.IsInTransit && !sp.IsInLocalTransit))
6553 return true;
6052 6554
6555 UUIDGroupNameRequestPacket upack = (UUIDGroupNameRequestPacket)Pack;
6053 6556
6054 for (int i = 0; i < upack.UUIDNameBlock.Length; i++) 6557 for (int i = 0; i < upack.UUIDNameBlock.Length; i++)
6055 { 6558 {
@@ -6101,7 +6604,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6101 } 6604 }
6102 } 6605 }
6103 } 6606 }
6104 6607
6105 //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method); 6608 //m_log.Debug("[LLCLIENTVIEW]: Not handling GenericMessage with method-type of: " + method);
6106 return false; 6609 return false;
6107 } 6610 }
@@ -6150,6 +6653,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6150 return true; 6653 return true;
6151 } 6654 }
6152 6655
6656 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
6657 {
6658 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
6659 if (p.AgentData.SessionID != SessionId ||
6660 p.AgentData.AgentID != AgentId)
6661 return true;
6662
6663 m_VelocityInterpolate = false;
6664 return true;
6665 }
6666
6667 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
6668 {
6669 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
6670 if (p.AgentData.SessionID != SessionId ||
6671 p.AgentData.AgentID != AgentId)
6672 return true;
6673
6674 m_VelocityInterpolate = true;
6675 return true;
6676 }
6677
6678
6153 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 6679 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
6154 { 6680 {
6155 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 6681 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6442,11 +6968,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6442 RezObject handlerRezObject = OnRezObject; 6968 RezObject handlerRezObject = OnRezObject;
6443 if (handlerRezObject != null) 6969 if (handlerRezObject != null)
6444 { 6970 {
6445 handlerRezObject(this, rezPacket.InventoryData.ItemID, rezPacket.RezData.RayEnd, 6971 UUID rezGroupID = rezPacket.AgentData.GroupID;
6446 rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID, 6972 if(!IsGroupMember(rezGroupID))
6447 rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection, 6973 rezGroupID = UUID.Zero;
6448 rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem, 6974 handlerRezObject(this, rezPacket.InventoryData.ItemID, rezGroupID, rezPacket.RezData.RayEnd,
6449 rezPacket.RezData.FromTaskID); 6975 rezPacket.RezData.RayStart, rezPacket.RezData.RayTargetID,
6976 rezPacket.RezData.BypassRaycast, rezPacket.RezData.RayEndIsIntersection,
6977 rezPacket.RezData.RezSelected, rezPacket.RezData.RemoveItem,
6978 rezPacket.RezData.FromTaskID);
6450 } 6979 }
6451 return true; 6980 return true;
6452 } 6981 }
@@ -6485,6 +7014,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6485 return true; 7014 return true;
6486 } 7015 }
6487 7016
7017 private bool HandlerRezRestoreToWorld(IClientAPI sender, Packet Pack)
7018 {
7019 RezRestoreToWorldPacket restore = (RezRestoreToWorldPacket)Pack;
7020
7021 #region Packet Session and User Check
7022 if (m_checkPackets)
7023 {
7024 if (restore.AgentData.SessionID != SessionId ||
7025 restore.AgentData.AgentID != AgentId)
7026 return true;
7027 }
7028 #endregion
7029
7030 RezRestoreToWorld handlerRezRestoreToWorld = OnRezRestoreToWorld;
7031 if (handlerRezRestoreToWorld != null)
7032 handlerRezRestoreToWorld(this, restore.InventoryData.ItemID);
7033
7034 return true;
7035 }
7036
6488 private bool HandlerModifyLand(IClientAPI sender, Packet Pack) 7037 private bool HandlerModifyLand(IClientAPI sender, Packet Pack)
6489 { 7038 {
6490 ModifyLandPacket modify = (ModifyLandPacket)Pack; 7039 ModifyLandPacket modify = (ModifyLandPacket)Pack;
@@ -6501,9 +7050,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6501 //m_log.Info("[LAND]: LAND:" + modify.ToString()); 7050 //m_log.Info("[LAND]: LAND:" + modify.ToString());
6502 if (modify.ParcelData.Length > 0) 7051 if (modify.ParcelData.Length > 0)
6503 { 7052 {
6504 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, 7053 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore,
6505 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. 7054 // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit.
6506 m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable
6507 if (OnModifyTerrain != null) 7055 if (OnModifyTerrain != null)
6508 { 7056 {
6509 for (int i = 0; i < modify.ParcelData.Length; i++) 7057 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6519,7 +7067,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6519 } 7067 }
6520 } 7068 }
6521 } 7069 }
6522 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6523 } 7070 }
6524 7071
6525 return true; 7072 return true;
@@ -6580,7 +7127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6580 byte[] visualparams = new byte[appear.VisualParam.Length]; 7127 byte[] visualparams = new byte[appear.VisualParam.Length];
6581 for (int i = 0; i < appear.VisualParam.Length; i++) 7128 for (int i = 0; i < appear.VisualParam.Length; i++)
6582 visualparams[i] = appear.VisualParam[i].ParamValue; 7129 visualparams[i] = appear.VisualParam[i].ParamValue;
6583 //var b = appear.WearableData[0]; 7130 //var b = appear.WearableData[0];
6584 7131
6585 Primitive.TextureEntry te = null; 7132 Primitive.TextureEntry te = null;
6586 if (appear.ObjectData.TextureEntry.Length > 1) 7133 if (appear.ObjectData.TextureEntry.Length > 1)
@@ -6588,7 +7135,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6588 7135
6589 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; 7136 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6590 for (int i=0; i<appear.WearableData.Length;i++) 7137 for (int i=0; i<appear.WearableData.Length;i++)
6591 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)}; 7138 cacheitems[i] = new WearableCacheItem(){
7139 CacheId = appear.WearableData[i].CacheID,
7140 TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)
7141 };
6592 7142
6593 7143
6594 7144
@@ -6794,13 +7344,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6794 return true; 7344 return true;
6795 } 7345 }
6796 7346
6797 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) 7347 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack)
6798 { 7348 {
7349 m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement");
7350
6799 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; 7351 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion;
6800 if (handlerCompleteMovementToRegion != null) 7352 if (handlerCompleteMovementToRegion != null)
6801 { 7353 {
6802 handlerCompleteMovementToRegion(sender, true); 7354 handlerCompleteMovementToRegion(sender, true);
6803 } 7355 }
7356 else
7357 m_log.Debug("HandleCompleteAgentMovement NULL handler");
7358
6804 handlerCompleteMovementToRegion = null; 7359 handlerCompleteMovementToRegion = null;
6805 7360
6806 return true; 7361 return true;
@@ -6818,7 +7373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6818 return true; 7373 return true;
6819 } 7374 }
6820 #endregion 7375 #endregion
6821 7376/*
6822 StartAnim handlerStartAnim = null; 7377 StartAnim handlerStartAnim = null;
6823 StopAnim handlerStopAnim = null; 7378 StopAnim handlerStopAnim = null;
6824 7379
@@ -6842,6 +7397,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6842 } 7397 }
6843 } 7398 }
6844 return true; 7399 return true;
7400*/
7401 ChangeAnim handlerChangeAnim = null;
7402
7403 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
7404 {
7405 handlerChangeAnim = OnChangeAnim;
7406 if (handlerChangeAnim != null)
7407 {
7408 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
7409 }
7410 }
7411
7412 handlerChangeAnim = OnChangeAnim;
7413 if (handlerChangeAnim != null)
7414 {
7415 handlerChangeAnim(UUID.Zero, false, true);
7416 }
7417
7418 return true;
6845 } 7419 }
6846 7420
6847 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 7421 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6997,7 +7571,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6997 SendUserInfoReply(false, true, ""); 7571 SendUserInfoReply(false, true, "");
6998 } 7572 }
6999 return true; 7573 return true;
7000
7001 } 7574 }
7002 7575
7003 private bool HandleUpdateUserInfo(IClientAPI sender, Packet Pack) 7576 private bool HandleUpdateUserInfo(IClientAPI sender, Packet Pack)
@@ -7087,6 +7660,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7087 #endregion 7660 #endregion
7088 7661
7089 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 7662 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
7663 GenericCall2 handler = OnUpdateThrottles;
7664 if (handler != null)
7665 {
7666 handler();
7667 }
7090 return true; 7668 return true;
7091 } 7669 }
7092 7670
@@ -7207,7 +7785,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7207 7785
7208 AddNewPrim handlerAddPrim = OnAddPrim; 7786 AddNewPrim handlerAddPrim = OnAddPrim;
7209 if (handlerAddPrim != null) 7787 if (handlerAddPrim != null)
7210 handlerAddPrim(AgentId, ActiveGroupId, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection); 7788 handlerAddPrim(AgentId, addPacket.AgentData.GroupID, addPacket.ObjectData.RayEnd, addPacket.ObjectData.Rotation, shape, addPacket.ObjectData.BypassRaycast, addPacket.ObjectData.RayStart, addPacket.ObjectData.RayTargetID, addPacket.ObjectData.RayEndIsIntersection);
7211 } 7789 }
7212 return true; 7790 return true;
7213 } 7791 }
@@ -7302,14 +7880,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7302 7880
7303 ObjectDuplicate handlerObjectDuplicate = null; 7881 ObjectDuplicate handlerObjectDuplicate = null;
7304 7882
7305 for (int i = 0; i < dupe.ObjectData.Length; i++) 7883 handlerObjectDuplicate = OnObjectDuplicate;
7884 if (handlerObjectDuplicate != null)
7306 { 7885 {
7307 handlerObjectDuplicate = OnObjectDuplicate; 7886 for (int i = 0; i < dupe.ObjectData.Length; i++)
7308 if (handlerObjectDuplicate != null)
7309 { 7887 {
7888 UUID rezGroupID = dupe.AgentData.GroupID;
7889 if(!IsGroupMember(rezGroupID))
7890 rezGroupID = UUID.Zero;
7310 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset, 7891 handlerObjectDuplicate(dupe.ObjectData[i].ObjectLocalID, dupe.SharedData.Offset,
7311 dupe.SharedData.DuplicateFlags, AgentId, 7892 dupe.SharedData.DuplicateFlags, AgentId,
7312 ActiveGroupId); 7893 rezGroupID);
7313 } 7894 }
7314 } 7895 }
7315 7896
@@ -7354,16 +7935,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7354 return true; 7935 return true;
7355 } 7936 }
7356 #endregion 7937 #endregion
7357 7938 List<uint> thisSelection = new List<uint>();
7358 ObjectSelect handlerObjectSelect = null; 7939 ObjectSelect handlerObjectSelect = null;
7359 7940 uint objID;
7360 for (int i = 0; i < incomingselect.ObjectData.Length; i++) 7941 handlerObjectSelect = OnObjectSelect;
7942 if (handlerObjectSelect != null)
7361 { 7943 {
7362 handlerObjectSelect = OnObjectSelect; 7944 for (int i = 0; i < incomingselect.ObjectData.Length; i++)
7363 if (handlerObjectSelect != null)
7364 { 7945 {
7365 handlerObjectSelect(incomingselect.ObjectData[i].ObjectLocalID, this); 7946 objID = incomingselect.ObjectData[i].ObjectLocalID;
7947 thisSelection.Add(objID);
7366 } 7948 }
7949
7950 handlerObjectSelect(thisSelection, this);
7367 } 7951 }
7368 return true; 7952 return true;
7369 } 7953 }
@@ -7382,13 +7966,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7382 #endregion 7966 #endregion
7383 7967
7384 ObjectDeselect handlerObjectDeselect = null; 7968 ObjectDeselect handlerObjectDeselect = null;
7385 7969 uint objID;
7386 for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) 7970 for (int i = 0; i < incomingdeselect.ObjectData.Length; i++)
7387 { 7971 {
7972 objID = incomingdeselect.ObjectData[i].ObjectLocalID;
7973
7388 handlerObjectDeselect = OnObjectDeselect; 7974 handlerObjectDeselect = OnObjectDeselect;
7389 if (handlerObjectDeselect != null) 7975 if (handlerObjectDeselect != null)
7390 { 7976 {
7391 OnObjectDeselect(incomingdeselect.ObjectData[i].ObjectLocalID, this); 7977 OnObjectDeselect(objID, this);
7392 } 7978 }
7393 } 7979 }
7394 return true; 7980 return true;
@@ -7511,7 +8097,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7511 physdata.Bounce = phsblock.Restitution; 8097 physdata.Bounce = phsblock.Restitution;
7512 physdata.Density = phsblock.Density; 8098 physdata.Density = phsblock.Density;
7513 physdata.Friction = phsblock.Friction; 8099 physdata.Friction = phsblock.Friction;
7514 physdata.GravitationModifier = phsblock.GravityMultiplier; 8100 physdata.GravitationModifier = phsblock.GravityMultiplier;
7515 } 8101 }
7516 8102
7517 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 8103 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7519,19 +8105,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7519 return true; 8105 return true;
7520 } 8106 }
7521 8107
8108 Dictionary<uint, uint> objImageSeqs = null;
8109 double lastobjImageSeqsMS = 0.0;
8110
7522 private bool HandleObjectImage(IClientAPI sender, Packet Pack) 8111 private bool HandleObjectImage(IClientAPI sender, Packet Pack)
7523 { 8112 {
7524 ObjectImagePacket imagePack = (ObjectImagePacket)Pack; 8113 ObjectImagePacket imagePack = (ObjectImagePacket)Pack;
7525 8114
7526 UpdatePrimTexture handlerUpdatePrimTexture = null; 8115 UpdatePrimTexture handlerUpdatePrimTexture = OnUpdatePrimTexture;
8116 if (handlerUpdatePrimTexture == null)
8117 return true;
8118
8119 double now = Util.GetTimeStampMS();
8120 if(objImageSeqs == null || ( now - lastobjImageSeqsMS > 30000.0))
8121 {
8122 objImageSeqs = null; // yeah i know superstition...
8123 objImageSeqs = new Dictionary<uint, uint>(16);
8124 }
8125
8126 lastobjImageSeqsMS = now;
8127 uint seq = Pack.Header.Sequence;
8128 uint id;
8129 uint lastseq;
8130
8131 ObjectImagePacket.ObjectDataBlock o;
7527 for (int i = 0; i < imagePack.ObjectData.Length; i++) 8132 for (int i = 0; i < imagePack.ObjectData.Length; i++)
7528 { 8133 {
7529 handlerUpdatePrimTexture = OnUpdatePrimTexture; 8134 o = imagePack.ObjectData[i];
7530 if (handlerUpdatePrimTexture != null) 8135 id = o.ObjectLocalID;
7531 { 8136 if(objImageSeqs.TryGetValue(id, out lastseq))
7532 handlerUpdatePrimTexture(imagePack.ObjectData[i].ObjectLocalID, 8137 {
7533 imagePack.ObjectData[i].TextureEntry, this); 8138 if(seq <= lastseq)
7534 } 8139 continue;
8140 }
8141 objImageSeqs[id] = seq;
8142 handlerUpdatePrimTexture(id, o.TextureEntry, this);
7535 } 8143 }
7536 return true; 8144 return true;
7537 } 8145 }
@@ -7605,6 +8213,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7605 touchArgs.Add(arg); 8213 touchArgs.Add(arg);
7606 } 8214 }
7607 } 8215 }
8216
7608 handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial, 8217 handlerGrabUpdate(grabUpdate.ObjectData.ObjectID, grabUpdate.ObjectData.GrabOffsetInitial,
7609 grabUpdate.ObjectData.GrabPosition, this, touchArgs); 8218 grabUpdate.ObjectData.GrabPosition, this, touchArgs);
7610 } 8219 }
@@ -7921,10 +8530,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7921 handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay; 8530 handlerObjectDuplicateOnRay = OnObjectDuplicateOnRay;
7922 if (handlerObjectDuplicateOnRay != null) 8531 if (handlerObjectDuplicateOnRay != null)
7923 { 8532 {
7924 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID, dupeOnRay.AgentData.DuplicateFlags, 8533
7925 AgentId, ActiveGroupId, dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd, 8534 UUID rezGroupID = dupeOnRay.AgentData.GroupID;
7926 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast, dupeOnRay.AgentData.RayEndIsIntersection, 8535 if(!IsGroupMember(rezGroupID))
7927 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates); 8536 rezGroupID = UUID.Zero;
8537
8538 handlerObjectDuplicateOnRay(dupeOnRay.ObjectData[i].ObjectLocalID,
8539 dupeOnRay.AgentData.DuplicateFlags, AgentId, rezGroupID,
8540 dupeOnRay.AgentData.RayTargetID, dupeOnRay.AgentData.RayEnd,
8541 dupeOnRay.AgentData.RayStart, dupeOnRay.AgentData.BypassRaycast,
8542 dupeOnRay.AgentData.RayEndIsIntersection,
8543 dupeOnRay.AgentData.CopyCenters, dupeOnRay.AgentData.CopyRotates);
7928 } 8544 }
7929 } 8545 }
7930 8546
@@ -9106,7 +9722,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9106 if ((locX >= m_scene.RegionInfo.WorldLocX) 9722 if ((locX >= m_scene.RegionInfo.WorldLocX)
9107 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX)) 9723 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
9108 && (locY >= m_scene.RegionInfo.WorldLocY) 9724 && (locY >= m_scene.RegionInfo.WorldLocY)
9109 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) ) 9725 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)))
9110 { 9726 {
9111 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle; 9727 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
9112 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX; 9728 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
@@ -9131,6 +9747,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9131 9747
9132 private bool HandleUUIDNameRequest(IClientAPI sender, Packet Pack) 9748 private bool HandleUUIDNameRequest(IClientAPI sender, Packet Pack)
9133 { 9749 {
9750 ScenePresence sp = (ScenePresence)SceneAgent;
9751 if(sp == null || sp.IsDeleted || (sp.IsInTransit && !sp.IsInLocalTransit))
9752 return true;
9753
9134 UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack; 9754 UUIDNameRequestPacket incoming = (UUIDNameRequestPacket)Pack;
9135 9755
9136 foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock) 9756 foreach (UUIDNameRequestPacket.UUIDNameBlockBlock UUIDBlock in incoming.UUIDNameBlock)
@@ -9148,13 +9768,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9148 9768
9149 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 9769 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
9150 { 9770 {
9151 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
9152
9153 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 9771 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
9772
9154 if (handlerRegionHandleRequest != null) 9773 if (handlerRegionHandleRequest != null)
9155 { 9774 {
9775 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
9156 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 9776 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID);
9157 } 9777 }
9778
9158 return true; 9779 return true;
9159 } 9780 }
9160 9781
@@ -9730,6 +10351,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9730 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) 10351 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9731 { 10352 {
9732 int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter)); 10353 int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
10354
9733 OnUpdateEstateAccessDeltaRequest(this, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter))); 10355 OnUpdateEstateAccessDeltaRequest(this, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)));
9734 10356
9735 } 10357 }
@@ -9765,7 +10387,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9765 Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter); 10387 Message = Utils.BytesToString(messagePacket.ParamList[1].Parameter);
9766 } 10388 }
9767 else 10389 else
9768 { 10390 {
9769 SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)); 10391 SenderID = new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter));
9770 SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter); 10392 SenderName = Utils.BytesToString(messagePacket.ParamList[3].Parameter);
9771 Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter); 10393 Message = Utils.BytesToString(messagePacket.ParamList[4].Parameter);
@@ -9907,7 +10529,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9907 return true; 10529 return true;
9908 10530
9909 case "kickestate": 10531 case "kickestate":
9910 10532
9911 if(((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) 10533 if(((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
9912 { 10534 {
9913 UUID invoice = messagePacket.MethodData.Invoice; 10535 UUID invoice = messagePacket.MethodData.Invoice;
@@ -9986,6 +10608,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9986 private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack) 10608 private bool HandleRequestGodlikePowers(IClientAPI sender, Packet Pack)
9987 { 10609 {
9988 RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack; 10610 RequestGodlikePowersPacket rglpPack = (RequestGodlikePowersPacket)Pack;
10611
10612 if (rglpPack.AgentData.SessionID != SessionId ||
10613 rglpPack.AgentData.AgentID != AgentId)
10614 return true;
10615
9989 RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock; 10616 RequestGodlikePowersPacket.RequestBlockBlock rblock = rglpPack.RequestBlock;
9990 UUID token = rblock.Token; 10617 UUID token = rblock.Token;
9991 10618
@@ -9995,7 +10622,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9995 10622
9996 if (handlerReqGodlikePowers != null) 10623 if (handlerReqGodlikePowers != null)
9997 { 10624 {
9998 handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike, this); 10625 handlerReqGodlikePowers(ablock.AgentID, ablock.SessionID, token, rblock.Godlike);
9999 } 10626 }
10000 10627
10001 return true; 10628 return true;
@@ -10006,6 +10633,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10006 GodUpdateRegionInfoPacket GodUpdateRegionInfo = 10633 GodUpdateRegionInfoPacket GodUpdateRegionInfo =
10007 (GodUpdateRegionInfoPacket)Packet; 10634 (GodUpdateRegionInfoPacket)Packet;
10008 10635
10636 if (GodUpdateRegionInfo.AgentData.SessionID != SessionId ||
10637 GodUpdateRegionInfo.AgentData.AgentID != AgentId)
10638 return true;
10639
10009 GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate; 10640 GodUpdateRegionInfoUpdate handlerGodUpdateRegionInfo = OnGodUpdateRegionInfoUpdate;
10010 if (handlerGodUpdateRegionInfo != null) 10641 if (handlerGodUpdateRegionInfo != null)
10011 { 10642 {
@@ -10039,6 +10670,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10039 GodlikeMessagePacket GodlikeMessage = 10670 GodlikeMessagePacket GodlikeMessage =
10040 (GodlikeMessagePacket)Packet; 10671 (GodlikeMessagePacket)Packet;
10041 10672
10673 if (GodlikeMessage.AgentData.SessionID != SessionId ||
10674 GodlikeMessage.AgentData.AgentID != AgentId)
10675 return true;
10676
10042 GodlikeMessage handlerGodlikeMessage = onGodlikeMessage; 10677 GodlikeMessage handlerGodlikeMessage = onGodlikeMessage;
10043 if (handlerGodlikeMessage != null) 10678 if (handlerGodlikeMessage != null)
10044 { 10679 {
@@ -10055,6 +10690,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10055 { 10690 {
10056 StateSavePacket SaveStateMessage = 10691 StateSavePacket SaveStateMessage =
10057 (StateSavePacket)Packet; 10692 (StateSavePacket)Packet;
10693
10694 if (SaveStateMessage.AgentData.SessionID != SessionId ||
10695 SaveStateMessage.AgentData.AgentID != AgentId)
10696 return true;
10697
10058 SaveStateHandler handlerSaveStatePacket = OnSaveState; 10698 SaveStateHandler handlerSaveStatePacket = OnSaveState;
10059 if (handlerSaveStatePacket != null) 10699 if (handlerSaveStatePacket != null)
10060 { 10700 {
@@ -10068,30 +10708,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10068 { 10708 {
10069 GodKickUserPacket gkupack = (GodKickUserPacket)Pack; 10709 GodKickUserPacket gkupack = (GodKickUserPacket)Pack;
10070 10710
10071 if (gkupack.UserInfo.GodSessionID == SessionId && AgentId == gkupack.UserInfo.GodID) 10711 if (gkupack.UserInfo.GodSessionID != SessionId ||
10072 { 10712 gkupack.UserInfo.GodID != AgentId)
10073 GodKickUser handlerGodKickUser = OnGodKickUser; 10713 return true;
10074 if (handlerGodKickUser != null) 10714
10075 { 10715 GodKickUser handlerGodKickUser = OnGodKickUser;
10076 handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.GodSessionID, 10716 if (handlerGodKickUser != null)
10077 gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason);
10078 }
10079 }
10080 else
10081 { 10717 {
10082 SendAgentAlertMessage("Kick request denied", false); 10718 handlerGodKickUser(gkupack.UserInfo.GodID, gkupack.UserInfo.AgentID, gkupack.UserInfo.KickFlags, gkupack.UserInfo.Reason);
10083 } 10719 }
10084 //KickUserPacket kupack = new KickUserPacket();
10085 //KickUserPacket.UserInfoBlock kupackib = kupack.UserInfo;
10086
10087 //kupack.UserInfo.AgentID = gkupack.UserInfo.AgentID;
10088 //kupack.UserInfo.SessionID = gkupack.UserInfo.GodSessionID;
10089 10720
10090 //kupack.TargetBlock.TargetIP = (uint)0;
10091 //kupack.TargetBlock.TargetPort = (ushort)0;
10092 //kupack.UserInfo.Reason = gkupack.UserInfo.Reason;
10093
10094 //OutPacket(kupack, ThrottleOutPacketType.Task);
10095 return true; 10721 return true;
10096 } 10722 }
10097 #endregion GodPackets 10723 #endregion GodPackets
@@ -10410,9 +11036,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10410 } 11036 }
10411 else 11037 else
10412 { 11038 {
10413 SendUseCachedMuteList(); 11039 if(muteListRequest.MuteData.MuteCRC == 0)
11040 SendEmpytMuteList();
11041 else
11042 SendUseCachedMuteList();
10414 } 11043 }
10415 return true; 11044 return true;
10416 } 11045 }
10417 11046
10418 private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet) 11047 private bool HandleUpdateMuteListEntry(IClientAPI client, Packet Packet)
@@ -10425,7 +11054,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10425 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 11054 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
10426 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 11055 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
10427 UpdateMuteListEntry.MuteData.MuteType, 11056 UpdateMuteListEntry.MuteData.MuteType,
10428 UpdateMuteListEntry.AgentData.AgentID); 11057 UpdateMuteListEntry.MuteData.MuteFlags);
10429 return true; 11058 return true;
10430 } 11059 }
10431 return false; 11060 return false;
@@ -10440,8 +11069,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10440 { 11069 {
10441 handlerRemoveMuteListEntry(this, 11070 handlerRemoveMuteListEntry(this,
10442 RemoveMuteListEntry.MuteData.MuteID, 11071 RemoveMuteListEntry.MuteData.MuteID,
10443 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 11072 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
10444 RemoveMuteListEntry.AgentData.AgentID);
10445 return true; 11073 return true;
10446 } 11074 }
10447 return false; 11075 return false;
@@ -10485,16 +11113,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10485 return false; 11113 return false;
10486 } 11114 }
10487 11115
11116 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
11117 {
11118 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
11119 (ChangeInventoryItemFlagsPacket)packet;
11120 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
11121 if (handlerChangeInventoryItemFlags != null)
11122 {
11123 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
11124 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
11125 return true;
11126 }
11127 return false;
11128 }
11129
10488 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 11130 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10489 { 11131 {
10490 return true; 11132 return true;
10491 } 11133 }
10492 11134
11135 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
11136 {
11137 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
11138
11139 #region Packet Session and User Check
11140 if (m_checkPackets)
11141 {
11142 if (packet.AgentData.SessionID != SessionId ||
11143 packet.AgentData.AgentID != AgentId)
11144 return true;
11145 }
11146 #endregion
11147 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
11148 List<InventoryItemBase> items = new List<InventoryItemBase>();
11149 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
11150 {
11151 InventoryItemBase b = new InventoryItemBase();
11152 b.ID = n.OldItemID;
11153 b.Folder = n.OldFolderID;
11154 items.Add(b);
11155 }
11156
11157 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
11158 if (handlerMoveItemsAndLeaveCopy != null)
11159 {
11160 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
11161 }
11162
11163 return true;
11164 }
11165
10493 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 11166 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10494 { 11167 {
10495 return true; 11168 return true;
10496 } 11169 }
10497 11170
11171
10498 private bool HandleInventoryDescendents(IClientAPI sender, Packet Pack) 11172 private bool HandleInventoryDescendents(IClientAPI sender, Packet Pack)
10499 { 11173 {
10500 return true; 11174 return true;
@@ -10748,7 +11422,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10748 if (m_GroupsModule != null) 11422 if (m_GroupsModule != null)
10749 { 11423 {
10750 m_GroupsModule.ActivateGroup(this, activateGroupPacket.AgentData.GroupID); 11424 m_GroupsModule.ActivateGroup(this, activateGroupPacket.AgentData.GroupID);
10751 m_GroupsModule.SendAgentGroupDataUpdate(this);
10752 } 11425 }
10753 return true; 11426 return true;
10754 11427
@@ -10873,11 +11546,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10873 } 11546 }
10874 return true; 11547 return true;
10875 } 11548 }
11549
11550 UUID lastGroupProfileRequestID = UUID.Zero;
11551 double lastGroupProfileRequestTS = Util.GetTimeStampMS();
11552
10876 private bool HandleGroupProfileRequest(IClientAPI sender, Packet Pack) 11553 private bool HandleGroupProfileRequest(IClientAPI sender, Packet Pack)
10877 { 11554 {
11555 if(m_GroupsModule == null)
11556 return true;
11557
10878 GroupProfileRequestPacket groupProfileRequest = 11558 GroupProfileRequestPacket groupProfileRequest =
10879 (GroupProfileRequestPacket)Pack; 11559 (GroupProfileRequestPacket)Pack;
10880 11560
11561
10881 #region Packet Session and User Check 11562 #region Packet Session and User Check
10882 if (m_checkPackets) 11563 if (m_checkPackets)
10883 { 11564 {
@@ -10887,36 +11568,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10887 } 11568 }
10888 #endregion 11569 #endregion
10889 11570
10890 if (m_GroupsModule != null) 11571 UUID grpID = groupProfileRequest.GroupData.GroupID;
10891 { 11572 double ts = Util.GetTimeStampMS();
10892 GroupProfileReplyPacket groupProfileReply = (GroupProfileReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupProfileReply); 11573 if(grpID == lastGroupProfileRequestID && ts - lastGroupProfileRequestTS < 10000)
11574 return true;
10893 11575
10894 groupProfileReply.AgentData = new GroupProfileReplyPacket.AgentDataBlock(); 11576 lastGroupProfileRequestID = grpID;
10895 groupProfileReply.GroupData = new GroupProfileReplyPacket.GroupDataBlock(); 11577 lastGroupProfileRequestTS = ts;
10896 groupProfileReply.AgentData.AgentID = AgentId;
10897 11578
10898 GroupProfileData d = m_GroupsModule.GroupProfileRequest(this, 11579 GroupProfileReplyPacket groupProfileReply = (GroupProfileReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupProfileReply);
10899 groupProfileRequest.GroupData.GroupID);
10900 11580
10901 groupProfileReply.GroupData.GroupID = d.GroupID; 11581 groupProfileReply.AgentData = new GroupProfileReplyPacket.AgentDataBlock();
10902 groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name); 11582 groupProfileReply.GroupData = new GroupProfileReplyPacket.GroupDataBlock();
10903 groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter); 11583 groupProfileReply.AgentData.AgentID = AgentId;
10904 groupProfileReply.GroupData.ShowInList = d.ShowInList;
10905 groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle);
10906 groupProfileReply.GroupData.PowersMask = d.PowersMask;
10907 groupProfileReply.GroupData.InsigniaID = d.InsigniaID;
10908 groupProfileReply.GroupData.FounderID = d.FounderID;
10909 groupProfileReply.GroupData.MembershipFee = d.MembershipFee;
10910 groupProfileReply.GroupData.OpenEnrollment = d.OpenEnrollment;
10911 groupProfileReply.GroupData.Money = d.Money;
10912 groupProfileReply.GroupData.GroupMembershipCount = d.GroupMembershipCount;
10913 groupProfileReply.GroupData.GroupRolesCount = d.GroupRolesCount;
10914 groupProfileReply.GroupData.AllowPublish = d.AllowPublish;
10915 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10916 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10917 11584
10918 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 11585 GroupProfileData d = m_GroupsModule.GroupProfileRequest(this,
11586 groupProfileRequest.GroupData.GroupID);
11587
11588 if(d.GroupID == UUID.Zero) // don't send broken data
11589 return true;
11590
11591 groupProfileReply.GroupData.GroupID = d.GroupID;
11592 groupProfileReply.GroupData.Name = Util.StringToBytes256(d.Name);
11593 groupProfileReply.GroupData.Charter = Util.StringToBytes1024(d.Charter);
11594 groupProfileReply.GroupData.ShowInList = d.ShowInList;
11595 groupProfileReply.GroupData.MemberTitle = Util.StringToBytes256(d.MemberTitle);
11596 groupProfileReply.GroupData.PowersMask = d.PowersMask;
11597 groupProfileReply.GroupData.InsigniaID = d.InsigniaID;
11598 groupProfileReply.GroupData.FounderID = d.FounderID;
11599 groupProfileReply.GroupData.MembershipFee = d.MembershipFee;
11600 groupProfileReply.GroupData.OpenEnrollment = d.OpenEnrollment;
11601 groupProfileReply.GroupData.Money = d.Money;
11602 groupProfileReply.GroupData.GroupMembershipCount = d.GroupMembershipCount;
11603 groupProfileReply.GroupData.GroupRolesCount = d.GroupRolesCount;
11604 groupProfileReply.GroupData.AllowPublish = d.AllowPublish;
11605 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
11606 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
11607
11608 Scene scene = (Scene)m_scene;
11609 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
11610 {
11611 ScenePresence p;
11612 if (scene.TryGetScenePresence(sender.AgentId, out p))
11613 {
11614 if (p.IsViewerUIGod)
11615 {
11616 groupProfileReply.GroupData.OpenEnrollment = true;
11617 groupProfileReply.GroupData.MembershipFee = 0;
11618 }
11619 }
10919 } 11620 }
11621
11622 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
11623
11624 if(grpID == lastGroupProfileRequestID)
11625 lastGroupProfileRequestTS = Util.GetTimeStampMS() - 7000;
11626
10920 return true; 11627 return true;
10921 } 11628 }
10922 private bool HandleGroupMembersRequest(IClientAPI sender, Packet Pack) 11629 private bool HandleGroupMembersRequest(IClientAPI sender, Packet Pack)
@@ -10939,12 +11646,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10939 m_GroupsModule.GroupMembersRequest(this, groupMembersRequestPacket.GroupData.GroupID); 11646 m_GroupsModule.GroupMembersRequest(this, groupMembersRequestPacket.GroupData.GroupID);
10940 11647
10941 int memberCount = members.Count; 11648 int memberCount = members.Count;
10942 11649 int indx = 0;
10943 while (true) 11650 while (indx < memberCount)
10944 { 11651 {
10945 int blockCount = members.Count; 11652 int blockCount = memberCount - indx;
10946 if (blockCount > 40) 11653 if (blockCount > 25)
10947 blockCount = 40; 11654 blockCount = 25;
10948 11655
10949 GroupMembersReplyPacket groupMembersReply = (GroupMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupMembersReply); 11656 GroupMembersReplyPacket groupMembersReply = (GroupMembersReplyPacket)PacketPool.Instance.GetPacket(PacketType.GroupMembersReply);
10950 11657
@@ -10965,8 +11672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10965 11672
10966 for (int i = 0; i < blockCount; i++) 11673 for (int i = 0; i < blockCount; i++)
10967 { 11674 {
10968 GroupMembersData m = members[0]; 11675 GroupMembersData m = members[indx++];
10969 members.RemoveAt(0);
10970 11676
10971 groupMembersReply.MemberData[i] = 11677 groupMembersReply.MemberData[i] =
10972 new GroupMembersReplyPacket.MemberDataBlock(); 11678 new GroupMembersReplyPacket.MemberDataBlock();
@@ -10984,8 +11690,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10984 m.IsOwner; 11690 m.IsOwner;
10985 } 11691 }
10986 OutPacket(groupMembersReply, ThrottleOutPacketType.Task); 11692 OutPacket(groupMembersReply, ThrottleOutPacketType.Task);
10987 if (members.Count == 0)
10988 return true;
10989 } 11693 }
10990 } 11694 }
10991 return true; 11695 return true;
@@ -11488,11 +12192,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11488 12192
11489 StartLure handlerStartLure = OnStartLure; 12193 StartLure handlerStartLure = OnStartLure;
11490 if (handlerStartLure != null) 12194 if (handlerStartLure != null)
11491 handlerStartLure(startLureRequest.Info.LureType, 12195 {
11492 Utils.BytesToString( 12196 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11493 startLureRequest.Info.Message), 12197 {
11494 startLureRequest.TargetData[0].TargetID, 12198 handlerStartLure(startLureRequest.Info.LureType,
11495 this); 12199 Utils.BytesToString(
12200 startLureRequest.Info.Message),
12201 startLureRequest.TargetData[i].TargetID,
12202 this);
12203 }
12204 }
11496 return true; 12205 return true;
11497 } 12206 }
11498 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 12207 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11606,10 +12315,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11606 } 12315 }
11607 #endregion 12316 #endregion
11608 12317
11609 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 12318 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11610 if (handlerClassifiedGodDelete != null) 12319 if (handlerClassifiedGodDelete != null)
11611 handlerClassifiedGodDelete( 12320 handlerClassifiedGodDelete(
11612 classifiedGodDelete.Data.ClassifiedID, 12321 classifiedGodDelete.Data.ClassifiedID,
12322 classifiedGodDelete.Data.QueryID,
11613 this); 12323 this);
11614 return true; 12324 return true;
11615 } 12325 }
@@ -11833,6 +12543,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11833 return true; 12543 return true;
11834 } 12544 }
11835 12545
12546 private bool HandleRevokePermissions(IClientAPI sender, Packet Pack)
12547 {
12548 RevokePermissionsPacket pkt = (RevokePermissionsPacket)Pack;
12549 if (pkt.AgentData.SessionID != SessionId ||
12550 pkt .AgentData.AgentID != AgentId)
12551 return true;
12552
12553 // don't use multidelegate "event"
12554 ScenePresence sp = (ScenePresence)SceneAgent;
12555 if(sp != null && !sp.IsDeleted && !sp.IsInTransit)
12556 {
12557 UUID objectID = pkt.Data.ObjectID;
12558 uint permissions = pkt.Data.ObjectPermissions;
12559
12560 sp.HandleRevokePermissions(objectID , permissions);
12561 }
12562 return true;
12563 }
11836 private bool HandlePlacesQuery(IClientAPI sender, Packet Pack) 12564 private bool HandlePlacesQuery(IClientAPI sender, Packet Pack)
11837 { 12565 {
11838 PlacesQueryPacket placesQueryPacket = 12566 PlacesQueryPacket placesQueryPacket =
@@ -11865,7 +12593,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11865 scriptQuestion.Data.Questions = question; 12593 scriptQuestion.Data.Questions = question;
11866 scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName); 12594 scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName);
11867 scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName); 12595 scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName);
11868 12596
11869 OutPacket(scriptQuestion, ThrottleOutPacketType.Task); 12597 OutPacket(scriptQuestion, ThrottleOutPacketType.Task);
11870 } 12598 }
11871 12599
@@ -11912,86 +12640,52 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11912 /// <param name="simclient"></param> 12640 /// <param name="simclient"></param>
11913 /// <param name="packet"></param> 12641 /// <param name="packet"></param>
11914 /// <returns></returns> 12642 /// <returns></returns>
12643
11915 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 12644 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11916 { 12645 {
12646 //m_log.Debug("texture cached: " + packet.ToString());
11917 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 12647 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11918 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); 12648 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11919 12649
11920 if (cachedtex.AgentData.SessionID != SessionId) 12650 if (cachedtex.AgentData.SessionID != SessionId)
11921 return false; 12651 return false;
11922 12652
11923
11924 // TODO: don't create new blocks if recycling an old packet 12653 // TODO: don't create new blocks if recycling an old packet
11925 cachedresp.AgentData.AgentID = AgentId; 12654 cachedresp.AgentData.AgentID = AgentId;
11926 cachedresp.AgentData.SessionID = m_sessionId; 12655 cachedresp.AgentData.SessionID = m_sessionId;
11927 cachedresp.AgentData.SerialNum = m_cachedTextureSerial; 12656 cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum;
11928 m_cachedTextureSerial++;
11929 cachedresp.WearableData = 12657 cachedresp.WearableData =
11930 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 12658 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11931 12659
11932 int maxWearablesLoop = cachedtex.WearableData.Length; 12660 int cacheHits = 0;
11933 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11934 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11935 12661
11936 // Find the cached baked textures for this user, if they're available 12662 // We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid
11937 12663
11938 IAssetService cache = m_scene.AssetService;
11939 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11940
11941 WearableCacheItem[] cacheItems = null; 12664 WearableCacheItem[] cacheItems = null;
11942 12665
11943 if (bakedTextureModule != null && cache != null) 12666 ScenePresence p = m_scene.GetScenePresence(AgentId);
11944 {
11945 ScenePresence p = m_scene.GetScenePresence(AgentId);
11946 if (p.Appearance != null)
11947 {
11948 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11949 {
11950 try
11951 {
11952 cacheItems = bakedTextureModule.Get(AgentId);
11953 p.Appearance.WearableCacheItems = cacheItems;
11954 p.Appearance.WearableCacheItemsDirty = false;
11955 }
11956 catch (Exception)
11957 {
11958 cacheItems = null;
11959 }
11960 12667
11961 } 12668 if (p != null && p.Appearance != null)
11962 else if (p.Appearance.WearableCacheItems != null) 12669 {
11963 { 12670 cacheItems = p.Appearance.WearableCacheItems;
11964 cacheItems = p.Appearance.WearableCacheItems;
11965 }
11966 }
11967 } 12671 }
11968 12672
12673 int maxWearablesLoop = cachedtex.WearableData.Length;
12674
11969 if (cacheItems != null) 12675 if (cacheItems != null)
11970 { 12676 {
11971 // We need to make sure the asset stored in the bake is available on this server also by its assetid before we map it to a Cacheid. 12677 if (maxWearablesLoop > cacheItems.Length)
11972 // Copy the baked textures to the sim's assets cache (local only). 12678 maxWearablesLoop = cacheItems.Length;
11973 foreach (WearableCacheItem item in cacheItems)
11974 {
11975 if (cache.GetCached(item.TextureID.ToString()) == null)
11976 {
11977 item.TextureAsset.Temporary = true;
11978 item.TextureAsset.Local = true;
11979 cache.Store(item.TextureAsset);
11980 }
11981 }
11982
11983 // Return the cached textures
11984 for (int i = 0; i < maxWearablesLoop; i++) 12679 for (int i = 0; i < maxWearablesLoop; i++)
11985 { 12680 {
11986 WearableCacheItem item = 12681 int idx = cachedtex.WearableData[i].TextureIndex;
11987 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex, cacheItems);
11988
11989 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12682 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11990 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 12683 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11991 cachedresp.WearableData[i].HostName = new byte[0]; 12684 cachedresp.WearableData[i].HostName = new byte[0];
11992 if (item != null && cachedtex.WearableData[i].ID == item.CacheId) 12685 if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId)
11993 { 12686 {
11994 cachedresp.WearableData[i].TextureID = item.TextureID; 12687 cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID;
12688 cacheHits++;
11995 } 12689 }
11996 else 12690 else
11997 { 12691 {
@@ -12001,7 +12695,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12001 } 12695 }
12002 else 12696 else
12003 { 12697 {
12004 // Cached textures not available
12005 for (int i = 0; i < maxWearablesLoop; i++) 12698 for (int i = 0; i < maxWearablesLoop; i++)
12006 { 12699 {
12007 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12700 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
@@ -12010,13 +12703,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12010 cachedresp.WearableData[i].HostName = new byte[0]; 12703 cachedresp.WearableData[i].HostName = new byte[0];
12011 } 12704 }
12012 } 12705 }
12013 12706
12707 //m_log.DebugFormat("texture cached: hits {0}", cacheHits);
12708
12014 cachedresp.Header.Zerocoded = true; 12709 cachedresp.Header.Zerocoded = true;
12015 OutPacket(cachedresp, ThrottleOutPacketType.Task); 12710 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12016 12711
12017 return true; 12712 return true;
12018 } 12713 }
12019 12714
12020 /// <summary> 12715 /// <summary>
12021 /// Send a response back to a client when it asks the asset server (via the region server) if it has 12716 /// Send a response back to a client when it asks the asset server (via the region server) if it has
12022 /// its appearance texture cached. 12717 /// its appearance texture cached.
@@ -12080,209 +12775,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12080 } 12775 }
12081 else 12776 else
12082 { 12777 {
12083// m_log.DebugFormat( 12778 ClientChangeObject updatehandler = onClientChangeObject;
12084// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
12085// i, block.Type, part.Name, part.LocalId);
12086 12779
12087// // Do this once since fetch parts creates a new array. 12780 if (updatehandler != null)
12088// SceneObjectPart[] parts = part.ParentGroup.Parts; 12781 {
12089// for (int j = 0; j < parts.Length; j++) 12782 ObjectChangeData udata = new ObjectChangeData();
12090// {
12091// part.StoreUndoState();
12092// parts[j].IgnoreUndoUpdate = true;
12093// }
12094 12783
12095 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 12784 /*ubit from ll JIRA:
12785 * 0x01 position
12786 * 0x02 rotation
12787 * 0x04 scale
12096 12788
12097 switch (block.Type) 12789 * 0x08 LINK_SET
12098 { 12790 * 0x10 UNIFORM for scale
12099 case 1: 12791 */
12100 Vector3 pos1 = new Vector3(block.Data, 0);
12101 12792
12102 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12793 // translate to internal changes
12103 if (handlerUpdatePrimSinglePosition != null) 12794 // not all cases .. just the ones older code did
12104 {
12105 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
12106 handlerUpdatePrimSinglePosition(localId, pos1, this);
12107 }
12108 break;
12109 12795
12110 case 2: 12796 switch (block.Type)
12111 Quaternion rot1 = new Quaternion(block.Data, 0, true); 12797 {
12798 case 1: //change position sp
12799 udata.position = new Vector3(block.Data, 0);
12112 12800
12113 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 12801 udata.change = ObjectChangeType.primP;
12114 if (handlerUpdatePrimSingleRotation != null) 12802 updatehandler(localId, udata, this);
12115 { 12803 break;
12116 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
12117 handlerUpdatePrimSingleRotation(localId, rot1, this);
12118 }
12119 break;
12120 12804
12121 case 3: 12805 case 2: // rotation sp
12122 Vector3 rotPos = new Vector3(block.Data, 0); 12806 udata.rotation = new Quaternion(block.Data, 0, true);
12123 Quaternion rot2 = new Quaternion(block.Data, 12, true);
12124 12807
12125 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 12808 udata.change = ObjectChangeType.primR;
12126 if (handlerUpdatePrimSingleRotationPosition != null) 12809 updatehandler(localId, udata, this);
12127 { 12810 break;
12128 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
12129 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
12130 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
12131 }
12132 break;
12133 12811
12134 case 4: 12812 case 3: // position plus rotation
12135 case 20: 12813 udata.position = new Vector3(block.Data, 0);
12136 Vector3 scale4 = new Vector3(block.Data, 0); 12814 udata.rotation = new Quaternion(block.Data, 12, true);
12137 12815
12138 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 12816 udata.change = ObjectChangeType.primPR;
12139 if (handlerUpdatePrimScale != null) 12817 updatehandler(localId, udata, this);
12140 { 12818 break;
12141 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
12142 handlerUpdatePrimScale(localId, scale4, this);
12143 }
12144 break;
12145 12819
12146 case 5: 12820 case 4: // scale sp
12147 Vector3 scale1 = new Vector3(block.Data, 12); 12821 udata.scale = new Vector3(block.Data, 0);
12148 Vector3 pos11 = new Vector3(block.Data, 0); 12822 udata.change = ObjectChangeType.primS;
12149 12823
12150 handlerUpdatePrimScale = OnUpdatePrimScale; 12824 updatehandler(localId, udata, this);
12151 if (handlerUpdatePrimScale != null) 12825 break;
12152 {
12153 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12154 handlerUpdatePrimScale(localId, scale1, this);
12155 12826
12156 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12827 case 0x14: // uniform scale sp
12157 if (handlerUpdatePrimSinglePosition != null) 12828 udata.scale = new Vector3(block.Data, 0);
12158 {
12159 handlerUpdatePrimSinglePosition(localId, pos11, this);
12160 }
12161 }
12162 break;
12163 12829
12164 case 9: 12830 udata.change = ObjectChangeType.primUS;
12165 Vector3 pos2 = new Vector3(block.Data, 0); 12831 updatehandler(localId, udata, this);
12832 break;
12166 12833
12167 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 12834 case 5: // scale and position sp
12835 udata.position = new Vector3(block.Data, 0);
12836 udata.scale = new Vector3(block.Data, 12);
12168 12837
12169 if (handlerUpdateVector != null) 12838 udata.change = ObjectChangeType.primPS;
12170 { 12839 updatehandler(localId, udata, this);
12171 handlerUpdateVector(localId, pos2, this); 12840 break;
12172 }
12173 break;
12174 12841
12175 case 10: 12842 case 0x15: //uniform scale and position
12176 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12843 udata.position = new Vector3(block.Data, 0);
12844 udata.scale = new Vector3(block.Data, 12);
12177 12845
12178 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12846 udata.change = ObjectChangeType.primPUS;
12179 if (handlerUpdatePrimRotation != null) 12847 updatehandler(localId, udata, this);
12180 { 12848 break;
12181 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
12182 handlerUpdatePrimRotation(localId, rot3, this);
12183 }
12184 break;
12185 12849
12186 case 11: 12850 // now group related (bit 4)
12187 Vector3 pos3 = new Vector3(block.Data, 0); 12851 case 9: //( 8 + 1 )group position
12188 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12852 udata.position = new Vector3(block.Data, 0);
12189 12853
12190 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12854 udata.change = ObjectChangeType.groupP;
12191 if (handlerUpdatePrimGroupRotation != null) 12855 updatehandler(localId, udata, this);
12192 { 12856 break;
12193 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
12194 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
12195 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
12196 }
12197 break;
12198 case 12:
12199 case 28:
12200 Vector3 scale7 = new Vector3(block.Data, 0);
12201 12857
12202 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12858 case 0x0A: // (8 + 2) group rotation
12203 if (handlerUpdatePrimGroupScale != null) 12859 udata.rotation = new Quaternion(block.Data, 0, true);
12204 {
12205 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
12206 handlerUpdatePrimGroupScale(localId, scale7, this);
12207 }
12208 break;
12209 12860
12210 case 13: 12861 udata.change = ObjectChangeType.groupR;
12211 Vector3 scale2 = new Vector3(block.Data, 12); 12862 updatehandler(localId, udata, this);
12212 Vector3 pos4 = new Vector3(block.Data, 0); 12863 break;
12213 12864
12214 handlerUpdatePrimScale = OnUpdatePrimScale; 12865 case 0x0B: //( 8 + 2 + 1) group rotation and position
12215 if (handlerUpdatePrimScale != null) 12866 udata.position = new Vector3(block.Data, 0);
12216 { 12867 udata.rotation = new Quaternion(block.Data, 12, true);
12217 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12218 handlerUpdatePrimScale(localId, scale2, this);
12219 12868
12220 // Change the position based on scale (for bug number 246) 12869 udata.change = ObjectChangeType.groupPR;
12221 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12870 updatehandler(localId, udata, this);
12222 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12871 break;
12223 if (handlerUpdatePrimSinglePosition != null)
12224 {
12225 handlerUpdatePrimSinglePosition(localId, pos4, this);
12226 }
12227 }
12228 break;
12229 12872
12230 case 29: 12873 case 0x0C: // (8 + 4) group scale
12231 Vector3 scale5 = new Vector3(block.Data, 12); 12874 // only afects root prim and only sent by viewer editor object tab scaling
12232 Vector3 pos5 = new Vector3(block.Data, 0); 12875 // mouse edition only allows uniform scaling
12876 // SL MAY CHANGE THIS in viewers
12233 12877
12234 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12878 udata.scale = new Vector3(block.Data, 0);
12235 if (handlerUpdatePrimGroupScale != null)
12236 {
12237 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12238 part.StoreUndoState(true);
12239 part.IgnoreUndoUpdate = true;
12240 handlerUpdatePrimGroupScale(localId, scale5, this);
12241 handlerUpdateVector = OnUpdatePrimGroupPosition;
12242 12879
12243 if (handlerUpdateVector != null) 12880 udata.change = ObjectChangeType.groupS;
12244 { 12881 updatehandler(localId, udata, this);
12245 handlerUpdateVector(localId, pos5, this);
12246 }
12247 12882
12248 part.IgnoreUndoUpdate = false; 12883 break;
12249 }
12250 12884
12251 break; 12885 case 0x0D: //(8 + 4 + 1) group scale and position
12886 // exception as above
12252 12887
12253 case 21: 12888 udata.position = new Vector3(block.Data, 0);
12254 Vector3 scale6 = new Vector3(block.Data, 12); 12889 udata.scale = new Vector3(block.Data, 12);
12255 Vector3 pos6 = new Vector3(block.Data, 0);
12256 12890
12257 handlerUpdatePrimScale = OnUpdatePrimScale; 12891 udata.change = ObjectChangeType.groupPS;
12258 if (handlerUpdatePrimScale != null) 12892 updatehandler(localId, udata, this);
12259 { 12893 break;
12260 part.StoreUndoState(false);
12261 part.IgnoreUndoUpdate = true;
12262 12894
12263 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12895 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
12264 handlerUpdatePrimScale(localId, scale6, this); 12896 udata.scale = new Vector3(block.Data, 0);
12265 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition;
12266 if (handlerUpdatePrimSinglePosition != null)
12267 {
12268 handlerUpdatePrimSinglePosition(localId, pos6, this);
12269 }
12270 12897
12271 part.IgnoreUndoUpdate = false; 12898 udata.change = ObjectChangeType.groupUS;
12272 } 12899 updatehandler(localId, udata, this);
12273 break; 12900 break;
12274 12901
12275 default: 12902 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
12276 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12903 udata.position = new Vector3(block.Data, 0);
12277 break; 12904 udata.scale = new Vector3(block.Data, 12);
12905
12906 udata.change = ObjectChangeType.groupPUS;
12907 updatehandler(localId, udata, this);
12908 break;
12909
12910 default:
12911 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12912 break;
12913 }
12278 } 12914 }
12279 12915
12280// for (int j = 0; j < parts.Length; j++)
12281// parts[j].IgnoreUndoUpdate = false;
12282 } 12916 }
12283 } 12917 }
12284 } 12918 }
12285
12286 return true; 12919 return true;
12287 } 12920 }
12288 12921
@@ -12342,7 +12975,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12342 /// <param name="throttles"></param> 12975 /// <param name="throttles"></param>
12343 public void SetChildAgentThrottle(byte[] throttles) 12976 public void SetChildAgentThrottle(byte[] throttles)
12344 { 12977 {
12345 m_udpClient.SetThrottles(throttles); 12978 SetChildAgentThrottle(throttles, 1.0f);
12979 }
12980
12981 public void SetChildAgentThrottle(byte[] throttles,float factor)
12982 {
12983 m_udpClient.SetThrottles(throttles, factor);
12984 GenericCall2 handler = OnUpdateThrottles;
12985 if (handler != null)
12986 {
12987 handler();
12988 }
12989 }
12990
12991 /// <summary>
12992 /// Sets the throttles from values supplied caller
12993 /// </summary>
12994 /// <param name="throttles"></param>
12995 public void SetAgentThrottleSilent(int throttle, int setting)
12996 {
12997 m_udpClient.ForceThrottleSetting(throttle,setting);
12998 }
12999
13000 public int GetAgentThrottleSilent(int throttle)
13001 {
13002 return m_udpClient.GetThrottleSetting(throttle);
12346 } 13003 }
12347 13004
12348 /// <summary> 13005 /// <summary>
@@ -12403,9 +13060,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12403 /// provide your own method.</param> 13060 /// provide your own method.</param>
12404 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) 13061 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
12405 { 13062 {
13063
13064/* this is causing packet loss for some reason
13065 if(!m_udpClient.IsConnected)
13066 {
13067 PacketPool.Instance.ReturnPacket(packet);
13068 return;
13069 }
13070*/
12406 if (m_outPacketsToDrop != null) 13071 if (m_outPacketsToDrop != null)
13072 {
12407 if (m_outPacketsToDrop.Contains(packet.Type.ToString())) 13073 if (m_outPacketsToDrop.Contains(packet.Type.ToString()))
13074 {
13075 PacketPool.Instance.ReturnPacket(packet);
12408 return; 13076 return;
13077 }
13078 }
12409 13079
12410 if (DebugPacketLevel > 0) 13080 if (DebugPacketLevel > 0)
12411 { 13081 {
@@ -12424,7 +13094,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12424 13094
12425 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect)) 13095 if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect))
12426 logPacket = false; 13096 logPacket = false;
12427 13097
12428 if (DebugPacketLevel <= 50 13098 if (DebugPacketLevel <= 50
12429 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) 13099 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
12430 logPacket = false; 13100 logPacket = false;
@@ -12437,7 +13107,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12437 "[CLIENT]: PACKET OUT to {0} ({1}) in {2} - {3}", 13107 "[CLIENT]: PACKET OUT to {0} ({1}) in {2} - {3}",
12438 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type); 13108 Name, SceneAgent.IsChildAgent ? "child" : "root ", m_scene.RegionInfo.RegionName, packet.Type);
12439 } 13109 }
12440 13110
12441 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); 13111 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
12442 } 13112 }
12443 13113
@@ -12450,8 +13120,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12450 uint regionY = 0; 13120 uint regionY = 0;
12451 13121
12452 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); 13122 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY);
12453 locx = Convert.ToSingle(args[0]) - (float)regionX; 13123 locx = (float)(Convert.ToDouble(args[0]) - (double)regionX);
12454 locy = Convert.ToSingle(args[1]) - (float)regionY; 13124 locy = (float)(Convert.ToDouble(args[1]) - (double)regionY);
12455 locz = Convert.ToSingle(args[2]); 13125 locz = Convert.ToSingle(args[2]);
12456 13126
12457 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; 13127 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo;
@@ -12677,20 +13347,75 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12677 13347
12678 public void RefreshGroupMembership() 13348 public void RefreshGroupMembership()
12679 { 13349 {
12680 if (m_GroupsModule != null) 13350 lock(m_groupPowers)
12681 { 13351 {
12682 GroupMembershipData[] GroupMembership = 13352 GroupMembershipData activeMembership = null;
13353 if (m_GroupsModule != null)
13354 {
13355 GroupMembershipData[] GroupMembership =
12683 m_GroupsModule.GetMembershipData(AgentId); 13356 m_GroupsModule.GetMembershipData(AgentId);
12684 13357
12685 m_groupPowers.Clear(); 13358 m_groupPowers.Clear();
12686 13359
12687 if (GroupMembership != null) 13360 if (GroupMembership != null)
12688 { 13361 {
12689 for (int i = 0; i < GroupMembership.Length; i++) 13362 for (int i = 0; i < GroupMembership.Length; i++)
13363 {
13364 m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers;
13365 }
13366 }
13367
13368 activeMembership = m_GroupsModule.GetActiveMembershipData(AgentId);
13369 if(activeMembership != null)
12690 { 13370 {
12691 m_groupPowers[GroupMembership[i].GroupID] = GroupMembership[i].GroupPowers; 13371 if(!m_groupPowers.ContainsKey(activeMembership.GroupID))
13372 activeMembership = null;
13373 else
13374 {
13375 m_activeGroupID = activeMembership.GroupID;
13376 m_activeGroupName = activeMembership.GroupName;
13377 m_activeGroupPowers = ActiveGroupPowers;
13378 }
12692 } 13379 }
12693 } 13380 }
13381
13382 if(activeMembership == null)
13383 {
13384 m_activeGroupID = UUID.Zero;
13385 m_activeGroupName = "";
13386 m_activeGroupPowers = 0;
13387 }
13388 }
13389 }
13390
13391 public void UpdateGroupMembership(GroupMembershipData[] data)
13392 {
13393 lock(m_groupPowers)
13394 {
13395 m_groupPowers.Clear();
13396
13397 if (data != null)
13398 {
13399 for (int i = 0; i < data.Length; i++)
13400 m_groupPowers[data[i].GroupID] = data[i].GroupPowers;
13401 }
13402 }
13403 }
13404
13405 public void GroupMembershipRemove(UUID GroupID)
13406 {
13407 lock(m_groupPowers)
13408 {
13409 if(m_groupPowers.ContainsKey(GroupID))
13410 m_groupPowers.Remove(GroupID);
13411 }
13412 }
13413
13414 public void GroupMembershipAddReplace(UUID GroupID,ulong GroupPowers)
13415 {
13416 lock(m_groupPowers)
13417 {
13418 m_groupPowers[GroupID] = GroupPowers;
12694 } 13419 }
12695 } 13420 }
12696 13421
@@ -12736,7 +13461,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12736// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 13461// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12737// requestID, taskID, (SourceType)sourceType, Name); 13462// requestID, taskID, (SourceType)sourceType, Name);
12738 13463
13464
13465 //Note, the bool returned from the below function is useless since it is always false.
12739 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 13466 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
13467
12740 } 13468 }
12741 13469
12742 /// <summary> 13470 /// <summary>
@@ -12782,7 +13510,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12782 SendAssetNotFound(req); 13510 SendAssetNotFound(req);
12783 return; 13511 return;
12784 } 13512 }
12785
12786 } 13513 }
12787 13514
12788 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset) 13515 if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
@@ -12819,7 +13546,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12819 /// <returns></returns> 13546 /// <returns></returns>
12820 private static int CalculateNumPackets(byte[] data) 13547 private static int CalculateNumPackets(byte[] data)
12821 { 13548 {
12822 const uint m_maxPacketSize = 600; 13549// const uint m_maxPacketSize = 600;
13550 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12823 int numPackets = 1; 13551 int numPackets = 1;
12824 13552
12825 if (data == null) 13553 if (data == null)
@@ -12858,11 +13586,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12858 /// </summary> 13586 /// </summary>
12859 public bool Async { get; set; } 13587 public bool Async { get; set; }
12860 13588
12861 /// <summary>
12862 /// If async is true, should this packet be handled in the async engine or given directly to a threadpool
12863 /// thread?
12864 /// </summary>
12865 public bool InEngine { get; set; }
12866 } 13589 }
12867 13590
12868 public class AsyncPacketProcess 13591 public class AsyncPacketProcess
@@ -12930,7 +13653,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12930 // this is the username of the *owner* 13653 // this is the username of the *owner*
12931 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName); 13654 dialog.Data.FirstName = Util.StringToBytes256(ownerFirstName);
12932 dialog.Data.LastName = Util.StringToBytes256(ownerLastName); 13655 dialog.Data.LastName = Util.StringToBytes256(ownerLastName);
12933 dialog.Data.Message = Util.StringToBytes256(message); 13656 dialog.Data.Message = Util.StringToBytes(message,512);
12934 13657
12935 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1]; 13658 ScriptDialogPacket.ButtonsBlock[] buttons = new ScriptDialogPacket.ButtonsBlock[1];
12936 buttons[0] = new ScriptDialogPacket.ButtonsBlock(); 13659 buttons[0] = new ScriptDialogPacket.ButtonsBlock();
@@ -12949,7 +13672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12949 if (p is ScenePresence) 13672 if (p is ScenePresence)
12950 { 13673 {
12951// m_log.DebugFormat( 13674// m_log.DebugFormat(
12952// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}", 13675// "[LLCLIENTVIEW]: Immediately sending terse agent update for {0} to {1} in {2}",
12953// p.Name, Name, Scene.Name); 13676// p.Name, Name, Scene.Name);
12954 13677
12955 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities 13678 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
@@ -12962,8 +13685,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12962 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = 13685 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block =
12963 CreateImprovedTerseBlock(p, false); 13686 CreateImprovedTerseBlock(p, false);
12964 13687
12965 const float TIME_DILATION = 1.0f; 13688// const float TIME_DILATION = 1.0f;
12966 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 13689 ushort timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);;
12967 13690
12968 ImprovedTerseObjectUpdatePacket packet 13691 ImprovedTerseObjectUpdatePacket packet
12969 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( 13692 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
@@ -12986,7 +13709,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12986 PlacesReplyData[] data) 13709 PlacesReplyData[] data)
12987 { 13710 {
12988 PlacesReplyPacket reply = null; 13711 PlacesReplyPacket reply = null;
12989 PlacesReplyPacket.QueryDataBlock[] dataBlocks = 13712 PlacesReplyPacket.QueryDataBlock[] dataBlocks =
12990 new PlacesReplyPacket.QueryDataBlock[0]; 13713 new PlacesReplyPacket.QueryDataBlock[0];
12991 13714
12992 for (int i = 0 ; i < data.Length ; i++) 13715 for (int i = 0 ; i < data.Length ; i++)
@@ -13164,7 +13887,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
13164 foreach (InventoryItemBase item in items) 13887 foreach (InventoryItemBase item in items)
13165 { 13888 {
13166 OSDMap ItemDataMap = new OSDMap(); 13889 OSDMap ItemDataMap = new OSDMap();
13167 13890
13168 ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID)); 13891 ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID));
13169 ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder)); 13892 ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder));
13170 13893
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
index 41dd4d1..deefd40 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -82,7 +82,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
82 82
83 if (pAssetCache != null) 83 if (pAssetCache != null)
84 m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f"); 84 m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f");
85 85
86 if (m_missingImage == null) 86 if (m_missingImage == null)
87 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); 87 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
88 88
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 0394e54..439621a 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -52,7 +52,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 /// are waiting on ACKs for</param> 52 /// are waiting on ACKs for</param>
53 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); 53 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
54 /// <summary> 54 /// <summary>
55 /// Fired when the queue for one or more packet categories is empty. This 55 /// Fired when the queue for one or more packet categories is empty. This
56 /// event can be hooked to put more data on the empty queues 56 /// event can be hooked to put more data on the empty queues
57 /// </summary> 57 /// </summary>
58 /// <param name="category">Categories of the packet queues that are empty</param> 58 /// <param name="category">Categories of the packet queues that are empty</param>
@@ -86,8 +86,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
86 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes. 86 /// Controls whether information is logged about each outbound packet immediately before it is sent. For debug purposes.
87 /// </summary> 87 /// </summary>
88 /// <remarks>Any level above 0 will turn on logging.</remarks> 88 /// <remarks>Any level above 0 will turn on logging.</remarks>
89 public int ThrottleDebugLevel 89 public int ThrottleDebugLevel
90 { 90 {
91 get 91 get
92 { 92 {
93 return m_throttleDebugLevel; 93 return m_throttleDebugLevel;
@@ -96,9 +96,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 set 96 set
97 { 97 {
98 m_throttleDebugLevel = value; 98 m_throttleDebugLevel = value;
99/*
99 m_throttleClient.DebugLevel = m_throttleDebugLevel; 100 m_throttleClient.DebugLevel = m_throttleDebugLevel;
100 foreach (TokenBucket tb in m_throttleCategories) 101 foreach (TokenBucket tb in m_throttleCategories)
101 tb.DebugLevel = m_throttleDebugLevel; 102 tb.DebugLevel = m_throttleDebugLevel;
103 */
102 } 104 }
103 } 105 }
104 private int m_throttleDebugLevel; 106 private int m_throttleDebugLevel;
@@ -118,18 +120,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
118 /// <summary>Circuit code that this client is connected on</summary> 120 /// <summary>Circuit code that this client is connected on</summary>
119 public readonly uint CircuitCode; 121 public readonly uint CircuitCode;
120 /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary> 122 /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary>
121 public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); 123 public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200);
122
123 /// <summary>
124 /// If true then we take action in response to unacked reliably sent packets such as resending the packet.
125 /// </summary>
126 public bool ProcessUnackedSends { get; set; }
127 124
128 /// <summary>Packets we have sent that need to be ACKed by the client</summary> 125 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
129 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 126 public UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
130 127
131 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 128 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
132 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); 129 public DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>();
133 130
134 /// <summary>Current packet sequence number</summary> 131 /// <summary>Current packet sequence number</summary>
135 public int CurrentSequence; 132 public int CurrentSequence;
@@ -160,19 +157,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
160 /// <summary>Number of packets sent to this client</summary> 157 /// <summary>Number of packets sent to this client</summary>
161 public int PacketsSent; 158 public int PacketsSent;
162 /// <summary>Number of packets resent to this client</summary> 159 /// <summary>Number of packets resent to this client</summary>
163 public int PacketsResent; 160 public int PacketsResent;
164 /// <summary>Total byte count of unacked packets sent to this client</summary> 161 /// <summary>Total byte count of unacked packets sent to this client</summary>
165 public int UnackedBytes; 162 public int UnackedBytes;
166 163
164 private int m_packetsUnAckReported;
167 /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary> 165 /// <summary>Total number of received packets that we have reported to the OnPacketStats event(s)</summary>
168 private int m_packetsReceivedReported; 166 private int m_packetsReceivedReported;
169 /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary> 167 /// <summary>Total number of sent packets that we have reported to the OnPacketStats event(s)</summary>
170 private int m_packetsSentReported; 168 private int m_packetsSentReported;
171 /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary> 169 /// <summary>Holds the Environment.TickCount value of when the next OnQueueEmpty can be fired</summary>
172 private int m_nextOnQueueEmpty = 1; 170 private double m_nextOnQueueEmpty = 0;
173 171
174 /// <summary>Throttle bucket for this agent's connection</summary> 172 /// <summary>Throttle bucket for this agent's connection</summary>
175 private readonly AdaptiveTokenBucket m_throttleClient; 173 private AdaptiveTokenBucket m_throttleClient;
176 public AdaptiveTokenBucket FlowThrottle 174 public AdaptiveTokenBucket FlowThrottle
177 { 175 {
178 get { return m_throttleClient; } 176 get { return m_throttleClient; }
@@ -181,10 +179,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 /// <summary>Throttle buckets for each packet category</summary> 179 /// <summary>Throttle buckets for each packet category</summary>
182 private readonly TokenBucket[] m_throttleCategories; 180 private readonly TokenBucket[] m_throttleCategories;
183 /// <summary>Outgoing queues for throttled packets</summary> 181 /// <summary>Outgoing queues for throttled packets</summary>
184 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 182 private DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
185 /// <summary>A container that can hold one packet for each outbox, used to store 183 /// <summary>A container that can hold one packet for each outbox, used to store
186 /// dequeued packets that are being held for throttling</summary> 184 /// dequeued packets that are being held for throttling</summary>
187 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 185 private OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
188 /// <summary>A reference to the LLUDPServer that is managing this client</summary> 186 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
189 private readonly LLUDPServer m_udpServer; 187 private readonly LLUDPServer m_udpServer;
190 188
@@ -193,13 +191,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
193 191
194 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 192 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
195 private int m_maxRTO = 60000; 193 private int m_maxRTO = 60000;
194 public bool m_deliverPackets = true;
195
196 private float m_burstTime;
197
198 public int m_lastStartpingTimeMS;
199 public int m_pingMS;
200
201 public int PingTimeMS
202 {
203 get
204 {
205 if (m_pingMS < 10)
206 return 10;
207 if(m_pingMS > 2000)
208 return 2000;
209 return m_pingMS;
210 }
211 }
196 212
197 /// <summary> 213 /// <summary>
198 /// This is the percentage of the udp texture queue to add to the task queue since 214 /// This is the percentage of the udp texture queue to add to the task queue since
199 /// textures are now generally handled through http. 215 /// textures are now generally handled through http.
200 /// </summary> 216 /// </summary>
201 private double m_cannibalrate = 0.0; 217 private double m_cannibalrate = 0.0;
202 218
203 private ClientInfo m_info = new ClientInfo(); 219 private ClientInfo m_info = new ClientInfo();
204 220
205 /// <summary> 221 /// <summary>
@@ -232,31 +248,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
232 if (maxRTO != 0) 248 if (maxRTO != 0)
233 m_maxRTO = maxRTO; 249 m_maxRTO = maxRTO;
234 250
235 ProcessUnackedSends = true; 251 m_burstTime = rates.BrustTime;
252 float m_burst = rates.ClientMaxRate * m_burstTime;
236 253
237 // Create a token bucket throttle for this client that has the scene token bucket as a parent 254 // Create a token bucket throttle for this client that has the scene token bucket as a parent
238 m_throttleClient 255 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, rates.AdaptiveThrottlesEnabled);
239 = new AdaptiveTokenBucket(
240 string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
241 parentThrottle, 0, rates.Total, rates.MinimumAdaptiveThrottleRate, rates.AdaptiveThrottlesEnabled);
242 256
243 // Create an array of token buckets for this clients different throttle categories 257 // Create an array of token buckets for this clients different throttle categories
244 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 258 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
245 259
246 m_cannibalrate = rates.CannibalizeTextureRate; 260 m_cannibalrate = rates.CannibalizeTextureRate;
247 261
262 m_burst = rates.Total * rates.BrustTime;
263
248 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 264 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
249 { 265 {
250 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 266 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
251 267
252 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 268 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
253 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 269 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
254
255 // Initialize the token buckets that control the throttling for each category 270 // Initialize the token buckets that control the throttling for each category
256 m_throttleCategories[i] 271 m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst);
257 = new TokenBucket(
258 string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name),
259 m_throttleClient, rates.GetRate(type), 0);
260 } 272 }
261 273
262 // Default the retransmission timeout to one second 274 // Default the retransmission timeout to one second
@@ -264,6 +276,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
264 276
265 // Initialize this to a sane value to prevent early disconnects 277 // Initialize this to a sane value to prevent early disconnects
266 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; 278 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
279 m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0;
267 } 280 }
268 281
269 /// <summary> 282 /// <summary>
@@ -280,9 +293,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
280 293
281 // pull the throttle out of the scene throttle 294 // pull the throttle out of the scene throttle
282 m_throttleClient.Parent.UnregisterRequest(m_throttleClient); 295 m_throttleClient.Parent.UnregisterRequest(m_throttleClient);
283 OnPacketStats = null; 296 PendingAcks.Clear();
284 OnQueueEmpty = null; 297 NeedAcks.Clear();
285 } 298 }
286 299
287 /// <summary> 300 /// <summary>
288 /// Gets information about this client connection 301 /// Gets information about this client connection
@@ -302,9 +315,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
302 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 315 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
303 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 316 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
304 m_info.totalThrottle = (int)m_throttleClient.DripRate; 317 m_info.totalThrottle = (int)m_throttleClient.DripRate;
305 m_info.targetThrottle = (int)m_throttleClient.TargetDripRate;
306 m_info.maxThrottle = (int)m_throttleClient.MaxDripRate;
307
308 return m_info; 318 return m_info;
309 } 319 }
310 320
@@ -341,8 +351,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
341 /// <param name="throttleType"></param> 351 /// <param name="throttleType"></param>
342 public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType) 352 public int GetPacketsQueuedCount(ThrottleOutPacketType throttleType)
343 { 353 {
344 if ((int)throttleType > 0) 354 int icat = (int)throttleType;
345 return m_packetOutboxes[(int)throttleType].Count; 355 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
356 return m_packetOutboxes[icat].Count;
346 else 357 else
347 return 0; 358 return 0;
348 } 359 }
@@ -359,7 +370,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
359 return string.Format( 370 return string.Format(
360 "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}", 371 "{0,7} {1,7} {2,7} {3,9} {4,7} {5,7} {6,7} {7,7} {8,7} {9,8} {10,7} {11,7}",
361 Util.EnvironmentTickCountSubtract(TickLastPacketReceived), 372 Util.EnvironmentTickCountSubtract(TickLastPacketReceived),
362 PacketsReceived, 373 PacketsReceived,
363 PacketsSent, 374 PacketsSent,
364 PacketsResent, 375 PacketsResent,
365 UnackedBytes, 376 UnackedBytes,
@@ -379,16 +390,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
379 { 390 {
380 int newPacketsReceived = PacketsReceived - m_packetsReceivedReported; 391 int newPacketsReceived = PacketsReceived - m_packetsReceivedReported;
381 int newPacketsSent = PacketsSent - m_packetsSentReported; 392 int newPacketsSent = PacketsSent - m_packetsSentReported;
382 393 int newPacketUnAck = UnackedBytes - m_packetsUnAckReported;
383 callback(newPacketsReceived, newPacketsSent, UnackedBytes); 394 callback(newPacketsReceived, newPacketsSent, UnackedBytes);
384 395
385 m_packetsReceivedReported += newPacketsReceived; 396 m_packetsReceivedReported += newPacketsReceived;
386 m_packetsSentReported += newPacketsSent; 397 m_packetsSentReported += newPacketsSent;
398 m_packetsUnAckReported += newPacketUnAck;
387 } 399 }
388 } 400 }
389 401
390 public void SetThrottles(byte[] throttleData) 402 public void SetThrottles(byte[] throttleData)
391 { 403 {
404 SetThrottles(throttleData, 1.0f);
405 }
406
407 public void SetThrottles(byte[] throttleData, float factor)
408 {
392 byte[] adjData; 409 byte[] adjData;
393 int pos = 0; 410 int pos = 0;
394 411
@@ -408,24 +425,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
408 } 425 }
409 426
410 // 0.125f converts from bits to bytes 427 // 0.125f converts from bits to bytes
411 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 428 float scale = 0.125f * factor;
412 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 429 int resend = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
413 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 430 int land = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
414 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 431 int wind = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
415 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 432 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
416 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 433 int task = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
417 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 434 int texture = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
435 int asset = (int)(BitConverter.ToSingle(adjData, pos) * scale);
436
418 437
419 if (ThrottleDebugLevel > 0)
420 {
421 long total = resend + land + wind + cloud + task + texture + asset;
422 m_log.DebugFormat(
423 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
424 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
425 }
426 438
427 // Make sure none of the throttles are set below our packet MTU, 439 // Make sure none of the throttles are set below our packet MTU,
428 // otherwise a throttle could become permanently clogged 440 // otherwise a throttle could become permanently clogged
441
442/* now using floats
429 resend = Math.Max(resend, LLUDPServer.MTU); 443 resend = Math.Max(resend, LLUDPServer.MTU);
430 land = Math.Max(land, LLUDPServer.MTU); 444 land = Math.Max(land, LLUDPServer.MTU);
431 wind = Math.Max(wind, LLUDPServer.MTU); 445 wind = Math.Max(wind, LLUDPServer.MTU);
@@ -433,52 +447,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP
433 task = Math.Max(task, LLUDPServer.MTU); 447 task = Math.Max(task, LLUDPServer.MTU);
434 texture = Math.Max(texture, LLUDPServer.MTU); 448 texture = Math.Max(texture, LLUDPServer.MTU);
435 asset = Math.Max(asset, LLUDPServer.MTU); 449 asset = Math.Max(asset, LLUDPServer.MTU);
450*/
436 451
437 // Since most textures are now delivered through http, make it possible 452 // Since most textures are now delivered through http, make it possible
438 // to cannibalize some of the bw from the texture throttle to use for 453 // to cannibalize some of the bw from the texture throttle to use for
439 // the task queue (e.g. object updates) 454 // the task queue (e.g. object updates)
440 task = task + (int)(m_cannibalrate * texture); 455 task = task + (int)(m_cannibalrate * texture);
441 texture = (int)((1 - m_cannibalrate) * texture); 456 texture = (int)((1 - m_cannibalrate) * texture);
442 457
443 //int total = resend + land + wind + cloud + task + texture + asset; 458 int total = resend + land + wind + cloud + task + texture + asset;
459
460 float m_burst = total * m_burstTime;
444 461
445 if (ThrottleDebugLevel > 0) 462 if (ThrottleDebugLevel > 0)
446 { 463 {
447 long total = resend + land + wind + cloud + task + texture + asset;
448 m_log.DebugFormat( 464 m_log.DebugFormat(
449 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}", 465 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
450 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total); 466 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
451 } 467 }
452 468
453 // Update the token buckets with new throttle values
454 if (m_throttleClient.AdaptiveEnabled)
455 {
456 long total = resend + land + wind + cloud + task + texture + asset;
457 m_throttleClient.TargetDripRate = total;
458 }
459
460 TokenBucket bucket; 469 TokenBucket bucket;
461 470
462 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 471 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
463 bucket.RequestedDripRate = resend; 472 bucket.RequestedDripRate = resend;
473 bucket.RequestedBurst = m_burst;
464 474
465 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; 475 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
466 bucket.RequestedDripRate = land; 476 bucket.RequestedDripRate = land;
477 bucket.RequestedBurst = m_burst;
467 478
468 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; 479 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
469 bucket.RequestedDripRate = wind; 480 bucket.RequestedDripRate = wind;
481 bucket.RequestedBurst = m_burst;
470 482
471 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; 483 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
472 bucket.RequestedDripRate = cloud; 484 bucket.RequestedDripRate = cloud;
485 bucket.RequestedBurst = m_burst;
473 486
474 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; 487 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
475 bucket.RequestedDripRate = asset; 488 bucket.RequestedDripRate = asset;
489 bucket.RequestedBurst = m_burst;
476 490
477 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 491 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
478 bucket.RequestedDripRate = task; 492 bucket.RequestedDripRate = task;
493 bucket.RequestedBurst = m_burst;
479 494
480 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 495 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
481 bucket.RequestedDripRate = texture; 496 bucket.RequestedDripRate = texture;
497 bucket.RequestedBurst = m_burst;
482 498
483 // Reset the packed throttles cached data 499 // Reset the packed throttles cached data
484 m_packedThrottles = null; 500 m_packedThrottles = null;
@@ -496,25 +512,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
496 int i = 0; 512 int i = 0;
497 513
498 // multiply by 8 to convert bytes back to bits 514 // multiply by 8 to convert bytes back to bits
499 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier; 515 multiplier *= 8;
516
517 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier;
500 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 518 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
501 519
502 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier; 520 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier;
503 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 521 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
504 522
505 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier; 523 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier;
506 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 524 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
507 525
508 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier; 526 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier;
509 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 527 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
510 528
511 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier; 529 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier;
512 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 530 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
513 531
514 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier; 532 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier;
515 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 533 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
516 534
517 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier; 535 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier;
518 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 536 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
519 537
520 m_packedThrottles = data; 538 m_packedThrottles = data;
@@ -523,43 +541,65 @@ namespace OpenSim.Region.ClientStack.LindenUDP
523 return data; 541 return data;
524 } 542 }
525 543
544 public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS)
545 {
546 int icat = (int)cat;
547 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
548 {
549 TokenBucket bucket = m_throttleCategories[icat];
550 return bucket.GetCatBytesCanSend(timeMS);
551 }
552 else
553 return 0;
554 }
555
526 /// <summary> 556 /// <summary>
527 /// Queue an outgoing packet if appropriate. 557 /// Queue an outgoing packet if appropriate.
528 /// </summary> 558 /// </summary>
529 /// <param name="packet"></param> 559 /// <param name="packet"></param>
530 /// <param name="forceQueue">Always queue the packet if at all possible.</param> 560 /// <param name="forceQueue">Always queue the packet if at all possible.</param>
531 /// <returns> 561 /// <returns>
532 /// true if the packet has been queued, 562 /// true if the packet has been queued,
533 /// false if the packet has not been queued and should be sent immediately. 563 /// false if the packet has not been queued and should be sent immediately.
534 /// </returns> 564 /// </returns>
535 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) 565 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
536 { 566 {
567 return EnqueueOutgoing(packet, forceQueue, false);
568 }
569
570 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
571 {
537 int category = (int)packet.Category; 572 int category = (int)packet.Category;
538 573
539 if (category >= 0 && category < m_packetOutboxes.Length) 574 if (category >= 0 && category < m_packetOutboxes.Length)
540 { 575 {
541 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 576 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
577
578 if (m_deliverPackets == false)
579 {
580 queue.Enqueue(packet, highPriority);
581 return true;
582 }
583
542 TokenBucket bucket = m_throttleCategories[category]; 584 TokenBucket bucket = m_throttleCategories[category];
543 585
544 // Don't send this packet if there is already a packet waiting in the queue 586 // Don't send this packet if queue is not empty
545 // even if we have the tokens to send it, tokens should go to the already 587 if (queue.Count > 0 || m_nextPackets[category] != null)
546 // queued packets
547 if (queue.Count > 0)
548 { 588 {
549 queue.Enqueue(packet); 589 queue.Enqueue(packet, highPriority);
550 return true; 590 return true;
551 } 591 }
552 592
553 593 if (!forceQueue && bucket.CheckTokens(packet.Buffer.DataLength))
554 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
555 { 594 {
556 // Enough tokens were removed from the bucket, the packet will not be queued 595 // enough tokens so it can be sent imediatly by caller
596 bucket.RemoveTokens(packet.Buffer.DataLength);
557 return false; 597 return false;
558 } 598 }
559 else 599 else
560 { 600 {
561 // Force queue specified or not enough tokens in the bucket, queue this packet 601 // Force queue specified or not enough tokens in the bucket, queue this packet
562 queue.Enqueue(packet); 602 queue.Enqueue(packet, highPriority);
563 return true; 603 return true;
564 } 604 }
565 } 605 }
@@ -568,28 +608,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
568 // We don't have a token bucket for this category, so it will not be queued 608 // We don't have a token bucket for this category, so it will not be queued
569 return false; 609 return false;
570 } 610 }
611
571 } 612 }
572 613
573 /// <summary> 614 /// <summary>
574 /// Loops through all of the packet queues for this client and tries to send 615 /// Loops through all of the packet queues for this client and tries to send
575 /// an outgoing packet from each, obeying the throttling bucket limits 616 /// an outgoing packet from each, obeying the throttling bucket limits
576 /// </summary> 617 /// </summary>
577 /// 618 ///
578 /// <remarks> 619 /// <remarks>
579 /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower 620 /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower
580 /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have 621 /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have
581 /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the 622 /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the
582 /// wind queue). 623 /// wind queue).
583 /// 624 ///
584 /// This function is only called from a synchronous loop in the 625 /// This function is only called from a synchronous loop in the
585 /// UDPServer so we don't need to bother making this thread safe 626 /// UDPServer so we don't need to bother making this thread safe
586 /// </remarks> 627 /// </remarks>
587 /// 628 ///
588 /// <returns>True if any packets were sent, otherwise false</returns> 629 /// <returns>True if any packets were sent, otherwise false</returns>
589 public bool DequeueOutgoing() 630 public bool DequeueOutgoing()
590 { 631 {
591 OutgoingPacket packet; 632// if (m_deliverPackets == false) return false;
592 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 633
634 OutgoingPacket packet = null;
635 DoubleLocklessQueue<OutgoingPacket> queue;
593 TokenBucket bucket; 636 TokenBucket bucket;
594 bool packetSent = false; 637 bool packetSent = false;
595 ThrottleOutPacketTypeFlags emptyCategories = 0; 638 ThrottleOutPacketTypeFlags emptyCategories = 0;
@@ -613,6 +656,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
613 m_udpServer.SendPacketFinal(nextPacket); 656 m_udpServer.SendPacketFinal(nextPacket);
614 m_nextPackets[i] = null; 657 m_nextPackets[i] = null;
615 packetSent = true; 658 packetSent = true;
659
660 if (m_packetOutboxes[i].Count < 5)
661 emptyCategories |= CategoryToFlag(i);
616 } 662 }
617 } 663 }
618 else 664 else
@@ -620,32 +666,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP
620 // No dequeued packet waiting to be sent, try to pull one off 666 // No dequeued packet waiting to be sent, try to pull one off
621 // this queue 667 // this queue
622 queue = m_packetOutboxes[i]; 668 queue = m_packetOutboxes[i];
623 if (queue.Dequeue(out packet)) 669 if (queue != null)
624 { 670 {
625 // A packet was pulled off the queue. See if we have 671 bool success = false;
626 // enough tokens in the bucket to send it out 672 try
627 if (bucket.RemoveTokens(packet.Buffer.DataLength))
628 { 673 {
629 // Send the packet 674 success = queue.Dequeue(out packet);
630 m_udpServer.SendPacketFinal(packet);
631 packetSent = true;
632 } 675 }
633 else 676 catch
634 { 677 {
635 // Save the dequeued packet for the next iteration 678 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
636 m_nextPackets[i] = packet;
637 } 679 }
680 if (success)
681 {
682 // A packet was pulled off the queue. See if we have
683 // enough tokens in the bucket to send it out
684 if (bucket.RemoveTokens(packet.Buffer.DataLength))
685 {
686 // Send the packet
687 m_udpServer.SendPacketFinal(packet);
688 packetSent = true;
689
690 if (queue.Count < 5)
691 emptyCategories |= CategoryToFlag(i);
692 }
693 else
694 {
695 // Save the dequeued packet for the next iteration
696 m_nextPackets[i] = packet;
697 }
638 698
639 // If the queue is empty after this dequeue, fire the queue 699 }
640 // empty callback now so it has a chance to fill before we 700 else
641 // get back here 701 {
642 if (queue.Count == 0) 702 // No packets in this queue. Fire the queue empty callback
703 // if it has not been called recently
643 emptyCategories |= CategoryToFlag(i); 704 emptyCategories |= CategoryToFlag(i);
705 }
644 } 706 }
645 else 707 else
646 { 708 {
647 // No packets in this queue. Fire the queue empty callback 709 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
648 // if it has not been called recently
649 emptyCategories |= CategoryToFlag(i); 710 emptyCategories |= CategoryToFlag(i);
650 } 711 }
651 } 712 }
@@ -712,6 +773,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
712 RTO = Math.Min(RTO * 2, m_maxRTO); 773 RTO = Math.Min(RTO * 2, m_maxRTO);
713 } 774 }
714 775
776 const double MIN_CALLBACK_MS = 20.0;
777 private bool m_isQueueEmptyRunning;
778
715 /// <summary> 779 /// <summary>
716 /// Does an early check to see if this queue empty callback is already 780 /// Does an early check to see if this queue empty callback is already
717 /// running, then asynchronously firing the event 781 /// running, then asynchronously firing the event
@@ -719,44 +783,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
719 /// <param name="categories">Throttle categories to fire the callback for</param> 783 /// <param name="categories">Throttle categories to fire the callback for</param>
720 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 784 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
721 { 785 {
722// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 786 if (!m_isQueueEmptyRunning)
723 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
724 { 787 {
725 m_isQueueEmptyRunning = true; 788 if (!HasUpdates(categories))
789 return;
726 790
727 int start = Environment.TickCount & Int32.MaxValue; 791 double start = Util.GetTimeStampMS();
728 const int MIN_CALLBACK_MS = 30; 792 if (start < m_nextOnQueueEmpty)
793 return;
729 794
795 m_isQueueEmptyRunning = true;
730 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 796 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
731 if (m_nextOnQueueEmpty == 0)
732 m_nextOnQueueEmpty = 1;
733 797
734 // Use a value of 0 to signal that FireQueueEmpty is running 798 // Asynchronously run the callback
735// m_nextOnQueueEmpty = 0; 799 if (m_udpServer.OqrEngine.IsRunning)
736 800 m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories));
737 m_categories = categories;
738
739 if (HasUpdates(m_categories))
740 {
741 if (!m_udpServer.OqrEngine.IsRunning)
742 {
743 // Asynchronously run the callback
744 Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty");
745 }
746 else
747 {
748 m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => FireQueueEmpty(categories));
749 }
750 }
751 else 801 else
752 { 802 Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty");
753 m_isQueueEmptyRunning = false;
754 }
755 } 803 }
756 } 804 }
757 805
758 private bool m_isQueueEmptyRunning; 806
759 private ThrottleOutPacketTypeFlags m_categories = 0;
760 807
761 /// <summary> 808 /// <summary>
762 /// Fires the OnQueueEmpty callback and sets the minimum time that it 809 /// Fires the OnQueueEmpty callback and sets the minimum time that it
@@ -767,33 +814,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
767 /// signature</param> 814 /// signature</param>
768 public void FireQueueEmpty(object o) 815 public void FireQueueEmpty(object o)
769 { 816 {
770// m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name); 817 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
771 818 QueueEmpty callback = OnQueueEmpty;
772// int start = Environment.TickCount & Int32.MaxValue;
773// const int MIN_CALLBACK_MS = 30;
774 819
775// if (m_udpServer.IsRunningOutbound) 820 if (callback != null)
776// { 821 {
777 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 822 // if (m_udpServer.IsRunningOutbound)
778 QueueEmpty callback = OnQueueEmpty; 823 // {
779 824 try { callback(categories); }
780 if (callback != null) 825 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
781 { 826 // }
782// if (m_udpServer.IsRunningOutbound) 827 }
783// {
784 try { callback(categories); }
785 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
786// }
787 }
788// }
789 828
790// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 829 m_isQueueEmptyRunning = false;
791// if (m_nextOnQueueEmpty == 0) 830 }
792// m_nextOnQueueEmpty = 1;
793 831
794// } 832 internal void ForceThrottleSetting(int throttle, int setting)
833 {
834 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
835 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU);
836 }
795 837
796 m_isQueueEmptyRunning = false; 838 internal int GetThrottleSetting(int throttle)
839 {
840 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
841 return (int)m_throttleCategories[throttle].RequestedDripRate;
842 else
843 return 0;
797 } 844 }
798 845
799 /// <summary> 846 /// <summary>
@@ -839,4 +886,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
839 } 886 }
840 } 887 }
841 } 888 }
889
890 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
891 {
892 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
893
894 public override int Count
895 {
896 get
897 {
898 return base.Count + highQueue.Count;
899 }
900 }
901
902 public override bool Dequeue(out T item)
903 {
904 if (highQueue.Dequeue(out item))
905 return true;
906
907 return base.Dequeue(out item);
908 }
909
910 public void Enqueue(T item, bool highPriority)
911 {
912 if (highPriority)
913 highQueue.Enqueue(item);
914 else
915 Enqueue(item);
916 }
917 }
842} 918}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4528714..b575ed9 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -51,60 +51,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
51 /// A shim around LLUDPServer that implements the IClientNetworkServer interface 51 /// A shim around LLUDPServer that implements the IClientNetworkServer interface
52 /// </summary> 52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")] 53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")]
54 public sealed class LLUDPServerShim : INonSharedRegionModule 54 public class LLUDPServerShim : INonSharedRegionModule
55 { 55 {
56 private bool m_Enabled = true; 56 protected IConfigSource m_Config;
57 private IConfigSource m_Config; 57 protected LLUDPServer m_udpServer;
58 LLUDPServer m_udpServer;
59 58
60 #region INonSharedRegionModule 59 #region INonSharedRegionModule
61 public string Name 60 public virtual string Name
62 { 61 {
63 get { return "LLUDPServerShim"; } 62 get { return "LLUDPServerShim"; }
64 } 63 }
65 64
66 public Type ReplaceableInterface 65 public virtual Type ReplaceableInterface
67 { 66 {
68 get { return null; } 67 get { return null; }
69 } 68 }
70 69
71 public void Initialise(IConfigSource source) 70 public virtual void Initialise(IConfigSource source)
72 { 71 {
73 m_Config = source; 72 m_Config = source;
74 } 73 }
75 74
76 public void Close() 75 public virtual void Close()
77 { 76 {
78 } 77 }
79 78
80 public void AddRegion(Scene scene) 79 public virtual void AddRegion(Scene scene)
81 { 80 {
82 uint port = (uint)scene.RegionInfo.InternalEndPoint.Port; 81 uint port = (uint)scene.RegionInfo.InternalEndPoint.Port;
83 82
84 IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address; 83 IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address;
85 Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, scene.RegionInfo.m_allow_alternate_ports, m_Config, scene.AuthenticateHandler); 84 Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, m_Config, scene.AuthenticateHandler);
86 scene.RegionInfo.InternalEndPoint.Port = (int)port; 85 scene.RegionInfo.InternalEndPoint.Port = (int)port;
87 86
88 AddScene(scene); 87 AddScene(scene);
89 } 88 }
90 89
91 public void RemoveRegion(Scene scene) 90 public virtual void RemoveRegion(Scene scene)
92 { 91 {
93 Stop(); 92 Stop();
94 } 93 }
95 94
96 public void RegionLoaded(Scene scene) 95 public virtual void RegionLoaded(Scene scene)
97 { 96 {
98 Start(); 97 Start();
99 } 98 }
100 #endregion 99 #endregion
101 100
102 public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 101 public virtual void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager)
103 { 102 {
104 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 103 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, configSource, circuitManager);
105 } 104 }
106 105
107 public void AddScene(IScene scene) 106 public virtual void AddScene(IScene scene)
108 { 107 {
109 m_udpServer.AddScene(scene); 108 m_udpServer.AddScene(scene);
110 109
@@ -223,22 +222,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
223 StatType.Pull, 222 StatType.Pull,
224 MeasuresOfInterest.None, 223 MeasuresOfInterest.None,
225 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod, 224 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod,
226// stat => 225// stat =>
227// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7), 226// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7),
228 StatVerbosity.Debug)); 227 StatVerbosity.Debug));
229 } 228 }
230 229
231 public bool HandlesRegion(Location x) 230 public virtual bool HandlesRegion(Location x)
232 { 231 {
233 return m_udpServer.HandlesRegion(x); 232 return m_udpServer.HandlesRegion(x);
234 } 233 }
235 234
236 public void Start() 235 public virtual void Start()
237 { 236 {
238 m_udpServer.Start(); 237 m_udpServer.Start();
239 } 238 }
240 239
241 public void Stop() 240 public virtual void Stop()
242 { 241 {
243 m_udpServer.Stop(); 242 m_udpServer.Stop();
244 } 243 }
@@ -257,7 +256,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
257 public const int MTU = 1400; 256 public const int MTU = 1400;
258 257
259 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> 258 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
260 public int ClientLogoutsDueToNoReceives { get; private set; } 259 public int ClientLogoutsDueToNoReceives { get; protected set; }
261 260
262 /// <summary> 261 /// <summary>
263 /// Default packet debug level given to new clients 262 /// Default packet debug level given to new clients
@@ -273,7 +272,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
273 /// <summary>The measured resolution of Environment.TickCount</summary> 272 /// <summary>The measured resolution of Environment.TickCount</summary>
274 public readonly float TickCountResolution; 273 public readonly float TickCountResolution;
275 274
276 /// <summary>Number of prim updates to put on the queue each time the 275 /// <summary>Number of prim updates to put on the queue each time the
277 /// OnQueueEmpty event is triggered for updates</summary> 276 /// OnQueueEmpty event is triggered for updates</summary>
278 public readonly int PrimUpdatesPerCallback; 277 public readonly int PrimUpdatesPerCallback;
279 278
@@ -284,54 +283,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP
284 /// <summary>Handlers for incoming packets</summary> 283 /// <summary>Handlers for incoming packets</summary>
285 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 284 //PacketEventDictionary packetEvents = new PacketEventDictionary();
286 /// <summary>Incoming packets that are awaiting handling</summary> 285 /// <summary>Incoming packets that are awaiting handling</summary>
287 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 286 //protected OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
287
288 protected OpenSim.Framework.BlockingQueue<IncomingPacket> packetInbox = new OpenSim.Framework.BlockingQueue<IncomingPacket>();
288 289
289 /// <summary>Bandwidth throttle for this UDP server</summary> 290 /// <summary>Bandwidth throttle for this UDP server</summary>
290 public TokenBucket Throttle { get; private set; } 291 public TokenBucket Throttle { get; protected set; }
291 292
292 /// <summary>Per client throttle rates enforced by this server</summary> 293 /// <summary>Per client throttle rates enforced by this server</summary>
293 /// <remarks> 294 /// <remarks>
294 /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have. 295 /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have.
295 /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually 296 /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually
296 /// do get changed immediately). They do not need to sum to the total. 297 /// do get changed immediately). They do not need to sum to the total.
297 /// </remarks> 298 /// </remarks>
298 public ThrottleRates ThrottleRates { get; private set; } 299 public ThrottleRates ThrottleRates { get; protected set; }
299 300
300 /// <summary>Manages authentication for agent circuits</summary> 301 /// <summary>Manages authentication for agent circuits</summary>
301 private AgentCircuitManager m_circuitManager; 302 protected AgentCircuitManager m_circuitManager;
302 303
303 /// <summary>Reference to the scene this UDP server is attached to</summary> 304 /// <summary>Reference to the scene this UDP server is attached to</summary>
304 public Scene Scene { get; private set; } 305 public Scene Scene { get; protected set; }
305 306
306 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 307 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
307 private Location m_location; 308 protected Location m_location;
308 309
309 /// <summary>The size of the receive buffer for the UDP socket. This value 310 /// <summary>The size of the receive buffer for the UDP socket. This value
310 /// is passed up to the operating system and used in the system networking 311 /// is passed up to the operating system and used in the system networking
311 /// stack. Use zero to leave this value as the default</summary> 312 /// stack. Use zero to leave this value as the default</summary>
312 private int m_recvBufferSize; 313 protected int m_recvBufferSize;
313
314 /// <summary>Flag to process packets asynchronously or synchronously</summary>
315 private bool m_asyncPacketHandling;
316 314
317 /// <summary>Tracks whether or not a packet was sent each round so we know 315 /// <summary>Tracks whether or not a packet was sent each round so we know
318 /// whether or not to sleep</summary> 316 /// whether or not to sleep</summary>
319 private bool m_packetSent; 317 protected bool m_packetSent;
320 318
321 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> 319 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
322 private int m_elapsedMSSinceLastStatReport = 0; 320 protected int m_elapsedMSSinceLastStatReport = 0;
323 321
324 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> 322 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
325 private int m_tickLastOutgoingPacketHandler; 323 protected double m_tickLastOutgoingPacketHandler;
326 324
327 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> 325 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
328 private int m_elapsedMSOutgoingPacketHandler; 326 protected double m_elapsedMSOutgoingPacketHandler;
329 327
330 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> 328 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
331 private int m_elapsed100MSOutgoingPacketHandler; 329 protected int m_elapsed100MSOutgoingPacketHandler;
332 330
333 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> 331 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
334 private int m_elapsed500MSOutgoingPacketHandler; 332 protected int m_elapsed500MSOutgoingPacketHandler;
335 333
336 /// <summary>Flag to signal when clients should check for resends</summary> 334 /// <summary>Flag to signal when clients should check for resends</summary>
337 protected bool m_resendUnacked; 335 protected bool m_resendUnacked;
@@ -342,32 +340,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
342 /// <summary>Flag to signal when clients should send pings</summary> 340 /// <summary>Flag to signal when clients should send pings</summary>
343 protected bool m_sendPing; 341 protected bool m_sendPing;
344 342
345 /// <summary> 343 protected int m_animationSequenceNumber;
346 /// Event used to signal when queued packets are available for sending.
347 /// </summary>
348 /// <remarks>
349 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
350 /// Some data is sent immediately and not queued. That data would not trigger this event.
351 /// </remarks>
352 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
353 344
354 private Pool<IncomingPacket> m_incomingPacketPool; 345 public int NextAnimationSequenceNumber
346 {
347 get
348 {
349 m_animationSequenceNumber++;
350 if (m_animationSequenceNumber > 2147482624)
351 m_animationSequenceNumber = 1;
352 return m_animationSequenceNumber;
353 }
354 }
355
356 protected ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
357
358 protected Pool<IncomingPacket> m_incomingPacketPool;
355 359
356 /// <summary> 360 /// <summary>
357 /// Stat for number of packets in the main pool awaiting use. 361 /// Stat for number of packets in the main pool awaiting use.
358 /// </summary> 362 /// </summary>
359 private Stat m_poolCountStat; 363 protected Stat m_poolCountStat;
360 364
361 /// <summary> 365 /// <summary>
362 /// Stat for number of packets in the inbound packet pool awaiting use. 366 /// Stat for number of packets in the inbound packet pool awaiting use.
363 /// </summary> 367 /// </summary>
364 private Stat m_incomingPacketPoolStat; 368 protected Stat m_incomingPacketPoolStat;
365 369
366 private int m_defaultRTO = 0; 370 protected int m_defaultRTO = 0;
367 private int m_maxRTO = 0; 371 protected int m_maxRTO = 0;
368 private int m_ackTimeout = 0; 372 protected int m_ackTimeout = 0;
369 private int m_pausedAckTimeout = 0; 373 protected int m_pausedAckTimeout = 0;
370 private bool m_disableFacelights = false; 374 protected bool m_disableFacelights = false;
371 375
372 public Socket Server { get { return null; } } 376 public Socket Server { get { return null; } }
373 377
@@ -389,28 +393,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
389 /// <summary> 393 /// <summary>
390 /// Record how many inbound packets could not be recognized as LLUDP packets. 394 /// Record how many inbound packets could not be recognized as LLUDP packets.
391 /// </summary> 395 /// </summary>
392 public int IncomingMalformedPacketCount { get; private set; } 396 public int IncomingMalformedPacketCount { get; protected set; }
393 397
394 /// <summary> 398 /// <summary>
395 /// Record how many inbound packets could not be associated with a simulator circuit. 399 /// Record how many inbound packets could not be associated with a simulator circuit.
396 /// </summary> 400 /// </summary>
397 public int IncomingOrphanedPacketCount { get; private set; } 401 public int IncomingOrphanedPacketCount { get; protected set; }
398 402
399 /// <summary> 403 /// <summary>
400 /// Record current outgoing client for monitoring purposes. 404 /// Record current outgoing client for monitoring purposes.
401 /// </summary> 405 /// </summary>
402 private IClientAPI m_currentOutgoingClient; 406 protected IClientAPI m_currentOutgoingClient;
403 407
404 /// <summary> 408 /// <summary>
405 /// Recording current incoming client for monitoring purposes. 409 /// Recording current incoming client for monitoring purposes.
406 /// </summary> 410 /// </summary>
407 private IClientAPI m_currentIncomingClient; 411 protected IClientAPI m_currentIncomingClient;
408 412
409 /// <summary> 413 /// <summary>
410 /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available 414 /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available
411 /// threadpool threads. 415 /// threadpool threads.
412 /// </summary> 416 /// </summary>
413 public JobEngine IpahEngine { get; private set; } 417// public JobEngine IpahEngine { get; protected set; }
414 418
415 /// <summary> 419 /// <summary>
416 /// Run queue empty processing within a single persistent thread. 420 /// Run queue empty processing within a single persistent thread.
@@ -420,27 +424,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP
420 /// connection schedule its own job in the threadpool which causes performance problems when there are many 424 /// connection schedule its own job in the threadpool which causes performance problems when there are many
421 /// connections. 425 /// connections.
422 /// </remarks> 426 /// </remarks>
423 public JobEngine OqrEngine { get; private set; } 427 public JobEngine OqrEngine { get; protected set; }
424 428
425 public LLUDPServer( 429 public LLUDPServer(
426 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, 430 IPAddress listenIP, ref uint port, int proxyPortOffsetParm,
427 IConfigSource configSource, AgentCircuitManager circuitManager) 431 IConfigSource configSource, AgentCircuitManager circuitManager)
428 : base(listenIP, (int)port) 432 : base(listenIP, (int)port)
429 { 433 {
430 #region Environment.TickCount Measurement 434 #region Environment.TickCount Measurement
431 435
436 // Update the port with the one we actually got
437 port = (uint)Port;
438
432 // Measure the resolution of Environment.TickCount 439 // Measure the resolution of Environment.TickCount
433 TickCountResolution = 0f; 440 TickCountResolution = 0f;
434 for (int i = 0; i < 5; i++) 441 for (int i = 0; i < 10; i++)
435 { 442 {
436 int start = Environment.TickCount; 443 int start = Environment.TickCount;
437 int now = start; 444 int now = start;
438 while (now == start) 445 while (now == start)
439 now = Environment.TickCount; 446 now = Environment.TickCount;
440 TickCountResolution += (float)(now - start) * 0.2f; 447 TickCountResolution += (float)(now - start);
448 }
449 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution * 0.1f + "ms");
450
451 TickCountResolution = 0f;
452 for (int i = 0; i < 100; i++)
453 {
454 double start = Util.GetTimeStampMS();
455 double now = start;
456 while (now == start)
457 now = Util.GetTimeStampMS();
458 TickCountResolution += (float)((now - start));
441 } 459 }
442 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); 460
443 TickCountResolution = (float)Math.Ceiling(TickCountResolution); 461 TickCountResolution = (float)Math.Round(TickCountResolution * 0.01f,6,MidpointRounding.AwayFromZero);
462 m_log.Info("[LLUDPSERVER]: Average Util.GetTimeStampMS resolution: " + TickCountResolution + "ms");
444 463
445 #endregion Environment.TickCount Measurement 464 #endregion Environment.TickCount Measurement
446 465
@@ -451,7 +470,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
451 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 470 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
452 if (config != null) 471 if (config != null)
453 { 472 {
454 m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true);
455 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); 473 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
456 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); 474 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
457 475
@@ -494,24 +512,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
494 } 512 }
495 #endregion BinaryStats 513 #endregion BinaryStats
496 514
497 // FIXME: Can't add info here because don't know scene yet. 515 Throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f);
498// m_throttle
499// = new TokenBucket(
500// string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps);
501
502 Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps);
503
504 ThrottleRates = new ThrottleRates(configSource); 516 ThrottleRates = new ThrottleRates(configSource);
505 517
506 if (usePools) 518 Random rnd = new Random(Util.EnvironmentTickCount());
507 EnablePools(); 519 m_animationSequenceNumber = rnd.Next(11474826);
520
521// if (usePools)
522// EnablePools();
523 base.DisablePools();
508 } 524 }
509 525
510 public void Start() 526 public void Start()
511 { 527 {
512 StartInbound(); 528 StartInbound();
513 StartOutbound(); 529 StartOutbound();
514 IpahEngine.Start(); 530// IpahEngine.Start();
515 OqrEngine.Start(); 531 OqrEngine.Start();
516 532
517 m_elapsedMSSinceLastStatReport = Environment.TickCount; 533 m_elapsedMSSinceLastStatReport = Environment.TickCount;
@@ -520,10 +536,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
520 public void StartInbound() 536 public void StartInbound()
521 { 537 {
522 m_log.InfoFormat( 538 m_log.InfoFormat(
523 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", 539 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server");
524 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
525 540
526 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); 541 base.StartInbound(m_recvBufferSize);
527 542
528 // This thread will process the packets received that are placed on the packetInbox 543 // This thread will process the packets received that are placed on the packetInbox
529 WorkManager.StartThread( 544 WorkManager.StartThread(
@@ -557,7 +572,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
557 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name); 572 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
558 base.StopOutbound(); 573 base.StopOutbound();
559 base.StopInbound(); 574 base.StopInbound();
560 IpahEngine.Stop(); 575// IpahEngine.Stop();
561 OqrEngine.Stop(); 576 OqrEngine.Stop();
562 } 577 }
563 578
@@ -642,7 +657,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
642 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. 657 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
643 /// </summary> 658 /// </summary>
644 /// <returns></returns> 659 /// <returns></returns>
645 private string GetWatchdogIncomingAlarmData() 660 protected string GetWatchdogIncomingAlarmData()
646 { 661 {
647 return string.Format( 662 return string.Format(
648 "Client is {0}", 663 "Client is {0}",
@@ -653,7 +668,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
653 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. 668 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
654 /// </summary> 669 /// </summary>
655 /// <returns></returns> 670 /// <returns></returns>
656 private string GetWatchdogOutgoingAlarmData() 671 protected string GetWatchdogOutgoingAlarmData()
657 { 672 {
658 return string.Format( 673 return string.Format(
659 "Client is {0}", 674 "Client is {0}",
@@ -676,15 +691,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
676 691
677 Scene = (Scene)scene; 692 Scene = (Scene)scene;
678 m_location = new Location(Scene.RegionInfo.RegionHandle); 693 m_location = new Location(Scene.RegionInfo.RegionHandle);
679 694/*
680 IpahEngine 695 IpahEngine
681 = new JobEngine( 696 = new JobEngine(
682 string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name), 697 string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name),
683 "INCOMING PACKET ASYNC HANDLING ENGINE"); 698 "INCOMING PACKET ASYNC HANDLING ENGINE");
684 699*/
685 OqrEngine 700 OqrEngine
686 = new JobEngine( 701 = new JobEngine(
687 string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name), 702 string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name),
688 "OUTGOING QUEUE REFILL ENGINE"); 703 "OUTGOING QUEUE REFILL ENGINE");
689 704
690 StatsManager.RegisterStat( 705 StatsManager.RegisterStat(
@@ -697,7 +712,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
697 scene.Name, 712 scene.Name,
698 StatType.Pull, 713 StatType.Pull,
699 MeasuresOfInterest.AverageChangeOverTime, 714 MeasuresOfInterest.AverageChangeOverTime,
700 stat => stat.Value = packetInbox.Count, 715 stat => stat.Value = packetInbox.Count(),
701 StatVerbosity.Debug)); 716 StatVerbosity.Debug));
702 717
703 // XXX: These stats are also pool stats but we register them separately since they are currently not 718 // XXX: These stats are also pool stats but we register them separately since they are currently not
@@ -710,9 +725,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
710 "clientstack", 725 "clientstack",
711 Scene.Name, 726 Scene.Name,
712 StatType.Pull, 727 StatType.Pull,
713 stat => 728 stat =>
714 { PercentageStat pstat = (PercentageStat)stat; 729 { PercentageStat pstat = (PercentageStat)stat;
715 pstat.Consequent = PacketPool.Instance.PacketsRequested; 730 pstat.Consequent = PacketPool.Instance.PacketsRequested;
716 pstat.Antecedent = PacketPool.Instance.PacketsReused; }, 731 pstat.Antecedent = PacketPool.Instance.PacketsReused; },
717 StatVerbosity.Debug)); 732 StatVerbosity.Debug));
718 733
@@ -725,8 +740,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
725 Scene.Name, 740 Scene.Name,
726 StatType.Pull, 741 StatType.Pull,
727 stat => 742 stat =>
728 { PercentageStat pstat = (PercentageStat)stat; 743 { PercentageStat pstat = (PercentageStat)stat;
729 pstat.Consequent = PacketPool.Instance.BlocksRequested; 744 pstat.Consequent = PacketPool.Instance.BlocksRequested;
730 pstat.Antecedent = PacketPool.Instance.BlocksReused; }, 745 pstat.Antecedent = PacketPool.Instance.BlocksReused; },
731 StatVerbosity.Debug)); 746 StatVerbosity.Debug));
732 747
@@ -766,7 +781,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
766 MeasuresOfInterest.AverageChangeOverTime, 781 MeasuresOfInterest.AverageChangeOverTime,
767 stat => stat.Value = GetTotalQueuedOutgoingPackets(), 782 stat => stat.Value = GetTotalQueuedOutgoingPackets(),
768 StatVerbosity.Info)); 783 StatVerbosity.Info));
769 784/*
770 StatsManager.RegisterStat( 785 StatsManager.RegisterStat(
771 new Stat( 786 new Stat(
772 "IncomingPacketAsyncRequestsWaiting", 787 "IncomingPacketAsyncRequestsWaiting",
@@ -779,7 +794,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
779 MeasuresOfInterest.None, 794 MeasuresOfInterest.None,
780 stat => stat.Value = IpahEngine.JobsWaiting, 795 stat => stat.Value = IpahEngine.JobsWaiting,
781 StatVerbosity.Debug)); 796 StatVerbosity.Debug));
782 797*/
783 StatsManager.RegisterStat( 798 StatsManager.RegisterStat(
784 new Stat( 799 new Stat(
785 "OQRERequestsWaiting", 800 "OQRERequestsWaiting",
@@ -792,14 +807,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
792 MeasuresOfInterest.None, 807 MeasuresOfInterest.None,
793 stat => stat.Value = OqrEngine.JobsWaiting, 808 stat => stat.Value = OqrEngine.JobsWaiting,
794 StatVerbosity.Debug)); 809 StatVerbosity.Debug));
795 810
796 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by 811 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
797 // scene name 812 // scene name
798 if (UsePools) 813 if (UsePools)
799 EnablePoolStats(); 814 EnablePoolStats();
800 815
816
801 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); 817 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
802 commands.Register(); 818 commands.Register();
819
803 } 820 }
804 821
805 public bool HandlesRegion(Location x) 822 public bool HandlesRegion(Location x)
@@ -906,9 +923,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
906 } 923 }
907 924
908 PacketPool.Instance.ReturnPacket(packet); 925 PacketPool.Instance.ReturnPacket(packet);
909
910 if (packetQueued)
911 m_dataPresentEvent.Set();
912 } 926 }
913 927
914 /// <summary> 928 /// <summary>
@@ -969,8 +983,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
969 bufferSize = dataLength; 983 bufferSize = dataLength;
970 buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); 984 buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
971 985
972 // m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + 986 m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
973 // type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); 987 type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length);
974 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 988 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
975 } 989 }
976 } 990 }
@@ -979,35 +993,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
979 993
980 #region Queue or Send 994 #region Queue or Send
981 995
996 bool highPriority = false;
997
998 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
999 {
1000 category = (ThrottleOutPacketType)((int)category & 127);
1001 highPriority = true;
1002 }
1003
982 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 1004 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
983 1005
984 // If we were not provided a method for handling unacked, use the UDPServer default method 1006 // If we were not provided a method for handling unacked, use the UDPServer default method
985 if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) 1007 if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0)
986 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 1008 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
987 1009
988 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will 1010 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
989 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 1011 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
990 // packet so that it isn't sent before a queued update packet. 1012 // packet so that it isn't sent before a queued update packet.
991 bool forceQueue = (type == PacketType.KillObject);
992 1013
993// if (type == PacketType.ImprovedTerseObjectUpdate) 1014 bool requestQueue = type == PacketType.KillObject;
994// { 1015 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
995// m_log.DebugFormat("Direct send ITOU to {0} in {1}", udpClient.AgentID, Scene.Name);
996// SendPacketFinal(outgoingPacket);
997// return false;
998// }
999// else
1000// {
1001 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue))
1002 { 1016 {
1003 SendPacketFinal(outgoingPacket); 1017 SendPacketFinal(outgoingPacket);
1004 return true; 1018 return true;
1005 } 1019 }
1006 else 1020
1007 { 1021 return false;
1008 return false;
1009 }
1010// }
1011 1022
1012 #endregion Queue or Send 1023 #endregion Queue or Send
1013 } 1024 }
@@ -1048,6 +1059,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1048 pc.PingID.OldestUnacked = 0; 1059 pc.PingID.OldestUnacked = 0;
1049 1060
1050 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); 1061 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1062 udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1051 } 1063 }
1052 1064
1053 public void CompletePing(LLUDPClient udpClient, byte pingID) 1065 public void CompletePing(LLUDPClient udpClient, byte pingID)
@@ -1145,7 +1157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1145 int dataLength = buffer.DataLength; 1157 int dataLength = buffer.DataLength;
1146 1158
1147 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here 1159 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
1148 if (!isZerocoded) 1160 if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null)
1149 { 1161 {
1150 // Keep appending ACKs until there is no room left in the buffer or there are 1162 // Keep appending ACKs until there is no room left in the buffer or there are
1151 // no more ACKs to append 1163 // no more ACKs to append
@@ -1180,7 +1192,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1180 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); 1192 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
1181 outgoingPacket.SequenceNumber = sequenceNumber; 1193 outgoingPacket.SequenceNumber = sequenceNumber;
1182 1194
1183 if (udpClient.ProcessUnackedSends && isReliable) 1195 if (isReliable)
1184 { 1196 {
1185 // Add this packet to the list of ACK responses we are waiting on from the server 1197 // Add this packet to the list of ACK responses we are waiting on from the server
1186 udpClient.NeedAcks.Add(outgoingPacket); 1198 udpClient.NeedAcks.Add(outgoingPacket);
@@ -1210,13 +1222,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name); 1222 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
1211 1223
1212 // Put the UDP payload on the wire 1224 // Put the UDP payload on the wire
1213 AsyncBeginSend(buffer); 1225// AsyncBeginSend(buffer);
1226 SyncSend(buffer);
1214 1227
1215 // Keep track of when this packet was sent out (right now) 1228 // Keep track of when this packet was sent out (right now)
1216 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1229 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1217 } 1230 }
1218 1231
1219 private void RecordMalformedInboundPacket(IPEndPoint endPoint) 1232 protected void RecordMalformedInboundPacket(IPEndPoint endPoint)
1220 { 1233 {
1221// if (m_malformedCount < 100) 1234// if (m_malformedCount < 100)
1222// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1235// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
@@ -1225,7 +1238,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1225 1238
1226 if ((IncomingMalformedPacketCount % 10000) == 0) 1239 if ((IncomingMalformedPacketCount % 10000) == 0)
1227 m_log.WarnFormat( 1240 m_log.WarnFormat(
1228 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", 1241 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1229 IncomingMalformedPacketCount, endPoint); 1242 IncomingMalformedPacketCount, endPoint);
1230 } 1243 }
1231 1244
@@ -1311,35 +1324,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1311 1324
1312 #region Packet to Client Mapping 1325 #region Packet to Client Mapping
1313 1326
1314 // UseCircuitCode handling 1327 // If there is already a client for this endpoint, don't process UseCircuitCode
1315 if (packet.Type == PacketType.UseCircuitCode) 1328 IClientAPI client = null;
1329 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1316 { 1330 {
1317 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1331 // UseCircuitCode handling
1318 // buffer. 1332 if (packet.Type == PacketType.UseCircuitCode)
1319 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1333 {
1334 // And if there is a UseCircuitCode pending, also drop it
1335 lock (m_pendingCache)
1336 {
1337 if (m_pendingCache.Contains(endPoint))
1338 return;
1320 1339
1321 Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode"); 1340 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1341 }
1322 1342
1323 return; 1343 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1344 // buffer.
1345 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1346
1347 Util.FireAndForget(HandleUseCircuitCode, array);
1348
1349 return;
1350 }
1324 } 1351 }
1325 else if (packet.Type == PacketType.CompleteAgentMovement) 1352
1353 // If this is a pending connection, enqueue, don't process yet
1354 lock (m_pendingCache)
1326 { 1355 {
1327 // Send ack straight away to let the viewer know that we got it. 1356 Queue<UDPPacketBuffer> queue;
1328 SendAckImmediate(endPoint, packet.Header.Sequence); 1357 if (m_pendingCache.TryGetValue(endPoint, out queue))
1358 {
1359 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1360 queue.Enqueue(buffer);
1361 return;
1362 }
1329 1363
1330 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1364/*
1331 // buffer. 1365 else if (packet.Type == PacketType.CompleteAgentMovement)
1332 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1366 {
1367 // Send ack straight away to let the viewer know that we got it.
1368 SendAckImmediate(endPoint, packet.Header.Sequence);
1333 1369
1334 Util.FireAndForget( 1370 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1335 HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion"); 1371 // buffer.
1372 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1336 1373
1337 return; 1374 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1375
1376 return;
1377 }
1378 */
1338 } 1379 }
1339 1380
1340 // Determine which agent this packet came from 1381 // Determine which agent this packet came from
1341 IClientAPI client; 1382 if (client == null || !(client is LLClientView))
1342 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1343 { 1383 {
1344 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1384 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1345 1385
@@ -1347,7 +1387,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1347 1387
1348 if ((IncomingOrphanedPacketCount % 10000) == 0) 1388 if ((IncomingOrphanedPacketCount % 10000) == 0)
1349 m_log.WarnFormat( 1389 m_log.WarnFormat(
1350 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", 1390 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1351 IncomingOrphanedPacketCount, endPoint); 1391 IncomingOrphanedPacketCount, endPoint);
1352 1392
1353 return; 1393 return;
@@ -1356,7 +1396,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1356 udpClient = ((LLClientView)client).UDPClient; 1396 udpClient = ((LLClientView)client).UDPClient;
1357 1397
1358 if (!udpClient.IsConnected) 1398 if (!udpClient.IsConnected)
1399 {
1400 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + Scene.RegionInfo.RegionName);
1359 return; 1401 return;
1402 }
1360 1403
1361 #endregion Packet to Client Mapping 1404 #endregion Packet to Client Mapping
1362 1405
@@ -1368,37 +1411,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1368 1411
1369 #region ACK Receiving 1412 #region ACK Receiving
1370 1413
1371 if (udpClient.ProcessUnackedSends) 1414 // Handle appended ACKs
1415 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1372 { 1416 {
1373 // Handle appended ACKs 1417 // m_log.DebugFormat(
1374 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 1418 // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1375 { 1419 // packet.Header.AckList.Length, client.Name, m_scene.Name);
1376 // m_log.DebugFormat(
1377 // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1378 // packet.Header.AckList.Length, client.Name, m_scene.Name);
1379 1420
1380 for (int i = 0; i < packet.Header.AckList.Length; i++) 1421 for (int i = 0; i < packet.Header.AckList.Length; i++)
1381 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); 1422 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
1382 } 1423 }
1383 1424
1384 // Handle PacketAck packets 1425 // Handle PacketAck packets
1385 if (packet.Type == PacketType.PacketAck) 1426 if (packet.Type == PacketType.PacketAck)
1386 { 1427 {
1387 PacketAckPacket ackPacket = (PacketAckPacket)packet; 1428 PacketAckPacket ackPacket = (PacketAckPacket)packet;
1388 1429
1389 // m_log.DebugFormat( 1430 // m_log.DebugFormat(
1390 // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}", 1431 // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
1391 // ackPacket.Packets.Length, client.Name, m_scene.Name); 1432 // ackPacket.Packets.Length, client.Name, m_scene.Name);
1392 1433
1393 for (int i = 0; i < ackPacket.Packets.Length; i++) 1434 for (int i = 0; i < ackPacket.Packets.Length; i++)
1394 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); 1435 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
1395 1436
1396 // We don't need to do anything else with PacketAck packets 1437 // We don't need to do anything else with PacketAck packets
1397 return;
1398 }
1399 }
1400 else if (packet.Type == PacketType.PacketAck)
1401 {
1402 return; 1438 return;
1403 } 1439 }
1404 1440
@@ -1442,7 +1478,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1442 { 1478 {
1443 if (packet.Header.Resent) 1479 if (packet.Header.Resent)
1444 m_log.DebugFormat( 1480 m_log.DebugFormat(
1445 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}", 1481 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
1446 packet.Header.Sequence, packet.Type, client.Name); 1482 packet.Header.Sequence, packet.Type, client.Name);
1447 else 1483 else
1448 m_log.WarnFormat( 1484 m_log.WarnFormat(
@@ -1459,24 +1495,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1459 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1495 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1460 #endregion BinaryStats 1496 #endregion BinaryStats
1461 1497
1462 if (packet.Type == PacketType.AgentUpdate)
1463 {
1464 if (DiscardInboundAgentUpdates)
1465 return;
1466 1498
1467 ((LLClientView)client).TotalAgentUpdates++; 1499//AgentUpdate removed from here
1468 1500
1469 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1470
1471 LLClientView llClient = client as LLClientView;
1472 if (agentUpdate.AgentData.SessionID != client.SessionId
1473 || agentUpdate.AgentData.AgentID != client.AgentId
1474 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1475 {
1476 PacketPool.Instance.ReturnPacket(packet);
1477 return;
1478 }
1479 }
1480 1501
1481 #region Ping Check Handling 1502 #region Ping Check Handling
1482 1503
@@ -1497,7 +1518,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1497 } 1518 }
1498 else if (packet.Type == PacketType.CompletePingCheck) 1519 else if (packet.Type == PacketType.CompletePingCheck)
1499 { 1520 {
1500 // We don't currently track client ping times 1521 int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1522 int c = udpClient.m_pingMS;
1523 c = 800 * c + 200 * t;
1524 c /= 1000;
1525 udpClient.m_pingMS = c;
1501 return; 1526 return;
1502 } 1527 }
1503 1528
@@ -1517,7 +1542,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1517 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1542 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1518 } 1543 }
1519 1544
1520 packetInbox.Enqueue(incomingPacket); 1545// if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1546// incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1547 if (incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1548 packetInbox.PriorityEnqueue(incomingPacket);
1549 else
1550 packetInbox.Enqueue(incomingPacket);
1551
1521 } 1552 }
1522 1553
1523 #region BinaryStats 1554 #region BinaryStats
@@ -1627,14 +1658,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1627 1658
1628 #endregion BinaryStats 1659 #endregion BinaryStats
1629 1660
1630 private void HandleUseCircuitCode(object o) 1661 protected void HandleUseCircuitCode(object o)
1631 { 1662 {
1632 IPEndPoint endPoint = null; 1663 IPEndPoint endPoint = null;
1633 IClientAPI client = null; 1664 IClientAPI client = null;
1634 1665
1635 try 1666 try
1636 { 1667 {
1637 // DateTime startTime = DateTime.Now; 1668// DateTime startTime = DateTime.Now;
1638 object[] array = (object[])o; 1669 object[] array = (object[])o;
1639 endPoint = (IPEndPoint)array[0]; 1670 endPoint = (IPEndPoint)array[0];
1640 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1671 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
@@ -1642,10 +1673,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1642 m_log.DebugFormat( 1673 m_log.DebugFormat(
1643 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1674 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1644 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint); 1675 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1645 1676
1646 AuthenticateResponse sessionInfo; 1677 AuthenticateResponse sessionInfo;
1647 if (IsClientAuthorized(uccp, out sessionInfo)) 1678 if (IsClientAuthorized(uccp, out sessionInfo))
1648 { 1679 {
1680 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1681
1649 // Begin the process of adding the client to the simulator 1682 // Begin the process of adding the client to the simulator
1650 client 1683 client
1651 = AddClient( 1684 = AddClient(
@@ -1654,20 +1687,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1654 uccp.CircuitCode.SessionID, 1687 uccp.CircuitCode.SessionID,
1655 endPoint, 1688 endPoint,
1656 sessionInfo); 1689 sessionInfo);
1657 1690
1691 // This will be true if the client is new, e.g. not
1692 // an existing child agent, and there is no circuit data
1693 if (client != null && aCircuit == null)
1694 {
1695 Scene.CloseAgent(client.AgentId, true);
1696 return;
1697 }
1698
1699 // Now we know we can handle more data
1700 Thread.Sleep(200);
1701
1702 // Obtain the pending queue and remove it from the cache
1703 Queue<UDPPacketBuffer> queue = null;
1704
1705 lock (m_pendingCache)
1706 {
1707 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1708 {
1709 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1710 return;
1711
1712 }
1713 m_pendingCache.Remove(endPoint);
1714 }
1715
1716 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1717
1718 // Reinject queued packets
1719 while (queue.Count > 0)
1720 {
1721 UDPPacketBuffer buf = queue.Dequeue();
1722 PacketReceived(buf);
1723 }
1724
1725 queue = null;
1726
1658 // Send ack straight away to let the viewer know that the connection is active. 1727 // Send ack straight away to let the viewer know that the connection is active.
1659 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1728 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1660 // circuit code to the existing child agent. This is not particularly obvious. 1729 // circuit code to the existing child agent. This is not particularly obvious.
1661 SendAckImmediate(endPoint, uccp.Header.Sequence); 1730 SendAckImmediate(endPoint, uccp.Header.Sequence);
1662 1731
1663 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1732 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1664 if (client != null) 1733 if (client != null)
1665 { 1734 {
1666 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1667 bool tp = (aCircuit.teleportFlags > 0); 1735 bool tp = (aCircuit.teleportFlags > 0);
1668 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from 1736 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1669 if (!tp && !client.SceneAgent.SentInitialDataToClient) 1737 if (!tp)
1670 client.SceneAgent.SendInitialDataToClient(); 1738 client.SceneAgent.SendInitialDataToMe();
1671 } 1739 }
1672 } 1740 }
1673 else 1741 else
@@ -1675,11 +1743,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1675 // Don't create clients for unauthorized requesters. 1743 // Don't create clients for unauthorized requesters.
1676 m_log.WarnFormat( 1744 m_log.WarnFormat(
1677 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1745 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1746
1678 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1747 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1748
1749 lock (m_pendingCache)
1750 m_pendingCache.Remove(endPoint);
1679 } 1751 }
1680 1752
1681 // m_log.DebugFormat( 1753 // m_log.DebugFormat(
1682 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", 1754 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1683 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); 1755 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
1684 1756
1685 } 1757 }
@@ -1694,8 +1766,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 e.StackTrace); 1766 e.StackTrace);
1695 } 1767 }
1696 } 1768 }
1697 1769/*
1698 private void HandleCompleteMovementIntoRegion(object o) 1770 protected void HandleCompleteMovementIntoRegion(object o)
1699 { 1771 {
1700 IPEndPoint endPoint = null; 1772 IPEndPoint endPoint = null;
1701 IClientAPI client = null; 1773 IClientAPI client = null;
@@ -1711,9 +1783,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1711 1783
1712 // Determine which agent this packet came from 1784 // Determine which agent this packet came from
1713 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination 1785 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1714 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode 1786 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1715 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these 1787 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1716 // packets asynchronously, we need to account for this thread proceeding more quickly than the 1788 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1717 // UseCircuitCode thread. 1789 // UseCircuitCode thread.
1718 int count = 40; 1790 int count = 40;
1719 while (count-- > 0) 1791 while (count-- > 0)
@@ -1735,7 +1807,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1735 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too 1807 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1736 // eager, then the new ScenePresence may not have registered a listener for this messsage 1808 // eager, then the new ScenePresence may not have registered a listener for this messsage
1737 // before we try to process it. 1809 // before we try to process it.
1738 // XXX: A better long term fix may be to add the SceneAgent before the client is added to 1810 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1739 // the client manager 1811 // the client manager
1740 m_log.DebugFormat( 1812 m_log.DebugFormat(
1741 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", 1813 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
@@ -1749,7 +1821,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1749 else 1821 else
1750 { 1822 {
1751 m_log.DebugFormat( 1823 m_log.DebugFormat(
1752 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", 1824 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1753 endPoint, Scene.Name); 1825 endPoint, Scene.Name);
1754 } 1826 }
1755 1827
@@ -1804,6 +1876,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1804 e.StackTrace); 1876 e.StackTrace);
1805 } 1877 }
1806 } 1878 }
1879*/
1807 1880
1808 /// <summary> 1881 /// <summary>
1809 /// Send an ack immediately to the given endpoint. 1882 /// Send an ack immediately to the given endpoint.
@@ -1814,7 +1887,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1814 /// </remarks> 1887 /// </remarks>
1815 /// <param name="remoteEndpoint"></param> 1888 /// <param name="remoteEndpoint"></param>
1816 /// <param name="sequenceNumber"></param> 1889 /// <param name="sequenceNumber"></param>
1817 private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) 1890 protected void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
1818 { 1891 {
1819 PacketAckPacket ack = new PacketAckPacket(); 1892 PacketAckPacket ack = new PacketAckPacket();
1820 ack.Header.Reliable = false; 1893 ack.Header.Reliable = false;
@@ -1835,10 +1908,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1835 1908
1836 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); 1909 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
1837 1910
1838 AsyncBeginSend(buffer); 1911// AsyncBeginSend(buffer);
1912 SyncSend(buffer);
1839 } 1913 }
1840 1914
1841 private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) 1915 protected bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo)
1842 { 1916 {
1843 UUID agentID = useCircuitCode.CircuitCode.ID; 1917 UUID agentID = useCircuitCode.CircuitCode.ID;
1844 UUID sessionID = useCircuitCode.CircuitCode.SessionID; 1918 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
@@ -1861,6 +1935,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1861 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 1935 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
1862 { 1936 {
1863 IClientAPI client = null; 1937 IClientAPI client = null;
1938 bool createNew = false;
1864 1939
1865 // We currently synchronize this code across the whole scene to avoid issues such as 1940 // We currently synchronize this code across the whole scene to avoid issues such as
1866 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done 1941 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
@@ -1869,14 +1944,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1869 { 1944 {
1870 if (!Scene.TryGetClient(agentID, out client)) 1945 if (!Scene.TryGetClient(agentID, out client))
1871 { 1946 {
1947 createNew = true;
1948 }
1949 else
1950 {
1951 if (client.SceneAgent == null)
1952 {
1953 Scene.CloseAgent(agentID, true);
1954 createNew = true;
1955 }
1956 }
1957
1958 if (createNew)
1959 {
1872 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1960 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1873 1961
1962
1874 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1963 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1875 client.OnLogout += LogoutHandler; 1964 client.OnLogout += LogoutHandler;
1876 client.DebugPacketLevel = DefaultClientPacketDebugLevel; 1965 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1877 1966
1878 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1967 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1879 1968
1880 client.Start(); 1969 client.Start();
1881 } 1970 }
1882 } 1971 }
@@ -1893,56 +1982,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1893 /// </remarks> 1982 /// </remarks>
1894 /// <param name='client'></param> 1983 /// <param name='client'></param>
1895 /// <param name='timeoutTicks'></param> 1984 /// <param name='timeoutTicks'></param>
1896 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) 1985 protected void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1897 { 1986 {
1898 lock (client.CloseSyncLock) 1987 lock (client.CloseSyncLock)
1899 { 1988 {
1900 ClientLogoutsDueToNoReceives++; 1989 ClientLogoutsDueToNoReceives++;
1901 1990
1902 m_log.WarnFormat( 1991 if (client.SceneAgent != null)
1903 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", 1992 {
1904 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name); 1993 m_log.WarnFormat(
1905 1994 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1906 if (!client.SceneAgent.IsChildAgent) 1995 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
1907 client.Kick("Simulator logged you out due to connection timeout."); 1996
1997 if (!client.SceneAgent.IsChildAgent)
1998 client.Kick("Simulator logged you out due to connection timeout.");
1999 }
1908 } 2000 }
1909 2001
1910 Scene.CloseAgent(client.AgentId, true); 2002 if (!Scene.CloseAgent(client.AgentId, true))
2003 client.Close(true,true);
1911 } 2004 }
1912 2005
1913 private void IncomingPacketHandler() 2006 protected void IncomingPacketHandler()
1914 { 2007 {
1915 Thread.CurrentThread.Priority = ThreadPriority.Highest; 2008 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1916 2009 IncomingPacket incomingPacket;
1917 // Set this culture for the thread that incoming packets are received 2010 // Set this culture for the thread that incoming packets are received
1918 // on to en-US to avoid number parsing issues 2011 // on to en-US to avoid number parsing issues
1919 Culture.SetCurrentCulture(); 2012 Culture.SetCurrentCulture();
1920 2013
1921 while (IsRunningInbound) 2014 while (IsRunningInbound)
1922 { 2015 {
2016 Scene.ThreadAlive(1);
1923 try 2017 try
1924 { 2018 {
1925 IncomingPacket incomingPacket = null; 2019 incomingPacket = packetInbox.Dequeue(250);
1926
1927 /*
1928 // HACK: This is a test to try and rate limit packet handling on Mono.
1929 // If it works, a more elegant solution can be devised
1930 if (Util.FireAndForgetCount() < 2)
1931 {
1932 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1933 Thread.Sleep(30);
1934 }
1935 */
1936 2020
1937 if (packetInbox.Dequeue(100, ref incomingPacket)) 2021 if (incomingPacket != null && IsRunningInbound)
1938 { 2022 {
1939 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); 2023 ProcessInPacket(incomingPacket);
1940 2024
1941 if (UsePools) 2025 if (UsePools)
2026 {
2027 incomingPacket.Client = null;
1942 m_incomingPacketPool.ReturnObject(incomingPacket); 2028 m_incomingPacketPool.ReturnObject(incomingPacket);
2029 }
2030 incomingPacket = null;
1943 } 2031 }
1944 } 2032 }
1945 catch (Exception ex) 2033 catch(Exception ex)
1946 { 2034 {
1947 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); 2035 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
1948 } 2036 }
@@ -1950,14 +2038,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1950 Watchdog.UpdateThread(); 2038 Watchdog.UpdateThread();
1951 } 2039 }
1952 2040
1953 if (packetInbox.Count > 0) 2041 if (packetInbox.Count() > 0)
1954 m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count + " packets"); 2042 m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count() + " packets");
1955 packetInbox.Clear(); 2043 packetInbox.Clear();
1956 2044
1957 Watchdog.RemoveThread(); 2045 Watchdog.RemoveThread();
1958 } 2046 }
1959 2047
1960 private void OutgoingPacketHandler() 2048 protected void OutgoingPacketHandler()
1961 { 2049 {
1962 Thread.CurrentThread.Priority = ThreadPriority.Highest; 2050 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1963 2051
@@ -1971,6 +2059,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1971 2059
1972 while (base.IsRunningOutbound) 2060 while (base.IsRunningOutbound)
1973 { 2061 {
2062 Scene.ThreadAlive(2);
2063
2064
1974 try 2065 try
1975 { 2066 {
1976 m_packetSent = false; 2067 m_packetSent = false;
@@ -1982,19 +2073,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1982 m_sendPing = false; 2073 m_sendPing = false;
1983 2074
1984 // Update elapsed time 2075 // Update elapsed time
1985 int thisTick = Environment.TickCount & Int32.MaxValue; 2076 double thisTick = Util.GetTimeStampMS();
1986 if (m_tickLastOutgoingPacketHandler > thisTick)
1987 m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick);
1988 else
1989 m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler);
1990 2077
2078 // update some 1ms resolution chained timers
2079 m_elapsedMSOutgoingPacketHandler += thisTick - m_tickLastOutgoingPacketHandler;
1991 m_tickLastOutgoingPacketHandler = thisTick; 2080 m_tickLastOutgoingPacketHandler = thisTick;
1992 2081
1993 // Check for pending outgoing resends every 100ms 2082 // Check for pending outgoing resends every 100ms
1994 if (m_elapsedMSOutgoingPacketHandler >= 100) 2083 if (m_elapsedMSOutgoingPacketHandler >= 100.0)
1995 { 2084 {
1996 m_resendUnacked = true; 2085 m_resendUnacked = true;
1997 m_elapsedMSOutgoingPacketHandler = 0; 2086 m_elapsedMSOutgoingPacketHandler = 0.0;
1998 m_elapsed100MSOutgoingPacketHandler += 1; 2087 m_elapsed100MSOutgoingPacketHandler += 1;
1999 } 2088 }
2000 2089
@@ -2012,15 +2101,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2012 m_sendPing = true; 2101 m_sendPing = true;
2013 m_elapsed500MSOutgoingPacketHandler = 0; 2102 m_elapsed500MSOutgoingPacketHandler = 0;
2014 } 2103 }
2015
2016 #endregion Update Timers 2104 #endregion Update Timers
2017 2105
2018 // Use this for emergency monitoring -- bug hunting
2019 //if (m_scene.EmergencyMonitoring)
2020 // clientPacketHandler = MonitoredClientOutgoingPacketHandler;
2021 //else
2022 // clientPacketHandler = ClientOutgoingPacketHandler;
2023
2024 // Handle outgoing packets, resends, acknowledgements, and pings for each 2106 // Handle outgoing packets, resends, acknowledgements, and pings for each
2025 // client. m_packetSent will be set to true if a packet is sent 2107 // client. m_packetSent will be set to true if a packet is sent
2026 Scene.ForEachClient(clientPacketHandler); 2108 Scene.ForEachClient(clientPacketHandler);
@@ -2029,13 +2111,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2029 2111
2030 // If nothing was sent, sleep for the minimum amount of time before a 2112 // If nothing was sent, sleep for the minimum amount of time before a
2031 // token bucket could get more tokens 2113 // token bucket could get more tokens
2032 //if (!m_packetSent) 2114
2033 // Thread.Sleep((int)TickCountResolution); 2115 if(Scene.GetNumberOfClients() == 0)
2034 // 2116 {
2035 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with 2117 Thread.Sleep(100);
2036 // modern mono it reduces CPU base load since there is no more continuous polling. 2118 }
2037 if (!m_packetSent) 2119 else if (!m_packetSent)
2038 m_dataPresentEvent.WaitOne(100); 2120// Thread.Sleep((int)TickCountResolution); outch this is bad on linux
2121 Thread.Sleep(15); // match the 16ms of windows7, dont ask 16 or win may decide to do 32ms.
2039 2122
2040 Watchdog.UpdateThread(); 2123 Watchdog.UpdateThread();
2041 } 2124 }
@@ -2061,7 +2144,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2061 2144
2062 if (udpClient.IsConnected) 2145 if (udpClient.IsConnected)
2063 { 2146 {
2064 if (udpClient.ProcessUnackedSends && m_resendUnacked) 2147 if (m_resendUnacked)
2065 HandleUnacked(llClient); 2148 HandleUnacked(llClient);
2066 2149
2067 if (m_sendAcks) 2150 if (m_sendAcks)
@@ -2086,160 +2169,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2086 #region Emergency Monitoring 2169 #region Emergency Monitoring
2087 // Alternative packet handler fuull of instrumentation 2170 // Alternative packet handler fuull of instrumentation
2088 // Handy for hunting bugs 2171 // Handy for hunting bugs
2089 private Stopwatch watch1 = new Stopwatch(); 2172 protected Stopwatch watch1 = new Stopwatch();
2090 private Stopwatch watch2 = new Stopwatch(); 2173 protected Stopwatch watch2 = new Stopwatch();
2091 2174
2092 private float avgProcessingTicks = 0; 2175 protected float avgProcessingTicks = 0;
2093 private float avgResendUnackedTicks = 0; 2176 protected float avgResendUnackedTicks = 0;
2094 private float avgSendAcksTicks = 0; 2177 protected float avgSendAcksTicks = 0;
2095 private float avgSendPingTicks = 0; 2178 protected float avgSendPingTicks = 0;
2096 private float avgDequeueTicks = 0; 2179 protected float avgDequeueTicks = 0;
2097 private long nticks = 0; 2180 protected long nticks = 0;
2098 private long nticksUnack = 0; 2181 protected long nticksUnack = 0;
2099 private long nticksAck = 0; 2182 protected long nticksAck = 0;
2100 private long nticksPing = 0; 2183 protected long nticksPing = 0;
2101 private int npacksSent = 0; 2184 protected int npacksSent = 0;
2102 private int npackNotSent = 0; 2185 protected int npackNotSent = 0;
2103 2186
2104 /// <summary> 2187 /// <summary>
2105 /// Number of inbound packets processed since startup. 2188 /// Number of inbound packets processed since startup.
2106 /// </summary> 2189 /// </summary>
2107 public long IncomingPacketsProcessed { get; private set; } 2190 public long IncomingPacketsProcessed { get; protected set; }
2108
2109 private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
2110 {
2111 nticks++;
2112 watch1.Start();
2113 m_currentOutgoingClient = client;
2114
2115 try
2116 {
2117 if (client is LLClientView)
2118 {
2119 LLClientView llClient = (LLClientView)client;
2120 LLUDPClient udpClient = llClient.UDPClient;
2121 2191
2122 if (udpClient.IsConnected) 2192 #endregion
2123 {
2124 if (m_resendUnacked)
2125 {
2126 nticksUnack++;
2127 watch2.Start();
2128
2129 HandleUnacked(llClient);
2130
2131 watch2.Stop();
2132 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
2133 watch2.Reset();
2134 }
2135
2136 if (m_sendAcks)
2137 {
2138 nticksAck++;
2139 watch2.Start();
2140
2141 SendAcks(udpClient);
2142
2143 watch2.Stop();
2144 avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck);
2145 watch2.Reset();
2146 }
2147
2148 if (m_sendPing)
2149 {
2150 nticksPing++;
2151 watch2.Start();
2152
2153 SendPing(udpClient);
2154 2193
2155 watch2.Stop(); 2194 protected void ProcessInPacket(IncomingPacket incomingPacket)
2156 avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing); 2195 {
2157 watch2.Reset(); 2196 Packet packet = incomingPacket.Packet;
2158 } 2197 LLClientView client = incomingPacket.Client;
2159 2198
2160 watch2.Start(); 2199 if(!client.IsActive)
2161 // Dequeue any outgoing packets that are within the throttle limits 2200 return;
2162 if (udpClient.DequeueOutgoing())
2163 {
2164 m_packetSent = true;
2165 npacksSent++;
2166 }
2167 else
2168 {
2169 npackNotSent++;
2170 }
2171 2201
2172 watch2.Stop(); 2202 m_currentIncomingClient = client;
2173 avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
2174 watch2.Reset();
2175 2203
2176 } 2204 try
2177 else
2178 {
2179 m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
2180 }
2181 }
2182 }
2183 catch (Exception ex)
2184 { 2205 {
2185 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + 2206 // Process this packet
2186 " threw an exception: " + ex.Message, ex); 2207 client.ProcessInPacket(packet);
2187 } 2208 }
2188 watch1.Stop(); 2209 catch(ThreadAbortException)
2189 avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks);
2190 watch1.Reset();
2191
2192 // reuse this -- it's every ~100ms
2193 if (Scene.EmergencyMonitoring && nticks % 100 == 0)
2194 { 2210 {
2195 m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})", 2211 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
2196 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); 2212 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2197 npackNotSent = npacksSent = 0; 2213 Stop();
2198 } 2214 }
2199 2215 catch(Exception e)
2200 }
2201
2202 #endregion
2203
2204 private void ProcessInPacket(IncomingPacket incomingPacket)
2205 {
2206 Packet packet = incomingPacket.Packet;
2207 LLClientView client = incomingPacket.Client;
2208
2209 if (client.IsActive)
2210 { 2216 {
2211 m_currentIncomingClient = client; 2217 // Don't let a failure in an individual client thread crash the whole sim.
2212 2218 m_log.Error(
2213 try 2219 string.Format(
2214 { 2220 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2215 // Process this packet 2221 client.Name,packet.Type),
2216 client.ProcessInPacket(packet); 2222 e);
2217 }
2218 catch (ThreadAbortException)
2219 {
2220 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
2221 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2222 Stop();
2223 }
2224 catch (Exception e)
2225 {
2226 // Don't let a failure in an individual client thread crash the whole sim.
2227 m_log.Error(
2228 string.Format(
2229 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2230 client.Name, packet.Type),
2231 e);
2232 }
2233 finally
2234 {
2235 m_currentIncomingClient = null;
2236 }
2237 } 2223 }
2238 else 2224 finally
2239 { 2225 {
2240 m_log.DebugFormat( 2226 m_currentIncomingClient = null;
2241 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
2242 packet.Type, client.Name, Scene.RegionInfo.RegionName);
2243 } 2227 }
2244 2228
2245 IncomingPacketsProcessed++; 2229 IncomingPacketsProcessed++;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
index ac6c0b4..012a57d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
@@ -48,11 +48,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
48 48
49 public void Register() 49 public void Register()
50 { 50 {
51/*
51 m_console.Commands.AddCommand( 52 m_console.Commands.AddCommand(
52 "Comms", false, "show server throttles", 53 "Comms", false, "show server throttles",
53 "show server throttles", 54 "show server throttles",
54 "Show information about server throttles", 55 "Show information about server throttles",
55 HandleShowServerThrottlesCommand); 56 HandleShowServerThrottlesCommand);
56 57
57 m_console.Commands.AddCommand( 58 m_console.Commands.AddCommand(
58 "Debug", false, "debug lludp packet", 59 "Debug", false, "debug lludp packet",
@@ -206,13 +207,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
206 HandleClientGetCommand); 207 HandleClientGetCommand);
207 208
208 m_console.Commands.AddCommand( 209 m_console.Commands.AddCommand(
209 "Debug", 210 "Debug",
210 false, 211 false,
211 "debug lludp client set", 212 "debug lludp client set",
212 "debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]", 213 "debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]",
213 "Set a debug parameter for a particular client. If no name is given then the value is set on all clients.", 214 "Set a debug parameter for a particular client. If no name is given then the value is set on all clients.",
214 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.", 215 "process-unacked-sends - Do we take action if a sent reliable packet has not been acked.",
215 HandleClientSetCommand); 216 HandleClientSetCommand);
217*/
216 } 218 }
217 219
218 private void HandleShowServerThrottlesCommand(string module, string[] args) 220 private void HandleShowServerThrottlesCommand(string module, string[] args)
@@ -224,24 +226,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
224 ConsoleDisplayList cdl = new ConsoleDisplayList(); 226 ConsoleDisplayList cdl = new ConsoleDisplayList();
225 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled); 227 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled);
226 228
227 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; 229 long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate;
228 cdl.AddRow( 230 cdl.AddRow(
229 "Max scene throttle", 231 "Max scene throttle",
230 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); 232 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
231 233
232 int maxClientDripRate = m_udpServer.ThrottleRates.Total; 234 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
233 cdl.AddRow( 235 cdl.AddRow(
234 "Max new client throttle", 236 "Max new client throttle",
235 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); 237 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
236 238
237 m_console.Output(cdl.ToString()); 239 m_console.Output(cdl.ToString());
238 240
239 m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer)); 241 m_console.OutputFormat("{0}\n", GetServerThrottlesReport(m_udpServer));
240 } 242 }
241 243
242 private string GetServerThrottlesReport(LLUDPServer udpServer) 244 private string GetServerThrottlesReport(LLUDPServer udpServer)
243 { 245 {
244 StringBuilder report = new StringBuilder(); 246 StringBuilder report = new StringBuilder();
245 247
246 report.AppendFormat( 248 report.AppendFormat(
247 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", 249 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
@@ -252,7 +254,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
252 "Cloud", 254 "Cloud",
253 "Task", 255 "Task",
254 "Texture", 256 "Texture",
255 "Asset"); 257 "Asset");
256 258
257 report.AppendFormat( 259 report.AppendFormat(
258 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n", 260 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}\n",
@@ -263,7 +265,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
263 "kb/s", 265 "kb/s",
264 "kb/s", 266 "kb/s",
265 "kb/s", 267 "kb/s",
266 "kb/s"); 268 "kb/s");
267 269
268 ThrottleRates throttleRates = udpServer.ThrottleRates; 270 ThrottleRates throttleRates = udpServer.ThrottleRates;
269 report.AppendFormat( 271 report.AppendFormat(
@@ -275,16 +277,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
275 (throttleRates.Cloud * 8) / 1000, 277 (throttleRates.Cloud * 8) / 1000,
276 (throttleRates.Task * 8) / 1000, 278 (throttleRates.Task * 8) / 1000,
277 (throttleRates.Texture * 8) / 1000, 279 (throttleRates.Texture * 8) / 1000,
278 (throttleRates.Asset * 8) / 1000); 280 (throttleRates.Asset * 8) / 1000);
279 281
280 return report.ToString(); 282 return report.ToString();
281 } 283 }
282 284
283 protected string GetColumnEntry(string entry, int maxLength, int columnPadding) 285 protected string GetColumnEntry(string entry, int maxLength, int columnPadding)
284 { 286 {
285 return string.Format( 287 return string.Format(
286 "{0,-" + maxLength + "}{1,-" + columnPadding + "}", 288 "{0,-" + maxLength + "}{1,-" + columnPadding + "}",
287 entry.Length > maxLength ? entry.Substring(0, maxLength) : entry, 289 entry.Length > maxLength ? entry.Substring(0, maxLength) : entry,
288 ""); 290 "");
289 } 291 }
290 292
@@ -373,7 +375,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
373 MainConsole.Instance.OutputFormat( 375 MainConsole.Instance.OutputFormat(
374 "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]"); 376 "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]");
375 return; 377 return;
376 } 378 }
377 379
378 string param = args[4]; 380 string param = args[4];
379 string rawValue = args[5]; 381 string rawValue = args[5];
@@ -465,7 +467,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
465 MainConsole.Instance.OutputFormat( 467 MainConsole.Instance.OutputFormat(
466 "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]"); 468 "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]");
467 return; 469 return;
468 } 470 }
469 471
470 string firstName = null; 472 string firstName = null;
471 string lastName = null; 473 string lastName = null;
@@ -489,7 +491,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
489 ConsoleDisplayList cdl = new ConsoleDisplayList(); 491 ConsoleDisplayList cdl = new ConsoleDisplayList();
490 cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled); 492 cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled);
491 cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000)); 493 cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000));
492 cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000)); 494 cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000));
493 cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000)); 495 cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000));
494 496
495 m_console.Output(cdl.ToString()); 497 m_console.Output(cdl.ToString());
@@ -505,14 +507,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
505 m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name); 507 m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name);
506 ConsoleDisplayList cdl = new ConsoleDisplayList(); 508 ConsoleDisplayList cdl = new ConsoleDisplayList();
507 509
508 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; 510 long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate;
509 cdl.AddRow( 511 cdl.AddRow(
510 "max-scene-throttle", 512 "max-scene-throttle",
511 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); 513 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
512 514
513 int maxClientDripRate = m_udpServer.ThrottleRates.Total; 515 int maxClientDripRate = m_udpServer.ThrottleRates.Total;
514 cdl.AddRow( 516 cdl.AddRow(
515 "max-new-client-throttle", 517 "max-new-client-throttle",
516 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset"); 518 maxClientDripRate != 0 ? string.Format("{0} kbps", maxClientDripRate * 8 / 1000) : "unset");
517 519
518 m_console.Output(cdl.ToString()); 520 m_console.Output(cdl.ToString());
@@ -527,7 +529,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
527 { 529 {
528 MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>"); 530 MainConsole.Instance.OutputFormat("Usage: debug lludp set <param> <value>");
529 return; 531 return;
530 } 532 }
531 533
532 string param = args[3]; 534 string param = args[3];
533 string rawValue = args[4]; 535 string rawValue = args[4];
@@ -550,12 +552,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
550 } 552 }
551 else 553 else
552 { 554 {
553 return; 555 return;
554 } 556 }
555 557
556 m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name); 558 m_console.OutputFormat("{0} set to {1} in {2}", param, rawValue, m_udpServer.Scene.Name);
557 } 559 }
558 560
561/* not in use, nothing to set/get from lludp
559 private void HandleClientGetCommand(string module, string[] args) 562 private void HandleClientGetCommand(string module, string[] args)
560 { 563 {
561 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) 564 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
@@ -582,11 +585,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
582 m_console.OutputFormat( 585 m_console.OutputFormat(
583 "Client debug parameters for {0} ({1}) in {2}", 586 "Client debug parameters for {0} ({1}) in {2}",
584 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); 587 sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
585
586 ConsoleDisplayList cdl = new ConsoleDisplayList();
587 cdl.AddRow("process-unacked-sends", udpClient.ProcessUnackedSends);
588
589 m_console.Output(cdl.ToString());
590 } 588 }
591 }); 589 });
592 } 590 }
@@ -600,7 +598,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
600 { 598 {
601 MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]"); 599 MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]");
602 return; 600 return;
603 } 601 }
604 602
605 string param = args[4]; 603 string param = args[4];
606 string rawValue = args[5]; 604 string rawValue = args[5];
@@ -609,28 +607,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
609 607
610 if (args.Length == 8) 608 if (args.Length == 8)
611 name = string.Format("{0} {1}", args[6], args[7]); 609 name = string.Format("{0} {1}", args[6], args[7]);
612 610 // nothing here now
613 if (param == "process-unacked-sends")
614 {
615 bool newValue;
616
617 if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
618 return;
619
620 m_udpServer.Scene.ForEachScenePresence(
621 sp =>
622 {
623 if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
624 {
625 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
626 udpClient.ProcessUnackedSends = newValue;
627
628 m_console.OutputFormat("{0} set to {1} for {2} in {3}", param, newValue, sp.Name, m_udpServer.Scene.Name);
629 }
630 });
631 }
632 } 611 }
633 612*/
634 private void HandlePacketCommand(string module, string[] args) 613 private void HandlePacketCommand(string module, string[] args)
635 { 614 {
636 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene) 615 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
@@ -718,12 +697,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
718 697
719 string direction = args[3]; 698 string direction = args[3];
720 string subCommand = args[4]; 699 string subCommand = args[4];
721 string packetName = args[5]; 700 string packetName = args[5];
722 701
723 if (subCommand == "add") 702 if (subCommand == "add")
724 { 703 {
725 MainConsole.Instance.OutputFormat( 704 MainConsole.Instance.OutputFormat(
726 "Adding packet {0} to {1} drop list for all connections in {2}", 705 "Adding packet {0} to {1} drop list for all connections in {2}",
727 direction, packetName, m_udpServer.Scene.Name); 706 direction, packetName, m_udpServer.Scene.Name);
728 707
729 m_udpServer.Scene.ForEachScenePresence( 708 m_udpServer.Scene.ForEachScenePresence(
@@ -741,7 +720,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
741 else if (subCommand == "remove") 720 else if (subCommand == "remove")
742 { 721 {
743 MainConsole.Instance.OutputFormat( 722 MainConsole.Instance.OutputFormat(
744 "Removing packet {0} from {1} drop list for all connections in {2}", 723 "Removing packet {0} from {1} drop list for all connections in {2}",
745 direction, packetName, m_udpServer.Scene.Name); 724 direction, packetName, m_udpServer.Scene.Name);
746 725
747 m_udpServer.Scene.ForEachScenePresence( 726 m_udpServer.Scene.ForEachScenePresence(
@@ -889,10 +868,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
889 MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name); 868 MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name);
890 MainConsole.Instance.OutputFormat("Running: {0}", m_udpServer.OqrEngine.IsRunning); 869 MainConsole.Instance.OutputFormat("Running: {0}", m_udpServer.OqrEngine.IsRunning);
891 MainConsole.Instance.OutputFormat( 870 MainConsole.Instance.OutputFormat(
892 "Requests waiting: {0}", 871 "Requests waiting: {0}",
893 m_udpServer.OqrEngine.IsRunning ? m_udpServer.OqrEngine.JobsWaiting.ToString() : "n/a"); 872 m_udpServer.OqrEngine.IsRunning ? m_udpServer.OqrEngine.JobsWaiting.ToString() : "n/a");
894 } 873 }
895 else 874 else
896 { 875 {
897 MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand); 876 MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand);
898 } 877 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f62dc15..f362b06 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -3,25 +3,25 @@
3 * Original Author: Jeff Cesnik 3 * Original Author: Jeff Cesnik
4 * All rights reserved. 4 * All rights reserved.
5 * 5 *
6 * - Redistribution and use in source and binary forms, with or without 6 * - Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met: 7 * modification, are permitted provided that the following conditions are met:
8 * 8 *
9 * - Redistributions of source code must retain the above copyright notice, this 9 * - Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer. 10 * list of conditions and the following disclaimer.
11 * - Neither the name of the openmetaverse.org nor the names 11 * - Neither the name of the openmetaverse.org nor the names
12 * of its contributors may be used to endorse or promote products derived from 12 * of its contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission. 13 * this software without specific prior written permission.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE. 25 * POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
@@ -57,9 +57,6 @@ namespace OpenMetaverse
57 /// <summary>UDP socket, used in either client or server mode</summary> 57 /// <summary>UDP socket, used in either client or server mode</summary>
58 private Socket m_udpSocket; 58 private Socket m_udpSocket;
59 59
60 /// <summary>Flag to process packets asynchronously or synchronously</summary>
61 private bool m_asyncPacketHandling;
62
63 /// <summary> 60 /// <summary>
64 /// Are we to use object pool(s) to reduce memory churn when receiving data? 61 /// Are we to use object pool(s) to reduce memory churn when receiving data?
65 /// </summary> 62 /// </summary>
@@ -107,13 +104,18 @@ namespace OpenMetaverse
107 /// </summary> 104 /// </summary>
108 public float AverageReceiveTicksForLastSamplePeriod { get; private set; } 105 public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
109 106
107 public int Port
108 {
109 get { return m_udpPort; }
110 }
111
110 #region PacketDropDebugging 112 #region PacketDropDebugging
111 /// <summary> 113 /// <summary>
112 /// For debugging purposes only... random number generator for dropping 114 /// For debugging purposes only... random number generator for dropping
113 /// outbound packets. 115 /// outbound packets.
114 /// </summary> 116 /// </summary>
115 private Random m_dropRandomGenerator = new Random(); 117 private Random m_dropRandomGenerator = new Random();
116 118
117 /// <summary> 119 /// <summary>
118 /// For debugging purposes only... parameters for a simplified 120 /// For debugging purposes only... parameters for a simplified
119 /// model of packet loss with bursts, overall drop rate should 121 /// model of packet loss with bursts, overall drop rate should
@@ -132,7 +134,7 @@ namespace OpenMetaverse
132 /// </summary> 134 /// </summary>
133 private int m_dropLastTick = 0; 135 private int m_dropLastTick = 0;
134 private int m_dropResetTicks = 500; 136 private int m_dropResetTicks = 500;
135 137
136 /// <summary> 138 /// <summary>
137 /// Debugging code used to simulate dropped packets with bursts 139 /// Debugging code used to simulate dropped packets with bursts
138 /// </summary> 140 /// </summary>
@@ -179,11 +181,16 @@ namespace OpenMetaverse
179 // m_dropRandomGenerator = new Random(); 181 // m_dropRandomGenerator = new Random();
180 } 182 }
181 183
184 ~OpenSimUDPBase()
185 {
186 if(m_udpSocket !=null)
187 try { m_udpSocket.Close(); } catch { }
188 }
182 /// <summary> 189 /// <summary>
183 /// Start inbound UDP packet handling. 190 /// Start inbound UDP packet handling.
184 /// </summary> 191 /// </summary>
185 /// <param name="recvBufferSize">The size of the receive buffer for 192 /// <param name="recvBufferSize">The size of the receive buffer for
186 /// the UDP socket. This value is passed up to the operating system 193 /// the UDP socket. This value is passed up to the operating system
187 /// and used in the system networking stack. Use zero to leave this 194 /// and used in the system networking stack. Use zero to leave this
188 /// value as the default</param> 195 /// value as the default</param>
189 /// <param name="asyncPacketHandling">Set this to true to start 196 /// <param name="asyncPacketHandling">Set this to true to start
@@ -195,10 +202,8 @@ namespace OpenMetaverse
195 /// manner (not throwing an exception when the remote side resets the 202 /// manner (not throwing an exception when the remote side resets the
196 /// connection). This call is ignored on Mono where the flag is not 203 /// connection). This call is ignored on Mono where the flag is not
197 /// necessary</remarks> 204 /// necessary</remarks>
198 public virtual void StartInbound(int recvBufferSize, bool asyncPacketHandling) 205 public virtual void StartInbound(int recvBufferSize)
199 { 206 {
200 m_asyncPacketHandling = asyncPacketHandling;
201
202 if (!IsRunningInbound) 207 if (!IsRunningInbound)
203 { 208 {
204 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop"); 209 m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
@@ -206,10 +211,6 @@ namespace OpenMetaverse
206 const int SIO_UDP_CONNRESET = -1744830452; 211 const int SIO_UDP_CONNRESET = -1744830452;
207 212
208 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 213 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
209
210 m_log.DebugFormat(
211 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
212 ipep.Address, ipep.Port);
213 214
214 m_udpSocket = new Socket( 215 m_udpSocket = new Socket(
215 AddressFamily.InterNetwork, 216 AddressFamily.InterNetwork,
@@ -227,14 +228,23 @@ namespace OpenMetaverse
227 { 228 {
228 m_log.Debug("[UDPBASE]: Failed to increase default TTL"); 229 m_log.Debug("[UDPBASE]: Failed to increase default TTL");
229 } 230 }
231
230 try 232 try
231 { 233 {
232 // This udp socket flag is not supported under mono, 234 // This udp socket flag is not supported under mono,
233 // so we'll catch the exception and continue 235 // so we'll catch the exception and continue
234 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); 236 // Try does not protect some mono versions on mac
235 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); 237 if(Util.IsWindows())
238 {
239 m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null);
240 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set");
241 }
242 else
243 {
244 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
245 }
236 } 246 }
237 catch (SocketException) 247 catch
238 { 248 {
239 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); 249 m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring");
240 } 250 }
@@ -243,13 +253,22 @@ namespace OpenMetaverse
243 // we never want two regions to listen on the same port as they cannot demultiplex each other's messages, 253 // we never want two regions to listen on the same port as they cannot demultiplex each other's messages,
244 // leading to a confusing bug. 254 // leading to a confusing bug.
245 // By default, Windows does not allow two sockets to bind to the same port. 255 // By default, Windows does not allow two sockets to bind to the same port.
246 m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); 256 //
257 // Unfortunately, this also causes a crashed sim to leave the socket in a state
258 // where it appears to be in use but is really just hung from the old process
259 // crashing rather than closing it. While this protects agains misconfiguration,
260 // allowing crashed sims to be started up again right away, rather than having to
261 // wait 2 minutes for the socket to clear is more valuable. Commented 12/13/2016
262 // m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
247 263
248 if (recvBufferSize != 0) 264 if (recvBufferSize != 0)
249 m_udpSocket.ReceiveBufferSize = recvBufferSize; 265 m_udpSocket.ReceiveBufferSize = recvBufferSize;
250 266
251 m_udpSocket.Bind(ipep); 267 m_udpSocket.Bind(ipep);
252 268
269 if (m_udpPort == 0)
270 m_udpPort = ((IPEndPoint)m_udpSocket.LocalEndPoint).Port;
271
253 IsRunningInbound = true; 272 IsRunningInbound = true;
254 273
255 // kick off an async receive. The Start() method will return, the 274 // kick off an async receive. The Start() method will return, the
@@ -319,7 +338,7 @@ namespace OpenMetaverse
319 { 338 {
320 UDPPacketBuffer buf; 339 UDPPacketBuffer buf;
321 340
322 // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other 341 // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other
323 // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux. 342 // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux.
324 // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation. 343 // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads. Requires more investigation.
325// if (UsePools) 344// if (UsePools)
@@ -372,8 +391,8 @@ namespace OpenMetaverse
372 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); 391 m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
373 } 392 }
374 } 393 }
375 catch (ObjectDisposedException e) 394 catch (ObjectDisposedException e)
376 { 395 {
377 m_log.Error( 396 m_log.Error(
378 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); 397 string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
379 } 398 }
@@ -392,12 +411,7 @@ namespace OpenMetaverse
392 if (IsRunningInbound) 411 if (IsRunningInbound)
393 { 412 {
394 UdpReceives++; 413 UdpReceives++;
395 414
396 // Asynchronous mode will start another receive before the
397 // callback for this packet is even fired. Very parallel :-)
398 if (m_asyncPacketHandling)
399 AsyncBeginReceive();
400
401 try 415 try
402 { 416 {
403 // get the buffer that was created in AsyncBeginReceive 417 // get the buffer that was created in AsyncBeginReceive
@@ -419,7 +433,7 @@ namespace OpenMetaverse
419 // since this should be rare and won't cause a runtime problem. 433 // since this should be rare and won't cause a runtime problem.
420 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) 434 if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
421 { 435 {
422 AverageReceiveTicksForLastSamplePeriod 436 AverageReceiveTicksForLastSamplePeriod
423 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; 437 = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
424 438
425 m_receiveTicksInCurrentSamplePeriod = 0; 439 m_receiveTicksInCurrentSamplePeriod = 0;
@@ -431,16 +445,16 @@ namespace OpenMetaverse
431 m_currentReceiveTimeSamples++; 445 m_currentReceiveTimeSamples++;
432 } 446 }
433 } 447 }
434 catch (SocketException se) 448 catch (SocketException se)
435 { 449 {
436 m_log.Error( 450 m_log.Error(
437 string.Format( 451 string.Format(
438 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ", 452 "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
439 UdpReceives, se.ErrorCode), 453 UdpReceives, se.ErrorCode),
440 se); 454 se);
441 } 455 }
442 catch (ObjectDisposedException e) 456 catch (ObjectDisposedException e)
443 { 457 {
444 m_log.Error( 458 m_log.Error(
445 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); 459 string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
446 } 460 }
@@ -454,10 +468,7 @@ namespace OpenMetaverse
454// if (UsePools) 468// if (UsePools)
455// Pool.ReturnObject(buffer); 469// Pool.ReturnObject(buffer);
456 470
457 // Synchronous mode waits until the packet callback completes 471 AsyncBeginReceive();
458 // before starting the receive to fetch another packet
459 if (!m_asyncPacketHandling)
460 AsyncBeginReceive();
461 } 472 }
462 } 473 }
463 } 474 }
@@ -471,7 +482,7 @@ namespace OpenMetaverse
471 // packets when testing throttles & retransmission code 482 // packets when testing throttles & retransmission code
472 // if (DropOutgoingPacket()) 483 // if (DropOutgoingPacket())
473 // return; 484 // return;
474 485
475 try 486 try
476 { 487 {
477 m_udpSocket.BeginSendTo( 488 m_udpSocket.BeginSendTo(
@@ -485,7 +496,7 @@ namespace OpenMetaverse
485 } 496 }
486 catch (SocketException) { } 497 catch (SocketException) { }
487 catch (ObjectDisposedException) { } 498 catch (ObjectDisposedException) { }
488// } 499 // }
489 } 500 }
490 501
491 void AsyncEndSend(IAsyncResult result) 502 void AsyncEndSend(IAsyncResult result)
@@ -500,5 +511,25 @@ namespace OpenMetaverse
500 catch (SocketException) { } 511 catch (SocketException) { }
501 catch (ObjectDisposedException) { } 512 catch (ObjectDisposedException) { }
502 } 513 }
514
515 public void SyncSend(UDPPacketBuffer buf)
516 {
517 try
518 {
519 m_udpSocket.SendTo(
520 buf.Data,
521 0,
522 buf.DataLength,
523 SocketFlags.None,
524 buf.RemoteEndPoint
525 );
526 UdpSends++;
527 }
528 catch (SocketException e)
529 {
530 m_log.Warn("[UDPBASE]: sync send SocketException {0} " + e.Message);
531 }
532 catch (ObjectDisposedException) { }
533 }
503 } 534 }
504} \ No newline at end of file 535}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index 5a2bcee..f585bea 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -62,7 +62,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 /// </summary> 62 /// </summary>
63 public int PacketsPooled 63 public int PacketsPooled
64 { 64 {
65 get 65 get
66 { 66 {
67 lock (pool) 67 lock (pool)
68 return pool.Count; 68 return pool.Count;
@@ -74,9 +74,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
74 /// </summary> 74 /// </summary>
75 public int BlocksPooled 75 public int BlocksPooled
76 { 76 {
77 get 77 get
78 { 78 {
79 lock (DataBlocks) 79 lock (DataBlocks)
80 return DataBlocks.Count; 80 return DataBlocks.Count;
81 } 81 }
82 } 82 }
@@ -248,7 +248,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
248 } 248 }
249 } 249 }
250 break; 250 break;
251 251
252 // Other packets wont pool 252 // Other packets wont pool
253 default: 253 default:
254 return; 254 return;
@@ -276,7 +276,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
276 { 276 {
277 DataBlocks[typeof(T)] = new Stack<Object>(); 277 DataBlocks[typeof(T)] = new Stack<Object>();
278 } 278 }
279 279
280 return new T(); 280 return new T();
281 } 281 }
282 } 282 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
index bf505b4..4a8f16d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs
@@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4using Mono.Addins; 4using Mono.Addins;
5 5
6// General Information about an assembly is controlled through the following 6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information 7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly. 8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenUDP")] 9[assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenUDP")]
@@ -15,8 +15,8 @@ using Mono.Addins;
15[assembly: AssemblyTrademark("")] 15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")] 16[assembly: AssemblyCulture("")]
17 17
18// Setting ComVisible to false makes the types in this assembly not visible 18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from 19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type. 20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)] 21[assembly: ComVisible(false)]
22 22
@@ -26,11 +26,11 @@ using Mono.Addins;
26// Version information for an assembly consists of the following four values: 26// Version information for an assembly consists of the following four values:
27// 27//
28// Major Version 28// Major Version
29// Minor Version 29// Minor Version
30// Build Number 30// Build Number
31// Revision 31// Revision
32// 32//
33[assembly: AssemblyVersion("0.8.3.*")] 33[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
34 34
35[assembly: Addin("LindenUDP", OpenSim.VersionInfo.VersionNumber)] 35[assembly: Addin("LindenUDP", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] 36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index a935dd2..eb262d2 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -70,7 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
70 m_scene = new SceneHelpers().SetupScene(); 70 m_scene = new SceneHelpers().SetupScene();
71 StatsManager.SimExtraStats = new SimExtraStatsCollector(); 71 StatsManager.SimExtraStats = new SimExtraStatsCollector();
72 } 72 }
73 73
74// /// <summary> 74// /// <summary>
75// /// Build an object name packet for test purposes 75// /// Build an object name packet for test purposes
76// /// </summary> 76// /// </summary>
@@ -84,13 +84,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
84// odb.Name = Utils.StringToBytes(objectName); 84// odb.Name = Utils.StringToBytes(objectName);
85// onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb }; 85// onp.ObjectData = new ObjectNamePacket.ObjectDataBlock[] { odb };
86// onp.Header.Zerocoded = false; 86// onp.Header.Zerocoded = false;
87// 87//
88// return onp; 88// return onp;
89// } 89// }
90// 90//
91 /// <summary> 91 /// <summary>
92 /// Test adding a client to the stack 92 /// Test adding a client to the stack
93 /// </summary> 93 /// </summary>
94/*
94 [Test] 95 [Test]
95 public void TestAddClient() 96 public void TestAddClient()
96 { 97 {
@@ -156,7 +157,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
156 config.Set("AckTimeout", -1); 157 config.Set("AckTimeout", -1);
157 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics); 158 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(m_scene, ics);
158 159
159 ScenePresence sp 160 ScenePresence sp
160 = ClientStackHelpers.AddChildClient( 161 = ClientStackHelpers.AddChildClient(
161 m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); 162 m_scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
162 163
@@ -165,7 +166,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
165 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); 166 ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
166 Assert.That(spAfterAckTimeout, Is.Null); 167 Assert.That(spAfterAckTimeout, Is.Null);
167 } 168 }
168 169*/
169// /// <summary> 170// /// <summary>
170// /// Test removing a client from the stack 171// /// Test removing a client from the stack
171// /// </summary> 172// /// </summary>
@@ -175,21 +176,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
175// TestHelper.InMethod(); 176// TestHelper.InMethod();
176// 177//
177// uint myCircuitCode = 123457; 178// uint myCircuitCode = 123457;
178// 179//
179// TestLLUDPServer testLLUDPServer; 180// TestLLUDPServer testLLUDPServer;
180// TestLLPacketServer testLLPacketServer; 181// TestLLPacketServer testLLPacketServer;
181// AgentCircuitManager acm; 182// AgentCircuitManager acm;
182// SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm); 183// SetupStack(new MockScene(), out testLLUDPServer, out testLLPacketServer, out acm);
183// AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm); 184// AddClient(myCircuitCode, new IPEndPoint(IPAddress.Loopback, 1000), testLLUDPServer, acm);
184// 185//
185// testLLUDPServer.RemoveClientCircuit(myCircuitCode); 186// testLLUDPServer.RemoveClientCircuit(myCircuitCode);
186// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode)); 187// Assert.IsFalse(testLLUDPServer.HasCircuit(myCircuitCode));
187// 188//
188// // Check that removing a non-existent circuit doesn't have any bad effects 189// // Check that removing a non-existent circuit doesn't have any bad effects
189// testLLUDPServer.RemoveClientCircuit(101); 190// testLLUDPServer.RemoveClientCircuit(101);
190// Assert.IsFalse(testLLUDPServer.HasCircuit(101)); 191// Assert.IsFalse(testLLUDPServer.HasCircuit(101));
191// } 192// }
192// 193//
193// /// <summary> 194// /// <summary>
194// /// Make sure that the client stack reacts okay to malformed packets 195// /// Make sure that the client stack reacts okay to malformed packets
195// /// </summary> 196// /// </summary>
@@ -200,8 +201,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
200// 201//
201// uint myCircuitCode = 123458; 202// uint myCircuitCode = 123458;
202// EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001); 203// EndPoint testEp = new IPEndPoint(IPAddress.Loopback, 1001);
203// MockScene scene = new MockScene(); 204// MockScene scene = new MockScene();
204// 205//
205// TestLLUDPServer testLLUDPServer; 206// TestLLUDPServer testLLUDPServer;
206// TestLLPacketServer testLLPacketServer; 207// TestLLPacketServer testLLPacketServer;
207// AgentCircuitManager acm; 208// AgentCircuitManager acm;
@@ -213,24 +214,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
213// // Send two garbled 'packets' in succession 214// // Send two garbled 'packets' in succession
214// testLLUDPServer.LoadReceive(data, testEp); 215// testLLUDPServer.LoadReceive(data, testEp);
215// testLLUDPServer.LoadReceive(data, testEp); 216// testLLUDPServer.LoadReceive(data, testEp);
216// testLLUDPServer.ReceiveData(null); 217// testLLUDPServer.ReceiveData(null);
217// 218//
218// // Check that we are still here 219// // Check that we are still here
219// Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode)); 220// Assert.IsTrue(testLLUDPServer.HasCircuit(myCircuitCode));
220// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0)); 221// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(0));
221// 222//
222// // Check that sending a valid packet to same circuit still succeeds 223// // Check that sending a valid packet to same circuit still succeeds
223// Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0)); 224// Assert.That(scene.ObjectNameCallsReceived, Is.EqualTo(0));
224// 225//
225// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp); 226// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "helloooo"), testEp);
226// testLLUDPServer.ReceiveData(null); 227// testLLUDPServer.ReceiveData(null);
227// 228//
228// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1)); 229// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(1));
229// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1)); 230// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(1));
230// } 231// }
231// 232//
232// /// <summary> 233// /// <summary>
233// /// Test that the stack continues to work even if some client has caused a 234// /// Test that the stack continues to work even if some client has caused a
234// /// SocketException on Socket.BeginReceive() 235// /// SocketException on Socket.BeginReceive()
235// /// </summary> 236// /// </summary>
236// [Test] 237// [Test]
@@ -239,32 +240,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
239// TestHelper.InMethod(); 240// TestHelper.InMethod();
240// 241//
241// MockScene scene = new MockScene(); 242// MockScene scene = new MockScene();
242// 243//
243// uint circuitCodeA = 130000; 244// uint circuitCodeA = 130000;
244// EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300); 245// EndPoint epA = new IPEndPoint(IPAddress.Loopback, 1300);
245// UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300"); 246// UUID agentIdA = UUID.Parse("00000000-0000-0000-0000-000000001300");
246// UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300"); 247// UUID sessionIdA = UUID.Parse("00000000-0000-0000-0000-000000002300");
247// 248//
248// uint circuitCodeB = 130001; 249// uint circuitCodeB = 130001;
249// EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301); 250// EndPoint epB = new IPEndPoint(IPAddress.Loopback, 1301);
250// UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301"); 251// UUID agentIdB = UUID.Parse("00000000-0000-0000-0000-000000001301");
251// UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301"); 252// UUID sessionIdB = UUID.Parse("00000000-0000-0000-0000-000000002301");
252// 253//
253// TestLLUDPServer testLLUDPServer; 254// TestLLUDPServer testLLUDPServer;
254// TestLLPacketServer testLLPacketServer; 255// TestLLPacketServer testLLPacketServer;
255// AgentCircuitManager acm; 256// AgentCircuitManager acm;
256// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); 257// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
257// AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm); 258// AddClient(circuitCodeA, epA, agentIdA, sessionIdA, testLLUDPServer, acm);
258// AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm); 259// AddClient(circuitCodeB, epB, agentIdB, sessionIdB, testLLUDPServer, acm);
259// 260//
260// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA); 261// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet1"), epA);
261// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB); 262// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(1, "packet2"), epB);
262// testLLUDPServer.LoadReceiveWithBeginException(epA); 263// testLLUDPServer.LoadReceiveWithBeginException(epA);
263// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB); 264// testLLUDPServer.LoadReceive(BuildTestObjectNamePacket(2, "packet3"), epB);
264// testLLUDPServer.ReceiveData(null); 265// testLLUDPServer.ReceiveData(null);
265// 266//
266// Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA)); 267// Assert.IsFalse(testLLUDPServer.HasCircuit(circuitCodeA));
267// 268//
268// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3)); 269// Assert.That(testLLPacketServer.GetTotalPacketsReceived(), Is.EqualTo(3));
269// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3)); 270// Assert.That(testLLPacketServer.GetPacketsReceivedFor(PacketType.ObjectName), Is.EqualTo(3));
270// } 271// }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
index 92f1fc3..1731aa9 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/PacketHandlerTests.cs
@@ -59,7 +59,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
59// agent.InventoryFolder = UUID.Zero; 59// agent.InventoryFolder = UUID.Zero;
60// agent.startpos = Vector3.Zero; 60// agent.startpos = Vector3.Zero;
61// agent.CapsPath = "http://wibble.com"; 61// agent.CapsPath = "http://wibble.com";
62// 62//
63// TestLLUDPServer testLLUDPServer; 63// TestLLUDPServer testLLUDPServer;
64// TestLLPacketServer testLLPacketServer; 64// TestLLPacketServer testLLPacketServer;
65// AgentCircuitManager acm; 65// AgentCircuitManager acm;
@@ -67,7 +67,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
67// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm); 67// SetupStack(scene, out testLLUDPServer, out testLLPacketServer, out acm);
68// 68//
69// TestClient testClient = new TestClient(agent, scene); 69// TestClient testClient = new TestClient(agent, scene);
70// 70//
71// LLPacketHandler packetHandler 71// LLPacketHandler packetHandler
72// = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings()); 72// = new LLPacketHandler(testClient, testLLPacketServer, new ClientStackUserSettings());
73// 73//
@@ -87,14 +87,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
87// /// <param name="testPacketServer"></param> 87// /// <param name="testPacketServer"></param>
88// /// <param name="acm">Agent circuit manager used in setting up the stack</param> 88// /// <param name="acm">Agent circuit manager used in setting up the stack</param>
89// protected void SetupStack( 89// protected void SetupStack(
90// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer, 90// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
91// out AgentCircuitManager acm) 91// out AgentCircuitManager acm)
92// { 92// {
93// IConfigSource configSource = new IniConfigSource(); 93// IConfigSource configSource = new IniConfigSource();
94// ClientStackUserSettings userSettings = new ClientStackUserSettings(); 94// ClientStackUserSettings userSettings = new ClientStackUserSettings();
95// testLLUDPServer = new TestLLUDPServer(); 95// testLLUDPServer = new TestLLUDPServer();
96// acm = new AgentCircuitManager(); 96// acm = new AgentCircuitManager();
97// 97//
98// uint port = 666; 98// uint port = 666;
99// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm); 99// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
100// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings); 100// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
index 3c82a78..873b1e5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
@@ -35,6 +35,7 @@ using OpenSim.Tests.Common;
35 35
36namespace OpenSim.Region.ClientStack.LindenUDP.Tests 36namespace OpenSim.Region.ClientStack.LindenUDP.Tests
37{ 37{
38 /*
38 [TestFixture] 39 [TestFixture]
39 public class ThrottleTests : OpenSimTestCase 40 public class ThrottleTests : OpenSimTestCase
40 { 41 {
@@ -57,16 +58,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
57 [Test] 58 [Test]
58 public void TestSetRequestDripRate() 59 public void TestSetRequestDripRate()
59 { 60 {
61
60 TestHelpers.InMethod(); 62 TestHelpers.InMethod();
61 63
62 TokenBucket tb = new TokenBucket("tb", null, 5000, 0); 64 TokenBucket tb = new TokenBucket(null, 5000f,10000f);
63 AssertRates(tb, 5000, 0, 5000, 0); 65 AssertRates(tb, 5000, 0, 5000, 0);
64 66
65 tb.RequestedDripRate = 4000; 67 tb.RequestedDripRate = 4000f;
66 AssertRates(tb, 4000, 0, 4000, 0); 68 AssertRates(tb, 4000, 0, 4000, 0);
67 69
68 tb.RequestedDripRate = 6000; 70 tb.RequestedDripRate = 6000;
69 AssertRates(tb, 6000, 0, 6000, 0); 71 AssertRates(tb, 6000, 0, 6000, 0);
72
70 } 73 }
71 74
72 [Test] 75 [Test]
@@ -74,7 +77,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
74 { 77 {
75 TestHelpers.InMethod(); 78 TestHelpers.InMethod();
76 79
77 TokenBucket tb = new TokenBucket("tb", null, 5000, 10000); 80 TokenBucket tb = new TokenBucket(null, 5000,15000);
78 AssertRates(tb, 5000, 0, 5000, 10000); 81 AssertRates(tb, 5000, 0, 5000, 10000);
79 82
80 tb.RequestedDripRate = 4000; 83 tb.RequestedDripRate = 4000;
@@ -92,9 +95,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
92 { 95 {
93 TestHelpers.InMethod(); 96 TestHelpers.InMethod();
94 97
95 TokenBucket tbParent = new TokenBucket("tbParent", null, 0, 0); 98 TokenBucket tbParent = new TokenBucket("tbParent", null, 0);
96 TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000, 0); 99 TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000);
97 TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000, 0); 100 TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000);
98 101
99 AssertRates(tbParent, 8000, 8000, 8000, 0); 102 AssertRates(tbParent, 8000, 8000, 8000, 0);
100 AssertRates(tbChild1, 3000, 0, 3000, 0); 103 AssertRates(tbChild1, 3000, 0, 3000, 0);
@@ -113,6 +116,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
113 AssertRates(tbParent, 6000, 8000, 6000, 0); 116 AssertRates(tbParent, 6000, 8000, 6000, 0);
114 AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0); 117 AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0);
115 AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0); 118 AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0);
119
116 } 120 }
117 121
118 private void AssertRates( 122 private void AssertRates(
@@ -133,7 +137,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
133 Scene scene = new SceneHelpers().SetupScene(); 137 Scene scene = new SceneHelpers().SetupScene();
134 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); 138 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
135 139
136 ScenePresence sp 140 ScenePresence sp
137 = ClientStackHelpers.AddChildClient( 141 = ClientStackHelpers.AddChildClient(
138 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); 142 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
139 143
@@ -141,7 +145,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
141 145
142 udpServer.Throttle.DebugLevel = 1; 146 udpServer.Throttle.DebugLevel = 1;
143 udpClient.ThrottleDebugLevel = 1; 147 udpClient.ThrottleDebugLevel = 1;
144 148
145 int resendBytes = 1000; 149 int resendBytes = 1000;
146 int landBytes = 2000; 150 int landBytes = 2000;
147 int windBytes = 3000; 151 int windBytes = 3000;
@@ -157,8 +161,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
157 int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; 161 int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
158 162
159 AssertThrottles( 163 AssertThrottles(
160 udpClient, 164 udpClient,
161 LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes, 165 LLUDPServer.MTU, landBytes, windBytes, cloudBytes, taskBytes,
162 textureBytes, assetBytes, totalBytes, 0, 0); 166 textureBytes, assetBytes, totalBytes, 0, 0);
163 } 167 }
164 168
@@ -177,7 +181,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
177 181
178 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics); 182 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
179 183
180 ScenePresence sp 184 ScenePresence sp
181 = ClientStackHelpers.AddChildClient( 185 = ClientStackHelpers.AddChildClient(
182 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); 186 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
183 187
@@ -203,7 +207,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
203 double commitRatio = 32000.0 / totalBytes; 207 double commitRatio = 32000.0 / totalBytes;
204 208
205 AssertThrottles( 209 AssertThrottles(
206 udpClient, 210 udpClient,
207 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, 211 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
208 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); 212 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
209 213
@@ -213,7 +217,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
213 commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes; 217 commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes;
214 218
215 AssertThrottles( 219 AssertThrottles(
216 udpClient, 220 udpClient,
217 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, 221 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
218 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); 222 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
219 223
@@ -223,7 +227,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
223 commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes; 227 commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes;
224 228
225 AssertThrottles( 229 AssertThrottles(
226 udpClient, 230 udpClient,
227 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio, 231 LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
228 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0); 232 textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
229 } 233 }
@@ -244,14 +248,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
244 int taskBytes = 14000; 248 int taskBytes = 14000;
245 int textureBytes = 16000; 249 int textureBytes = 16000;
246 int assetBytes = 18000; 250 int assetBytes = 18000;
247 int totalBytes 251 int totalBytes
248 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); 252 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
249 253
250 Scene scene = new SceneHelpers().SetupScene(); 254 Scene scene = new SceneHelpers().SetupScene();
251 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); 255 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
252 udpServer.Throttle.RequestedDripRate = totalBytes; 256 udpServer.Throttle.RequestedDripRate = totalBytes;
253 257
254 ScenePresence sp1 258 ScenePresence sp1
255 = ClientStackHelpers.AddChildClient( 259 = ClientStackHelpers.AddChildClient(
256 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); 260 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
257 261
@@ -261,8 +265,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
261 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); 265 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
262 266
263 AssertThrottles( 267 AssertThrottles(
264 udpClient1, 268 udpClient1,
265 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, 269 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
266 textureBytes / 2, assetBytes / 2, totalBytes, 0, 0); 270 textureBytes / 2, assetBytes / 2, totalBytes, 0, 0);
267 271
268 // Test: Now add another client 272 // Test: Now add another client
@@ -277,13 +281,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
277 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); 281 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
278 282
279 AssertThrottles( 283 AssertThrottles(
280 udpClient1, 284 udpClient1,
281 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, 285 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
282 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); 286 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
283 287
284 AssertThrottles( 288 AssertThrottles(
285 udpClient2, 289 udpClient2,
286 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4, 290 resendBytes / 4, landBytes / 4, windBytes / 4, cloudBytes / 4, taskBytes / 4,
287 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0); 291 textureBytes / 4, assetBytes / 4, totalBytes / 2, 0, 0);
288 } 292 }
289 293
@@ -303,14 +307,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
303 int taskBytes = 12000; 307 int taskBytes = 12000;
304 int textureBytes = 14000; 308 int textureBytes = 14000;
305 int assetBytes = 16000; 309 int assetBytes = 16000;
306 int totalBytes 310 int totalBytes
307 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2); 311 = (int)((resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes) / 2);
308 312
309 Scene scene = new SceneHelpers().SetupScene(); 313 Scene scene = new SceneHelpers().SetupScene();
310 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene); 314 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
311 udpServer.ThrottleRates.Total = totalBytes; 315 udpServer.ThrottleRates.Total = totalBytes;
312 316
313 ScenePresence sp 317 ScenePresence sp
314 = ClientStackHelpers.AddChildClient( 318 = ClientStackHelpers.AddChildClient(
315 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); 319 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
316 320
@@ -321,8 +325,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
321 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); 325 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
322 326
323 AssertThrottles( 327 AssertThrottles(
324 udpClient, 328 udpClient,
325 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2, 329 resendBytes / 2, landBytes / 2, windBytes / 2, cloudBytes / 2, taskBytes / 2,
326 textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes); 330 textureBytes / 2, assetBytes / 2, totalBytes, 0, totalBytes);
327 } 331 }
328 332
@@ -348,7 +352,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
348 udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1); 352 udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1);
349 udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5); 353 udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5);
350 354
351 ScenePresence sp1 355 ScenePresence sp1
352 = ClientStackHelpers.AddChildClient( 356 = ClientStackHelpers.AddChildClient(
353 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); 357 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
354 358
@@ -359,8 +363,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
359 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); 363 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
360 364
361 AssertThrottles( 365 AssertThrottles(
362 udpClient1, 366 udpClient1,
363 resendBytes, landBytes, windBytes, cloudBytes, taskBytes, 367 resendBytes, landBytes, windBytes, cloudBytes, taskBytes,
364 textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1); 368 textureBytes, assetBytes, totalBytes, 0, totalBytes * 1.1);
365 369
366 // Now add another client 370 // Now add another client
@@ -375,25 +379,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
375 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes); 379 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
376 380
377 AssertThrottles( 381 AssertThrottles(
378 udpClient1, 382 udpClient1,
379 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, 383 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
380 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); 384 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
381 385
382 AssertThrottles( 386 AssertThrottles(
383 udpClient2, 387 udpClient2,
384 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75, 388 resendBytes * 0.75, landBytes * 0.75, windBytes * 0.75, cloudBytes * 0.75, taskBytes * 0.75,
385 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1); 389 textureBytes * 0.75, assetBytes * 0.75, totalBytes * 0.75, 0, totalBytes * 1.1);
386 } 390 }
387 391
388 private void AssertThrottles( 392 private void AssertThrottles(
389 LLUDPClient udpClient, 393 LLUDPClient udpClient,
390 double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes, 394 double resendBytes, double landBytes, double windBytes, double cloudBytes, double taskBytes, double textureBytes, double assetBytes,
391 double totalBytes, double targetBytes, double maxBytes) 395 double totalBytes, double targetBytes, double maxBytes)
392 { 396 {
393 ClientInfo ci = udpClient.GetClientInfo(); 397 ClientInfo ci = udpClient.GetClientInfo();
394 398
395// Console.WriteLine( 399// Console.WriteLine(
396// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}", 400// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
397// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle); 401// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
398 402
399 Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend"); 403 Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend");
@@ -424,4 +428,5 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
424 udpClient.SetThrottles(throttles); 428 udpClient.SetThrottles(throttles);
425 } 429 }
426 } 430 }
431 */
427} \ No newline at end of file 432} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index 7a2756b..f8ec97a 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -58,17 +58,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
58 58
59 /// <summary>Flag used to enable adaptive throttles</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
60 public bool AdaptiveThrottlesEnabled; 60 public bool AdaptiveThrottlesEnabled;
61 61
62 /// <summary> 62 /// <summary>
63 /// Set the minimum rate that the adaptive throttles can set. The viewer 63 /// Set the minimum rate that the adaptive throttles can set. The viewer
64 /// can still throttle lower than this, but the adaptive throttles will 64 /// can still throttle lower than this, but the adaptive throttles will
65 /// never decrease rates below this no matter how many packets are dropped 65 /// never decrease rates below this no matter how many packets are dropped
66 /// </summary> 66 /// </summary>
67 public Int64 MinimumAdaptiveThrottleRate; 67 public Int64 MinimumAdaptiveThrottleRate;
68 68
69 /// <summary>Amount of the texture throttle to steal for the task throttle</summary> 69 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
70 public double CannibalizeTextureRate; 70 public double CannibalizeTextureRate;
71 71
72 public int ClientMaxRate;
73 public float BrustTime;
74
72 /// <summary> 75 /// <summary>
73 /// Default constructor 76 /// Default constructor
74 /// </summary> 77 /// </summary>
@@ -88,13 +91,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
88 Texture = throttleConfig.GetInt("texture_default", 18500); 91 Texture = throttleConfig.GetInt("texture_default", 18500);
89 Asset = throttleConfig.GetInt("asset_default", 10500); 92 Asset = throttleConfig.GetInt("asset_default", 10500);
90 93
91 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 94 Total = Resend + Land + Wind + Cloud + Task + Texture + Asset;
95 // 5120000 bps default max
96 ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 640000);
97 if (ClientMaxRate > 1000000)
98 ClientMaxRate = 1000000; // no more than 8Mbps
92 99
93 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); 100 BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10);
101 BrustTime *= 1e-3f;
102
103 // Adaptive is broken
104// AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
105 AdaptiveThrottlesEnabled = false;
94 MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000); 106 MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000);
95 107
96 CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f); 108 // http textures do use udp bandwidth setting
97 CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9); 109// CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
110// CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
111 CannibalizeTextureRate = 0f;
112
98 } 113 }
99 catch (Exception) { } 114 catch (Exception) { }
100 } 115 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index 4616203..1daf091 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -43,150 +43,143 @@ namespace OpenSim.Region.ClientStack.LindenUDP
43 { 43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 45
46 public string Identifier { get; private set; } 46 private static Int32 m_counter = 0;
47 47
48 public int DebugLevel { get; set; } 48// private Int32 m_identifier;
49 49
50 /// <summary> 50 protected const float m_timeScale = 1e-3f;
51 /// Number of ticks (ms) per quantum, drip rate and max burst
52 /// are defined over this interval.
53 /// </summary>
54 protected const Int32 m_ticksPerQuantum = 1000;
55 51
56 /// <summary> 52 /// <summary>
57 /// This is the number of quantums worth of packets that can 53 /// This is the number of m_minimumDripRate bytes
58 /// be accommodated during a burst 54 /// allowed in a burst
55 /// roughtly, with this settings, the maximum time system will take
56 /// to recheck a bucket in ms
57 ///
59 /// </summary> 58 /// </summary>
60 protected const Double m_quantumsPerBurst = 1.5; 59 protected const float m_quantumsPerBurst = 5;
61 60
62 /// <summary> 61 /// <summary>
63 /// </summary> 62 /// </summary>
64 protected const Int32 m_minimumDripRate = LLUDPServer.MTU; 63 protected const float m_minimumDripRate = 1500;
65 64
66 /// <summary>Time of the last drip, in system ticks</summary> 65 /// <summary>Time of the last drip</summary>
67 protected Int32 m_lastDrip; 66 protected double m_lastDrip;
68 67
69 /// <summary> 68 /// <summary>
70 /// The number of bytes that can be sent at this moment. This is the 69 /// The number of bytes that can be sent at this moment. This is the
71 /// current number of tokens in the bucket 70 /// current number of tokens in the bucket
72 /// </summary> 71 /// </summary>
73 protected Int64 m_tokenCount; 72 protected float m_tokenCount;
74 73
75 /// <summary> 74 /// <summary>
76 /// Map of children buckets and their requested maximum burst rate 75 /// Map of children buckets and their requested maximum burst rate
77 /// </summary> 76 /// </summary>
78 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); 77
78 protected Dictionary<TokenBucket, float> m_children = new Dictionary<TokenBucket, float>();
79
80#region Properties
79 81
80 /// <summary> 82 /// <summary>
81 /// The parent bucket of this bucket, or null if this bucket has no 83 /// The parent bucket of this bucket, or null if this bucket has no
82 /// parent. The parent bucket will limit the aggregate bandwidth of all 84 /// parent. The parent bucket will limit the aggregate bandwidth of all
83 /// of its children buckets 85 /// of its children buckets
84 /// </summary> 86 /// </summary>
85 public TokenBucket Parent { get; protected set; } 87 protected TokenBucket m_parent;
86 88 public TokenBucket Parent
89 {
90 get { return m_parent; }
91 set { m_parent = value; }
92 }
87 /// <summary> 93 /// <summary>
88 /// Maximum burst rate in bytes per second. This is the maximum number 94 /// This is the maximum number
89 /// of tokens that can accumulate in the bucket at any one time. This 95 /// of tokens that can accumulate in the bucket at any one time. This
90 /// also sets the total request for leaf nodes 96 /// also sets the total request for leaf nodes
91 /// </summary> 97 /// </summary>
92 protected Int64 m_burstRate; 98 protected float m_burst;
93 public Int64 RequestedBurstRate 99
100 protected float m_maxDripRate = 0;
101 public virtual float MaxDripRate
94 { 102 {
95 get { return m_burstRate; } 103 get { return m_maxDripRate; }
96 set { m_burstRate = (value < 0 ? 0 : value); } 104 set { m_maxDripRate = value; }
97 } 105 }
98 106
99 public Int64 BurstRate 107 public float RequestedBurst
100 { 108 {
101 get { 109 get { return m_burst; }
102 double rate = RequestedBurstRate * BurstRateModifier(); 110 set {
103 if (rate < m_minimumDripRate * m_quantumsPerBurst) 111 float rate = (value < 0 ? 0 : value);
112 if (rate < 1.5f * m_minimumDripRate)
113 rate = 1.5f * m_minimumDripRate;
114 else if (rate > m_minimumDripRate * m_quantumsPerBurst)
104 rate = m_minimumDripRate * m_quantumsPerBurst; 115 rate = m_minimumDripRate * m_quantumsPerBurst;
105 116
106 return (Int64) rate; 117 m_burst = rate;
118 }
119 }
120
121 public float Burst
122 {
123 get {
124 float rate = RequestedBurst * BurstModifier();
125 if (rate < m_minimumDripRate)
126 rate = m_minimumDripRate;
127 return (float)rate;
107 } 128 }
108 } 129 }
109 130
110 /// <summary> 131 /// <summary>
111 /// The requested drip rate for this particular bucket. 132 /// The requested drip rate for this particular bucket.
112 /// </summary> 133 /// </summary>
113 /// <remarks> 134 /// <remarks>
114 /// 0 then TotalDripRequest is used instead. 135 /// 0 then TotalDripRequest is used instead.
115 /// Can never be above MaxDripRate. 136 /// Can never be above MaxDripRate.
116 /// Tokens are added to the bucket at any time 137 /// Tokens are added to the bucket at any time
117 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 138 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
118 /// the system tick interval (typically around 15-22ms) 139 /// the system tick interval (typically around 15-22ms)</remarks>
119 /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive 140 protected float m_dripRate;
120 /// number on get if TotalDripRequest is set. This also stops us being able to retrieve the fact that
121 /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get
122 /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties.
123 /// </remarks>
124 public virtual Int64 RequestedDripRate
125 {
126 get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); }
127 set
128 {
129 if (value <= 0)
130 m_dripRate = 0;
131 else if (MaxDripRate > 0 && value > MaxDripRate)
132 m_dripRate = MaxDripRate;
133 else
134 m_dripRate = value;
135 141
136 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 142 public float RequestedDripRate
143 {
144 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
145 set {
146 m_dripRate = (value < 0 ? 0 : value);
147 m_totalDripRequest = m_dripRate;
137 148
138 if (Parent != null) 149 if (m_parent != null)
139 Parent.RegisterRequest(this, m_dripRate); 150 m_parent.RegisterRequest(this,m_dripRate);
140 } 151 }
141 } 152 }
142 153
143 /// <summary> 154 public float DripRate
144 /// Gets the drip rate.
145 /// </summary>
146 /// <value>
147 /// DripRate can never be above max drip rate or below min drip rate.
148 /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the
149 /// parent bucket.
150 /// </value>
151 public virtual Int64 DripRate
152 { 155 {
153 get 156 get {
154 { 157 float rate = Math.Min(RequestedDripRate,TotalDripRequest);
155 double rate; 158 if (m_parent == null)
156 159 return rate;
157 // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set
158 // on ourselves which is not equal to the child drip rates.
159 if (Parent == null)
160 {
161 if (TotalDripRequest > 0)
162 rate = Math.Min(RequestedDripRate, TotalDripRequest);
163 else
164 rate = RequestedDripRate;
165 }
166 else
167 {
168 rate = (double)RequestedDripRate * Parent.DripRateModifier();
169 }
170 160
161 rate *= m_parent.DripRateModifier();
171 if (rate < m_minimumDripRate) 162 if (rate < m_minimumDripRate)
172 rate = m_minimumDripRate; 163 rate = m_minimumDripRate;
173 else if (MaxDripRate > 0 && rate > MaxDripRate)
174 rate = MaxDripRate;
175 164
176 return (Int64)rate; 165 return (float)rate;
177 } 166 }
178 } 167 }
179 protected Int64 m_dripRate;
180
181 // <summary>
182 // The maximum rate for flow control. Drip rate can never be greater than this.
183 // </summary>
184 public Int64 MaxDripRate { get; set; }
185 168
186 /// <summary> 169 /// <summary>
187 /// The current total of the requested maximum burst rates of children buckets. 170 /// The current total of the requested maximum burst rates of children buckets.
188 /// </summary> 171 /// </summary>
189 public Int64 TotalDripRequest { get; protected set; } 172 protected float m_totalDripRequest;
173 public float TotalDripRequest
174 {
175 get { return m_totalDripRequest; }
176 set { m_totalDripRequest = value; }
177 }
178
179#endregion Properties
180
181#region Constructor
182
190 183
191 /// <summary> 184 /// <summary>
192 /// Default constructor 185 /// Default constructor
@@ -194,20 +187,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
194 /// <param name="identifier">Identifier for this token bucket</param> 187 /// <param name="identifier">Identifier for this token bucket</param>
195 /// <param name="parent">Parent bucket if this is a child bucket, or 188 /// <param name="parent">Parent bucket if this is a child bucket, or
196 /// null if this is a root bucket</param> 189 /// null if this is a root bucket</param>
197 /// <param name="requestedDripRate"> 190 /// <param name="maxBurst">Maximum size of the bucket in bytes, or
198 /// Requested rate that the bucket fills, in bytes per 191 /// zero if this bucket has no maximum capacity</param>
199 /// second. If zero, the bucket always remains full. 192 /// <param name="dripRate">Rate that the bucket fills, in bytes per
200 /// </param> 193 /// second. If zero, the bucket always remains full</param>
201 public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate) 194 public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst)
202 { 195 {
203 Identifier = identifier; 196 m_counter++;
204 197
205 Parent = parent; 198 Parent = parent;
206 RequestedDripRate = requestedDripRate; 199 RequestedDripRate = dripRate;
207 MaxDripRate = maxDripRate; 200 RequestedBurst = MaxBurst;
208 m_lastDrip = Util.EnvironmentTickCount(); 201 m_lastDrip = Util.GetTimeStampMS() + 100000.0; // skip first drip
209 } 202 }
210 203
204#endregion Constructor
205
211 /// <summary> 206 /// <summary>
212 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning 207 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
213 /// no modification if the requested bandwidth is less than the 208 /// no modification if the requested bandwidth is less than the
@@ -215,22 +210,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
215 /// hierarchy. However, if any of the parents is over-booked, then 210 /// hierarchy. However, if any of the parents is over-booked, then
216 /// the modifier will be less than 1. 211 /// the modifier will be less than 1.
217 /// </summary> 212 /// </summary>
218 protected double DripRateModifier() 213 protected float DripRateModifier()
219 { 214 {
220 Int64 driprate = DripRate; 215 float driprate = DripRate;
221 double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 216 return driprate >= TotalDripRequest ? 1.0f : (driprate / TotalDripRequest);
222
223// if (DebugLevel > 0)
224// m_log.DebugFormat(
225// "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}",
226// driprate, TotalDripRequest, modifier, Identifier);
227
228 return modifier;
229 } 217 }
230 218
231 /// <summary> 219 /// <summary>
232 /// </summary> 220 /// </summary>
233 protected double BurstRateModifier() 221 protected float BurstModifier()
234 { 222 {
235 // for now... burst rate is always m_quantumsPerBurst (constant) 223 // for now... burst rate is always m_quantumsPerBurst (constant)
236 // larger than drip rate so the ratio of burst requests is the 224 // larger than drip rate so the ratio of burst requests is the
@@ -242,29 +230,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
242 /// Register drip rate requested by a child of this throttle. Pass the 230 /// Register drip rate requested by a child of this throttle. Pass the
243 /// changes up the hierarchy. 231 /// changes up the hierarchy.
244 /// </summary> 232 /// </summary>
245 public void RegisterRequest(TokenBucket child, Int64 request) 233 public void RegisterRequest(TokenBucket child, float request)
246 { 234 {
247 lock (m_children) 235 lock (m_children)
248 { 236 {
249 m_children[child] = request; 237 m_children[child] = request;
250 238
251 TotalDripRequest = 0; 239 m_totalDripRequest = 0;
252 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 240 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
253 TotalDripRequest += cref.Value; 241 m_totalDripRequest += cref.Value;
254 } 242 }
255
256 // Pass the new values up to the parent
257 if (Parent != null)
258 {
259 Int64 effectiveDripRate;
260
261 if (RequestedDripRate > 0)
262 effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest);
263 else
264 effectiveDripRate = TotalDripRequest;
265 243
266 Parent.RegisterRequest(this, effectiveDripRate); 244 // Pass the new values up to the parent
267 } 245 if (m_parent != null)
246 m_parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest));
268 } 247 }
269 248
270 /// <summary> 249 /// <summary>
@@ -277,23 +256,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
277 { 256 {
278 m_children.Remove(child); 257 m_children.Remove(child);
279 258
280 TotalDripRequest = 0; 259 m_totalDripRequest = 0;
281 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 260 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
282 TotalDripRequest += cref.Value; 261 m_totalDripRequest += cref.Value;
283 } 262 }
284 263
285 // Pass the new values up to the parent 264 // Pass the new values up to the parent
286 if (Parent != null) 265 if (Parent != null)
287 Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); 266 Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
288 } 267 }
289 268
290 /// <summary> 269 /// <summary>
291 /// Remove a given number of tokens from the bucket 270 /// Remove a given number of tokens from the bucket
292 /// </summary> 271 /// </summary>
293 /// <param name="amount">Number of tokens to remove from the bucket</param> 272 /// <param name="amount">Number of tokens to remove from the bucket</param>
294 /// <returns>True if the requested number of tokens were removed from 273 /// <returns>True if the requested number of tokens were removed from
295 /// the bucket, otherwise false</returns> 274 /// the bucket, otherwise false</returns>
296 public bool RemoveTokens(Int64 amount) 275 public bool RemoveTokens(int amount)
297 { 276 {
298 // Deposit tokens for this interval 277 // Deposit tokens for this interval
299 Drip(); 278 Drip();
@@ -310,24 +289,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
310 return false; 289 return false;
311 } 290 }
312 291
313 /// <summary> 292 public bool CheckTokens(int amount)
314 /// Deposit tokens into the bucket from a child bucket that did
315 /// not use all of its available tokens
316 /// </summary>
317 protected void Deposit(Int64 count)
318 { 293 {
319 m_tokenCount += count; 294 return (m_tokenCount - amount >= 0);
295 }
320 296
321 // Deposit the overflow in the parent bucket, this is how we share 297 public int GetCatBytesCanSend(int timeMS)
322 // unused bandwidth 298 {
323 Int64 burstrate = BurstRate; 299// return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3);
324 if (m_tokenCount > burstrate) 300 return (int)(timeMS * DripRate * 1e-3);
325 m_tokenCount = burstrate;
326 } 301 }
327 302
328 /// <summary> 303 /// <summary>
329 /// Add tokens to the bucket over time. The number of tokens added each 304 /// Add tokens to the bucket over time. The number of tokens added each
330 /// call depends on the length of time that has passed since the last 305 /// call depends on the length of time that has passed since the last
331 /// call to Drip 306 /// call to Drip
332 /// </summary> 307 /// </summary>
333 /// <returns>True if tokens were added to the bucket, otherwise false</returns> 308 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
@@ -337,128 +312,106 @@ namespace OpenSim.Region.ClientStack.LindenUDP
337 // with no drip rate... 312 // with no drip rate...
338 if (DripRate == 0) 313 if (DripRate == 0)
339 { 314 {
340 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier); 315 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", m_counter);
341 return; 316 return;
342 } 317 }
343 318
344 // Determine the interval over which we are adding tokens, never add 319 double now = Util.GetTimeStampMS();
345 // more than a single quantum of tokens 320 double deltaMS = now - m_lastDrip;
346 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); 321 m_lastDrip = now;
347 m_lastDrip = Util.EnvironmentTickCount(); 322
348
349 // This can be 0 in the very unusual case that the timer wrapped
350 // It can be 0 if we try add tokens at a sub-tick rate
351 if (deltaMS <= 0) 323 if (deltaMS <= 0)
352 return; 324 return;
353 325
354 Deposit(deltaMS * DripRate / m_ticksPerQuantum); 326 m_tokenCount += (float)deltaMS * DripRate * m_timeScale;
327
328 float burst = Burst;
329 if (m_tokenCount > burst)
330 m_tokenCount = burst;
355 } 331 }
356 } 332 }
357 333
358 public class AdaptiveTokenBucket : TokenBucket 334 public class AdaptiveTokenBucket : TokenBucket
359 { 335 {
360 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 336 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
361 337
362 public bool AdaptiveEnabled { get; set; } 338 public bool AdaptiveEnabled { get; set; }
363 339
364 /// <summary> 340 /// <summary>
365 /// Target drip rate for this bucket. 341 /// The minimum rate for flow control. Minimum drip rate is one
342 /// packet per second.
366 /// </summary> 343 /// </summary>
367 /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks> 344
368 public Int64 TargetDripRate 345 protected const float m_minimumFlow = 50000;
369 { 346
370 get { return m_targetDripRate; } 347 // <summary>
371 set 348 // The maximum rate for flow control. Drip rate can never be
349 // greater than this.
350 // </summary>
351
352 public override float MaxDripRate
353 {
354 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
355 set
372 { 356 {
373 m_targetDripRate = Math.Max(value, m_minimumFlow); 357 m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow));
374 } 358 }
375 } 359 }
376 protected Int64 m_targetDripRate; 360
361 private bool m_enabled = false;
377 362
378 // <summary> 363 // <summary>
379 // Adjust drip rate in response to network conditions. 364 // Adjust drip rate in response to network conditions.
380 // </summary> 365 // </summary>
381 public virtual Int64 AdjustedDripRate 366 public float AdjustedDripRate
382 { 367 {
383 get { return m_dripRate; } 368 get { return m_dripRate; }
384 set 369 set
385 { 370 {
386 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate); 371 m_dripRate = OpenSim.Framework.Util.Clamp<float>(value, m_minimumFlow, MaxDripRate);
387 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
388 372
389 if (Parent != null) 373 if (m_parent != null)
390 Parent.RegisterRequest(this, m_dripRate); 374 m_parent.RegisterRequest(this, m_dripRate);
391 } 375 }
392 } 376 }
393
394 /// <summary>
395 /// The minimum rate for adaptive flow control.
396 /// </summary>
397 protected Int64 m_minimumFlow = 32000;
398 377
399 /// <summary>
400 /// Constructor for the AdaptiveTokenBucket class
401 /// <param name="identifier">Unique identifier for the client</param>
402 /// <param name="parent">Parent bucket in the hierarchy</param>
403 /// <param name="requestedDripRate"></param>
404 /// <param name="maxDripRate">The ceiling rate for adaptation</param>
405 /// <param name="minDripRate">The floor rate for adaptation</param>
406 /// </summary>
407 public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, Int64 minDripRate, bool enabled)
408 : base(identifier, parent, requestedDripRate, maxDripRate)
409 {
410 AdaptiveEnabled = enabled;
411 378
412 if (AdaptiveEnabled) 379 // <summary>
413 { 380 //
414// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); 381 // </summary>
415 m_minimumFlow = minDripRate; 382 public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled)
416 TargetDripRate = m_minimumFlow; 383 : base(parent, maxDripRate, maxBurst)
417 AdjustedDripRate = m_minimumFlow;
418 }
419 }
420
421 /// <summary>
422 /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
423 /// <param name="packets">Number of packets that expired without successful delivery</param>
424 /// </summary>
425 public void ExpirePackets(Int32 packets)
426 { 384 {
427 if (AdaptiveEnabled) 385 m_enabled = enabled;
428 {
429 if (DebugLevel > 0)
430 m_log.WarnFormat(
431 "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}",
432 AdjustedDripRate, packets, Identifier);
433 386
434 // AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets)); 387 m_maxDripRate = (maxDripRate == 0 ? m_totalDripRequest : Math.Max(maxDripRate, m_minimumFlow));
435 388
436 // Compute the fallback solely on the rate allocated beyond the minimum, this 389 if (enabled)
437 // should smooth out the fallback to the minimum rate 390 m_dripRate = m_maxDripRate * .5f;
438 AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets)); 391 else
439 } 392 m_dripRate = m_maxDripRate;
393 if (m_parent != null)
394 m_parent.RegisterRequest(this, m_dripRate);
440 } 395 }
441 396
442 /// <summary> 397 /// <summary>
443 /// Reliable packets acked by the client adjust the drip rate up. 398 /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
444 /// <param name="packets">Number of packets successfully acknowledged</param> 399 /// <param name="packets">Number of packets that expired without successful delivery</param>
445 /// </summary> 400 /// </summary>
446 public void AcknowledgePackets(Int32 packets) 401 public void ExpirePackets(Int32 count)
447 { 402 {
448 if (AdaptiveEnabled) 403 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
449 AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU; 404 if (m_enabled)
405 AdjustedDripRate = (Int64)(AdjustedDripRate / Math.Pow(2, count));
450 } 406 }
451 407
452 /// <summary> 408 // <summary>
453 /// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted 409 //
454 /// throttles back to the minimum levels 410 // </summary>
455 /// <param>minDripRate--the new minimum flow</param> 411 public void AcknowledgePackets(Int32 count)
456 /// </summary>
457 public void ResetMinimumAdaptiveFlow(Int64 minDripRate)
458 { 412 {
459 m_minimumFlow = minDripRate; 413 if (m_enabled)
460 TargetDripRate = m_minimumFlow; 414 AdjustedDripRate = AdjustedDripRate + count;
461 AdjustedDripRate = m_minimumFlow;
462 } 415 }
463 } 416 }
464} \ No newline at end of file 417}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
index b546a99..76f4c6f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
@@ -74,6 +74,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
74 /// <summary>Holds information about pending removals</summary> 74 /// <summary>Holds information about pending removals</summary>
75 private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>(); 75 private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>();
76 76
77
78 public void Clear()
79 {
80 m_packets.Clear();
81 m_pendingAdds = null;
82 m_pendingAcknowledgements = null;
83 m_pendingRemoves = null;
84 }
85
77 /// <summary> 86 /// <summary>
78 /// Add an unacked packet to the collection 87 /// Add an unacked packet to the collection
79 /// </summary> 88 /// </summary>
@@ -85,7 +94,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
85 public void Add(OutgoingPacket packet) 94 public void Add(OutgoingPacket packet)
86 { 95 {
87 m_pendingAdds.Enqueue(packet); 96 m_pendingAdds.Enqueue(packet);
88 Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength); 97 Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength);
89 } 98 }
90 99
91 /// <summary> 100 /// <summary>
@@ -107,7 +116,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
107 /// <summary> 116 /// <summary>
108 /// Marks a packet as no longer needing acknowledgement without a received acknowledgement. 117 /// Marks a packet as no longer needing acknowledgement without a received acknowledgement.
109 /// This method is called when a packet expires and we no longer need an acknowledgement. 118 /// This method is called when a packet expires and we no longer need an acknowledgement.
110 /// When some reliable packet types expire, they are handled in a way other than simply 119 /// When some reliable packet types expire, they are handled in a way other than simply
111 /// resending them. The only effect of removal this way is to update unacked byte count. 120 /// resending them. The only effect of removal this way is to update unacked byte count.
112 /// </summary> 121 /// </summary>
113 /// <param name="sequenceNumber">Sequence number of the packet to 122 /// <param name="sequenceNumber">Sequence number of the packet to
@@ -146,7 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
146 155
147 foreach (OutgoingPacket packet in m_packets.Values) 156 foreach (OutgoingPacket packet in m_packets.Values)
148 { 157 {
149 // TickCount of zero means a packet is in the resend queue 158 // TickCount of zero means a packet is in the resend queue
150 // but hasn't actually been sent over the wire yet 159 // but hasn't actually been sent over the wire yet
151 if (packet.TickCount == 0) 160 if (packet.TickCount == 0)
152 continue; 161 continue;
@@ -163,7 +172,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
163 // As with other network applications, assume that an expired packet is 172 // As with other network applications, assume that an expired packet is
164 // an indication of some network problem, slow transmission 173 // an indication of some network problem, slow transmission
165 packet.Client.FlowThrottle.ExpirePackets(1); 174 packet.Client.FlowThrottle.ExpirePackets(1);
166 175
167 expiredPackets.Add(packet); 176 expiredPackets.Add(packet);
168 } 177 }
169 } 178 }
@@ -182,7 +191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
182 while (m_pendingAdds.TryDequeue(out pendingAdd)) 191 while (m_pendingAdds.TryDequeue(out pendingAdd))
183 if (pendingAdd != null) 192 if (pendingAdd != null)
184 m_packets[pendingAdd.SequenceNumber] = pendingAdd; 193 m_packets[pendingAdd.SequenceNumber] = pendingAdd;
185 194
186 // Process all the pending removes, including updating statistics and round-trip times 195 // Process all the pending removes, including updating statistics and round-trip times
187 PendingAck pendingAcknowledgement; 196 PendingAck pendingAcknowledgement;
188 while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement)) 197 while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement))
@@ -219,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
219 else 228 else
220 { 229 {
221 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack", 230 // m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack",
222 // pendingAcknowledgement.SequenceNumber); 231 // pendingAcknowledgement.SequenceNumber);
223 } 232 }
224 } 233 }
225 234
diff --git a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
index 0b6ee2f..e859653 100644
--- a/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ClientStack/Properties/AssemblyInfo.cs
@@ -2,7 +2,7 @@
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4 4
5// General Information about an assembly is controlled through the following 5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly. 7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.ClientStack")] 8[assembly: AssemblyTitle("OpenSim.Region.ClientStack")]
@@ -14,8 +14,8 @@ using System.Runtime.InteropServices;
14[assembly: AssemblyTrademark("")] 14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")] 15[assembly: AssemblyCulture("")]
16 16
17// Setting ComVisible to false makes the types in this assembly not visible 17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from 18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type. 19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)] 20[assembly: ComVisible(false)]
21 21
@@ -25,7 +25,7 @@ using System.Runtime.InteropServices;
25// Version information for an assembly consists of the following four values: 25// Version information for an assembly consists of the following four values:
26// 26//
27// Major Version 27// Major Version
28// Minor Version 28// Minor Version
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//