aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs1070
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs703
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs474
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs21
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs404
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs426
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs297
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs5
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs164
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs13
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1704
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs325
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs305
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs17
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs12
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs370
22 files changed, 4134 insertions, 2222 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 774202e..1236e83 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -26,6 +26,7 @@
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;
31using System.IO; 32using System.IO;
@@ -44,7 +45,6 @@ using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization; 45using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Framework.Servers; 46using OpenSim.Framework.Servers;
46using OpenSim.Framework.Servers.HttpServer; 47using OpenSim.Framework.Servers.HttpServer;
47using OpenSim.Framework.Client;
48using OpenSim.Services.Interfaces; 48using OpenSim.Services.Interfaces;
49 49
50using Caps = OpenSim.Framework.Capabilities.Caps; 50using Caps = OpenSim.Framework.Capabilities.Caps;
@@ -55,14 +55,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
55namespace OpenSim.Region.ClientStack.Linden 55namespace OpenSim.Region.ClientStack.Linden
56{ 56{
57 public delegate void UpLoadedAsset( 57 public delegate void UpLoadedAsset(
58 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 58 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
59 byte[] data, string inventoryType, string assetType); 59 byte[] data, string inventoryType, string assetType,
60 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
61 bool IsAtestUpload, ref string error);
60 62
61 public delegate UUID UpdateItem(UUID itemID, byte[] data); 63 public delegate UUID UpdateItem(UUID itemID, byte[] data);
62 64
63 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 65 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
64 66
65 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 67 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
66 68
67 public delegate void NewAsset(AssetBase asset); 69 public delegate void NewAsset(AssetBase asset);
68 70
@@ -88,6 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden
88 90
89 private Scene m_Scene; 91 private Scene m_Scene;
90 private Caps m_HostCapsObj; 92 private Caps m_HostCapsObj;
93 private ModelCost m_ModelCost;
91 94
92 private static readonly string m_requestPath = "0000/"; 95 private static readonly string m_requestPath = "0000/";
93 // private static readonly string m_mapLayerPath = "0001/"; 96 // private static readonly string m_mapLayerPath = "0001/";
@@ -99,8 +102,10 @@ namespace OpenSim.Region.ClientStack.Linden
99 private static readonly string m_copyFromNotecardPath = "0007/"; 102 private static readonly string m_copyFromNotecardPath = "0007/";
100 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 103 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
101 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 104 private static readonly string m_getObjectPhysicsDataPath = "0101/";
102 /* 0102 - 0103 RESERVED */ 105 private static readonly string m_getObjectCostPath = "0102/";
106 private static readonly string m_ResourceCostSelectedPath = "0103/";
103 private static readonly string m_UpdateAgentInformationPath = "0500/"; 107 private static readonly string m_UpdateAgentInformationPath = "0500/";
108 private static readonly string m_animSetTaskUpdatePath = "0260/";
104 109
105 // These are callbacks which will be setup by the scene so that we can update scene data when we 110 // These are callbacks which will be setup by the scene so that we can update scene data when we
106 // receive capability calls 111 // receive capability calls
@@ -115,12 +120,50 @@ namespace OpenSim.Region.ClientStack.Linden
115 private IAssetService m_assetService; 120 private IAssetService m_assetService;
116 private bool m_dumpAssetsToFile = false; 121 private bool m_dumpAssetsToFile = false;
117 private string m_regionName; 122 private string m_regionName;
123
118 private int m_levelUpload = 0; 124 private int m_levelUpload = 0;
119 125
126 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
127 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
128
129 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
130 // may not be visible till relog
131
132 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
133 private UUID m_testAssetsCreatorID = UUID.Zero;
134
135 private float m_PrimScaleMin = 0.001f;
136
137 private enum FileAgentInventoryState : int
138 {
139 idle = 0,
140 processRequest = 1,
141 waitUpload = 2,
142 processUpload = 3
143 }
144 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
145
120 public BunchOfCaps(Scene scene, Caps caps) 146 public BunchOfCaps(Scene scene, Caps caps)
121 { 147 {
122 m_Scene = scene; 148 m_Scene = scene;
123 m_HostCapsObj = caps; 149 m_HostCapsObj = caps;
150
151 // create a model upload cost provider
152 m_ModelCost = new ModelCost();
153 // tell it about scene object limits
154 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
155 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
156
157// m_ModelCost.ObjectLinkedPartsMax = ??
158// m_ModelCost.PrimScaleMin = ??
159
160 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
161 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
162 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
163 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
164 float modelPrimCreationCost = m_ModelCost.primCreationCost;
165 float modelMeshByteCost = m_ModelCost.bytecost;
166
124 IConfigSource config = m_Scene.Config; 167 IConfigSource config = m_Scene.Config;
125 if (config != null) 168 if (config != null)
126 { 169 {
@@ -135,6 +178,37 @@ namespace OpenSim.Region.ClientStack.Linden
135 { 178 {
136 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 179 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
137 } 180 }
181 // economy for model upload
182 IConfig EconomyConfig = config.Configs["Economy"];
183 if (EconomyConfig != null)
184 {
185 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
186 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
187 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
188 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
189 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
190 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
191
192 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
193
194 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
195 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
196 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
197 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
198 if (testcreator != "")
199 {
200 UUID id;
201 UUID.TryParse(testcreator, out id);
202 if (id != null)
203 m_testAssetsCreatorID = id;
204 }
205
206 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
207 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
208 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
209 m_ModelCost.primCreationCost = modelPrimCreationCost;
210 m_ModelCost.bytecost = modelMeshByteCost;
211 }
138 } 212 }
139 213
140 m_assetService = m_Scene.AssetService; 214 m_assetService = m_Scene.AssetService;
@@ -146,6 +220,8 @@ namespace OpenSim.Region.ClientStack.Linden
146 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 220 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
147 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 221 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
148 GetClient = m_Scene.SceneGraph.GetControllingClient; 222 GetClient = m_Scene.SceneGraph.GetControllingClient;
223
224 m_FileAgentInventoryState = FileAgentInventoryState.idle;
149 } 225 }
150 226
151 /// <summary> 227 /// <summary>
@@ -173,13 +249,31 @@ namespace OpenSim.Region.ClientStack.Linden
173 //m_capsHandlers["MapLayer"] = 249 //m_capsHandlers["MapLayer"] =
174 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", 250 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
175 // capsBase + m_mapLayerPath, 251 // capsBase + m_mapLayerPath,
176 // GetMapLayer); 252 // GetMapLayer);
253
254 IRequestHandler getObjectPhysicsDataHandler
255 = new RestStreamHandler(
256 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
257 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
258
259 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
260 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
261 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
262 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
263
264
177 IRequestHandler req 265 IRequestHandler req
178 = new RestStreamHandler( 266 = new RestStreamHandler(
179 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); 267 "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null);
180 268
181 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); 269 m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
182 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); 270 m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
271
272// IRequestHandler animSetRequestHandler
273// = new RestStreamHandler(
274// "POST", capsBase + m_animSetTaskUpdatePath, AnimSetTaskInventory, "UpdateScript", null);
275
276// m_HostCapsObj.RegisterHandler("UpdateAnimSetTaskInventory", animSetRequestHandler);
183 } 277 }
184 catch (Exception e) 278 catch (Exception e)
185 { 279 {
@@ -191,7 +285,6 @@ namespace OpenSim.Region.ClientStack.Linden
191 { 285 {
192 try 286 try
193 { 287 {
194 // I don't think this one works...
195 m_HostCapsObj.RegisterHandler( 288 m_HostCapsObj.RegisterHandler(
196 "NewFileAgentInventory", 289 "NewFileAgentInventory",
197 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 290 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -206,13 +299,11 @@ namespace OpenSim.Region.ClientStack.Linden
206 "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null); 299 "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null);
207 300
208 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 301 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
302 m_HostCapsObj.RegisterHandler("UpdateAnimSetAgentInventory", req);
209 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 303 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
210 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 304 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
211 305
212 IRequestHandler getObjectPhysicsDataHandler 306
213 = new RestStreamHandler(
214 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
215 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
216 307
217 IRequestHandler UpdateAgentInformationHandler 308 IRequestHandler UpdateAgentInformationHandler
218 = new RestStreamHandler( 309 = new RestStreamHandler(
@@ -268,8 +359,11 @@ namespace OpenSim.Region.ClientStack.Linden
268 public string SeedCapRequest(string request, string path, string param, 359 public string SeedCapRequest(string request, string path, string param,
269 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 360 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
270 { 361 {
271// m_log.DebugFormat( 362 m_log.DebugFormat(
272// "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 363 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
364
365 if (!m_HostCapsObj.WaitForActivation())
366 return string.Empty;
273 367
274 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 368 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
275 { 369 {
@@ -400,62 +494,178 @@ namespace OpenSim.Region.ClientStack.Linden
400 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 494 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
401 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 495 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
402 496
497 // start by getting the client
498 IClientAPI client = null;
499 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
500
501 // check current state so we only have one service at a time
502 lock (m_ModelCost)
503 {
504 switch (m_FileAgentInventoryState)
505 {
506 case FileAgentInventoryState.processRequest:
507 case FileAgentInventoryState.processUpload:
508 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
509 resperror.message = "Uploader busy processing previus request";
510 resperror.identifier = UUID.Zero;
511
512 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
513 errorResponse.uploader = "";
514 errorResponse.state = "error";
515 errorResponse.error = resperror;
516 return errorResponse;
517 break;
518 case FileAgentInventoryState.waitUpload:
519 // todo stop current uploader server
520 break;
521 case FileAgentInventoryState.idle:
522 default:
523 break;
524 }
525
526 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
527 }
528
529 int cost = 0;
530 int nreqtextures = 0;
531 int nreqmeshs= 0;
532 int nreqinstances = 0;
533 bool IsAtestUpload = false;
534
535 string assetName = llsdRequest.name;
536
537 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
538
403 if (llsdRequest.asset_type == "texture" || 539 if (llsdRequest.asset_type == "texture" ||
404 llsdRequest.asset_type == "animation" || 540 llsdRequest.asset_type == "animation" ||
541 llsdRequest.asset_type == "animatn" || // this is the asset name actually used by viewers
542 llsdRequest.asset_type == "mesh" ||
405 llsdRequest.asset_type == "sound") 543 llsdRequest.asset_type == "sound")
406 { 544 {
407 ScenePresence avatar = null; 545 ScenePresence avatar = null;
408 IClientAPI client = null;
409 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 546 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
410 547
411 // check user level 548 // check user level
412 if (avatar != null) 549 if (avatar != null)
413 { 550 {
414 client = avatar.ControllingClient;
415
416 if (avatar.UserLevel < m_levelUpload) 551 if (avatar.UserLevel < m_levelUpload)
417 { 552 {
418 if (client != null) 553 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
419 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 554 resperror.message = "Insufficient permissions to upload";
555 resperror.identifier = UUID.Zero;
420 556
421 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 557 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
422 errorResponse.uploader = ""; 558 errorResponse.uploader = "";
423 errorResponse.state = "error"; 559 errorResponse.state = "error";
560 errorResponse.error = resperror;
561 lock (m_ModelCost)
562 m_FileAgentInventoryState = FileAgentInventoryState.idle;
424 return errorResponse; 563 return errorResponse;
425 } 564 }
426 } 565 }
427 566
428 // check funds 567 // check test upload and funds
429 if (client != null) 568 if (client != null)
430 { 569 {
431 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 570 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
432 571
572 int baseCost = 0;
433 if (mm != null) 573 if (mm != null)
574 baseCost = mm.UploadCharge;
575
576 string warning = String.Empty;
577
578 if (llsdRequest.asset_type == "mesh")
434 { 579 {
435 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 580 string error;
581 int modelcost;
582
583
584 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
585 meshcostdata, out error, ref warning))
436 { 586 {
437 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 587 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
588 resperror.message = error;
589 resperror.identifier = UUID.Zero;
438 590
439 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 591 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
440 errorResponse.uploader = ""; 592 errorResponse.uploader = "";
441 errorResponse.state = "error"; 593 errorResponse.state = "error";
594 errorResponse.error = resperror;
595
596 lock (m_ModelCost)
597 m_FileAgentInventoryState = FileAgentInventoryState.idle;
442 return errorResponse; 598 return errorResponse;
443 } 599 }
600 cost = modelcost;
601 }
602 else
603 {
604 cost = baseCost;
605 }
606
607 if (cost > 0 && mm != null)
608 {
609 // check for test upload
610
611 if (m_ForceFreeTestUpload) // all are test
612 {
613 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
614 assetName = "TEST-" + assetName;
615
616 IsAtestUpload = true;
617 }
618
619 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
620 {
621
622 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
623 }
624
625
626 if(IsAtestUpload) // let user know, still showing cost estimation
627 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";
628
629 // check funds
630 else
631 {
632 if (!mm.UploadCovered(client.AgentId, (int)cost))
633 {
634 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
635 resperror.message = "Insuficient funds";
636 resperror.identifier = UUID.Zero;
637
638 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
639 errorResponse.uploader = "";
640 errorResponse.state = "error";
641 errorResponse.error = resperror;
642 lock (m_ModelCost)
643 m_FileAgentInventoryState = FileAgentInventoryState.idle;
644 return errorResponse;
645 }
646 }
444 } 647 }
648
649 if (client != null && warning != String.Empty)
650 client.SendAgentAlertMessage(warning, true);
445 } 651 }
446 } 652 }
447 653
448 string assetName = llsdRequest.name;
449 string assetDes = llsdRequest.description; 654 string assetDes = llsdRequest.description;
450 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 655 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
451 UUID newAsset = UUID.Random(); 656 UUID newAsset = UUID.Random();
452 UUID newInvItem = UUID.Random(); 657 UUID newInvItem = UUID.Random();
453 UUID parentFolder = llsdRequest.folder_id; 658 UUID parentFolder = llsdRequest.folder_id;
454 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 659 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
660 UUID texturesFolder = UUID.Zero;
661
662 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
663 texturesFolder = llsdRequest.texture_folder_id;
455 664
456 AssetUploader uploader = 665 AssetUploader uploader =
457 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 666 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
458 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 667 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
668 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
459 669
460 m_HostCapsObj.HttpListener.AddStreamHandler( 670 m_HostCapsObj.HttpListener.AddStreamHandler(
461 new BinaryStreamHandler( 671 new BinaryStreamHandler(
@@ -473,10 +683,22 @@ namespace OpenSim.Region.ClientStack.Linden
473 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 683 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
474 uploaderPath; 684 uploaderPath;
475 685
686
476 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 687 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
477 uploadResponse.uploader = uploaderURL; 688 uploadResponse.uploader = uploaderURL;
478 uploadResponse.state = "upload"; 689 uploadResponse.state = "upload";
690 uploadResponse.upload_price = (int)cost;
691
692 if (llsdRequest.asset_type == "mesh")
693 {
694 uploadResponse.data = meshcostdata;
695 }
696
479 uploader.OnUpLoad += UploadCompleteHandler; 697 uploader.OnUpLoad += UploadCompleteHandler;
698
699 lock (m_ModelCost)
700 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
701
480 return uploadResponse; 702 return uploadResponse;
481 } 703 }
482 704
@@ -488,8 +710,14 @@ namespace OpenSim.Region.ClientStack.Linden
488 /// <param name="data"></param> 710 /// <param name="data"></param>
489 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 711 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
490 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 712 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
491 string assetType) 713 string assetType, int cost,
714 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
715 bool IsAtestUpload, ref string error)
492 { 716 {
717
718 lock (m_ModelCost)
719 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
720
493 m_log.DebugFormat( 721 m_log.DebugFormat(
494 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 722 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
495 assetID, inventoryItem, inventoryType, assetType); 723 assetID, inventoryItem, inventoryType, assetType);
@@ -497,6 +725,34 @@ namespace OpenSim.Region.ClientStack.Linden
497 sbyte assType = 0; 725 sbyte assType = 0;
498 sbyte inType = 0; 726 sbyte inType = 0;
499 727
728 IClientAPI client = null;
729
730 UUID owner_id = m_HostCapsObj.AgentID;
731 UUID creatorID;
732
733 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
734
735 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
736
737 if (istest && m_testAssetsCreatorID != UUID.Zero)
738 creatorID = m_testAssetsCreatorID;
739 else
740 creatorID = owner_id;
741
742 string creatorIDstr = creatorID.ToString();
743
744 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
745 if (mm != null)
746 {
747 // make sure client still has enougth credit
748 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
749 {
750 error = "Insufficient funds.";
751 return;
752 }
753 }
754
755 // strings to types
500 if (inventoryType == "sound") 756 if (inventoryType == "sound")
501 { 757 {
502 inType = (sbyte)InventoryType.Sound; 758 inType = (sbyte)InventoryType.Sound;
@@ -511,6 +767,12 @@ namespace OpenSim.Region.ClientStack.Linden
511 inType = (sbyte)InventoryType.Animation; 767 inType = (sbyte)InventoryType.Animation;
512 assType = (sbyte)AssetType.Animation; 768 assType = (sbyte)AssetType.Animation;
513 } 769 }
770 else if (inventoryType == "animset")
771 {
772 inType = (sbyte)CustomInventoryType.AnimationSet;
773 assType = (sbyte)CustomAssetType.AnimationSet;
774 m_log.Debug("got animset upload request");
775 }
514 else if (inventoryType == "wearable") 776 else if (inventoryType == "wearable")
515 { 777 {
516 inType = (sbyte)InventoryType.Wearable; 778 inType = (sbyte)InventoryType.Wearable;
@@ -526,159 +788,253 @@ namespace OpenSim.Region.ClientStack.Linden
526 } 788 }
527 else if (inventoryType == "object") 789 else if (inventoryType == "object")
528 { 790 {
529 inType = (sbyte)InventoryType.Object; 791 if (assetType == "mesh") // this code for now is for mesh models uploads only
530 assType = (sbyte)AssetType.Object;
531
532 List<Vector3> positions = new List<Vector3>();
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
540 InventoryFolderBase textureUploadFolder = null;
541
542 List<InventoryFolderBase> foldersToUpdate = new List<InventoryFolderBase>();
543 List<InventoryItemBase> itemsToUpdate = new List<InventoryItemBase>();
544 IClientInventory clientInv = null;
545
546 if (texture_list.Count > 0)
547 { 792 {
548 ScenePresence avatar = null; 793 inType = (sbyte)InventoryType.Object;
549 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 794 assType = (sbyte)AssetType.Object;
795
796 List<Vector3> positions = new List<Vector3>();
797 List<Quaternion> rotations = new List<Quaternion>();
798 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
799
800 // compare and get updated information
801/* does nothing still we do need something to avoid special viewer to upload something diferent from the cost estimation
802 bool mismatchError = true;
550 803
551 if (avatar != null) 804 while (mismatchError)
552 { 805 {
553 IClientCore core = (IClientCore)avatar.ControllingClient; 806 mismatchError = false;
807 }
808
809 if (mismatchError)
810 {
811 error = "Upload and fee estimation information don't match";
812 lock (m_ModelCost)
813 m_FileAgentInventoryState = FileAgentInventoryState.idle;
814
815 return;
816 }
817*/
818 OSDArray instance_list = (OSDArray)request["instance_list"];
819 OSDArray mesh_list = (OSDArray)request["mesh_list"];
820 OSDArray texture_list = (OSDArray)request["texture_list"];
821 SceneObjectGroup grp = null;
822
823 // create and store texture assets
824 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
825 texturesFolder != UUID.Zero);
554 826
555 if (core.TryGet<IClientInventory>(out clientInv)) 827
828 List<UUID> textures = new List<UUID>();
829
830
831// if (doTextInv)
832 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
833
834 if(client == null) // don't put textures in inventory if there is no client
835 doTextInv = false;
836
837 for (int i = 0; i < texture_list.Count; i++)
838 {
839 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
840 textureAsset.Data = texture_list[i].AsBinary();
841 if (istest)
842 textureAsset.Local = true;
843 m_assetService.Store(textureAsset);
844 textures.Add(textureAsset.FullID);
845
846 if (doTextInv)
556 { 847 {
557 var systemTextureFolder = m_Scene.InventoryService.GetFolderForType(m_HostCapsObj.AgentID, FolderType.Texture); 848 string name = assetName;
558 textureUploadFolder = new InventoryFolderBase(UUID.Random(), assetName, m_HostCapsObj.AgentID, (short)FolderType.None, systemTextureFolder.ID, 1); 849 if (name.Length > 25)
559 if (m_Scene.InventoryService.AddFolder(textureUploadFolder)) 850 name = name.Substring(0, 24);
560 { 851 name += "_Texture#" + i.ToString();
561 foldersToUpdate.Add(textureUploadFolder); 852 InventoryItemBase texitem = new InventoryItemBase();
853 texitem.Owner = m_HostCapsObj.AgentID;
854 texitem.CreatorId = creatorIDstr;
855 texitem.CreatorData = String.Empty;
856 texitem.ID = UUID.Random();
857 texitem.AssetID = textureAsset.FullID;
858 texitem.Description = "mesh model texture";
859 texitem.Name = name;
860 texitem.AssetType = (int)AssetType.Texture;
861 texitem.InvType = (int)InventoryType.Texture;
862 texitem.Folder = texturesFolder;
863
864 texitem.CurrentPermissions
865 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
866
867 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
868 texitem.EveryOnePermissions = 0;
869 texitem.NextPermissions = (uint)PermissionMask.All;
870 texitem.CreationDate = Util.UnixTimeSinceEpoch();
871
872 m_Scene.AddInventoryItem(client, texitem);
873 texitem = null;
874 }
875 }
562 876
563 m_log.DebugFormat( 877 // create and store meshs assets
564 "[BUNCH OF CAPS]: Created new folder '{0}' ({1}) for textures uploaded with mesh object {2}", 878 List<UUID> meshAssets = new List<UUID>();
565 textureUploadFolder.Name, textureUploadFolder.ID, assetName); 879 List<bool> meshAvatarSkeletons = new List<bool>();
566 } 880 List<bool> meshAvatarColliders = new List<bool>();
567 else 881
882 bool curAvSkeleton;
883 bool curAvCollider;
884 for (int i = 0; i < mesh_list.Count; i++)
885 {
886 curAvSkeleton = false;
887 curAvCollider = false;
888
889 // we do need to parse the mesh now
890 OSD osd = OSDParser.DeserializeLLSDBinary(mesh_list[i]);
891 if (osd is OSDMap)
892 {
893 OSDMap mosd = (OSDMap)osd;
894 if (mosd.ContainsKey("skeleton"))
568 { 895 {
569 textureUploadFolder = null; 896 OSDMap skeleton = (OSDMap)mosd["skeleton"];
897 int sksize = skeleton["size"].AsInteger();
898 if (sksize > 0)
899 curAvSkeleton = true;
570 } 900 }
571 } 901 }
572 }
573 }
574 902
575 List<UUID> textures = new List<UUID>(); 903 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
576 for (int i = 0; i < texture_list.Count; i++) 904 meshAsset.Data = mesh_list[i].AsBinary();
577 { 905 if (istest)
578 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 906 meshAsset.Local = true;
579 textureAsset.Data = texture_list[i].AsBinary(); 907 m_assetService.Store(meshAsset);
580 m_assetService.Store(textureAsset); 908 meshAssets.Add(meshAsset.FullID);
581 textures.Add(textureAsset.FullID); 909 meshAvatarSkeletons.Add(curAvSkeleton);
910 meshAvatarColliders.Add(curAvCollider);
911
912 // test code
913 if (curAvSkeleton && client != null)
914 {
915 string name = assetName;
916 if (name.Length > 25)
917 name = name.Substring(0, 24);
918 name += "_Mesh#" + i.ToString();
919 InventoryItemBase meshitem = new InventoryItemBase();
920 meshitem.Owner = m_HostCapsObj.AgentID;
921 meshitem.CreatorId = creatorIDstr;
922 meshitem.CreatorData = String.Empty;
923 meshitem.ID = UUID.Random();
924 meshitem.AssetID = meshAsset.FullID;
925 meshitem.Description = "mesh ";
926 meshitem.Name = name;
927 meshitem.AssetType = (int)AssetType.Mesh;
928 meshitem.InvType = (int)InventoryType.Mesh;
929 // meshitem.Folder = UUID.Zero; // send to default
930
931 meshitem.Folder = parentFolder; // dont let it go to folder Meshes that viewers dont show
932
933 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
934 // (owner) permissions. This becomes a problem if next permissions are changed.
935 meshitem.CurrentPermissions
936 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
937
938 meshitem.BasePermissions = (uint)PermissionMask.All;
939 meshitem.EveryOnePermissions = 0;
940 meshitem.NextPermissions = (uint)PermissionMask.All;
941 meshitem.CreationDate = Util.UnixTimeSinceEpoch();
942
943 m_Scene.AddInventoryItem(client, meshitem);
944 meshitem = null;
945 }
946 }
582 947
583 if (textureUploadFolder != null) 948 int skipedMeshs = 0;
949 // build prims from instances
950 for (int i = 0; i < instance_list.Count; i++)
584 { 951 {
585 InventoryItemBase textureItem = new InventoryItemBase(); 952 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 953
611 if (clientInv != null && (foldersToUpdate.Count > 0 || itemsToUpdate.Count > 0)) 954 // skip prims that are 2 small
612 { 955 Vector3 scale = inner_instance_list["scale"].AsVector3();
613 clientInv.SendBulkUpdateInventory(foldersToUpdate.ToArray(), itemsToUpdate.ToArray());
614 }
615 956
616 for (int i = 0; i < mesh_list.Count; i++) 957 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
617 { 958 {
618 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 959 skipedMeshs++;
960 continue;
961 }
619 962
620 Primitive.TextureEntry textureEntry 963 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
621 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
622 OSDMap inner_instance_list = (OSDMap)instance_list[i];
623 964
624 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 965 Primitive.TextureEntry textureEntry
625 for (uint face = 0; face < face_list.Count; face++) 966 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
626 {
627 OSDMap faceMap = (OSDMap)face_list[(int)face];
628 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
629 if(faceMap.ContainsKey("fullbright"))
630 f.Fullbright = faceMap["fullbright"].AsBoolean();
631 if (faceMap.ContainsKey ("diffuse_color"))
632 f.RGBA = faceMap["diffuse_color"].AsColor4();
633 967
634 int textureNum = faceMap["image"].AsInteger();
635 float imagerot = faceMap["imagerot"].AsInteger();
636 float offsets = (float)faceMap["offsets"].AsReal();
637 float offsett = (float)faceMap["offsett"].AsReal();
638 float scales = (float)faceMap["scales"].AsReal();
639 float scalet = (float)faceMap["scalet"].AsReal();
640 968
641 if(imagerot != 0) 969 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
642 f.Rotation = imagerot; 970 for (uint face = 0; face < face_list.Count; face++)
971 {
972 OSDMap faceMap = (OSDMap)face_list[(int)face];
973 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
974 if (faceMap.ContainsKey("fullbright"))
975 f.Fullbright = faceMap["fullbright"].AsBoolean();
976 if (faceMap.ContainsKey("diffuse_color"))
977 f.RGBA = faceMap["diffuse_color"].AsColor4();
643 978
644 if(offsets != 0) 979 int textureNum = faceMap["image"].AsInteger();
645 f.OffsetU = offsets; 980 float imagerot = faceMap["imagerot"].AsInteger();
981 float offsets = (float)faceMap["offsets"].AsReal();
982 float offsett = (float)faceMap["offsett"].AsReal();
983 float scales = (float)faceMap["scales"].AsReal();
984 float scalet = (float)faceMap["scalet"].AsReal();
646 985
647 if (offsett != 0) 986 if (imagerot != 0)
648 f.OffsetV = offsett; 987 f.Rotation = imagerot;
649 988
650 if (scales != 0) 989 if (offsets != 0)
651 f.RepeatU = scales; 990 f.OffsetU = offsets;
652 991
653 if (scalet != 0) 992 if (offsett != 0)
654 f.RepeatV = scalet; 993 f.OffsetV = offsett;
655 994
656 if (textures.Count > textureNum) 995 if (scales != 0)
657 f.TextureID = textures[textureNum]; 996 f.RepeatU = scales;
658 else
659 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
660 997
661 textureEntry.FaceTextures[face] = f; 998 if (scalet != 0)
662 } 999 f.RepeatV = scalet;
663 1000
664 pbs.TextureEntry = textureEntry.GetBytes(); 1001 if (textures.Count > textureNum)
1002 f.TextureID = textures[textureNum];
1003 else
1004 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
665 1005
666 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 1006 textureEntry.FaceTextures[face] = f;
667 meshAsset.Data = mesh_list[i].AsBinary(); 1007 }
668 m_assetService.Store(meshAsset);
669 1008
670 pbs.SculptEntry = true; 1009 pbs.TextureEntry = textureEntry.GetBytes();
671 pbs.SculptTexture = meshAsset.FullID;
672 pbs.SculptType = (byte)SculptType.Mesh;
673 pbs.SculptData = meshAsset.Data;
674 1010
675 Vector3 position = inner_instance_list["position"].AsVector3(); 1011 bool hasmesh = false;
676 Vector3 scale = inner_instance_list["scale"].AsVector3(); 1012 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
677 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 1013 {
1014 int meshindx = inner_instance_list["mesh"].AsInteger();
1015 if (meshAssets.Count > meshindx)
1016 {
1017 pbs.SculptEntry = true;
1018 pbs.SculptType = (byte)SculptType.Mesh;
1019 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
1020 // data will be requested from asset on rez (i hope)
1021 hasmesh = true;
1022 }
1023 }
1024
1025 Vector3 position = inner_instance_list["position"].AsVector3();
1026 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
1027
1028 // for now viwers do send fixed defaults
1029 // but this may change
1030// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
1031 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
1032 if(hasmesh)
1033 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
1034// int material = inner_instance_list["material"].AsInteger();
1035 byte material = (byte)Material.Wood;
678 1036
679// no longer used - begin ------------------------ 1037// no longer used - begin ------------------------
680// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
681// int material = inner_instance_list["material"].AsInteger();
682// int mesh = inner_instance_list["mesh"].AsInteger(); 1038// int mesh = inner_instance_list["mesh"].AsInteger();
683 1039
684// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 1040// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -693,24 +1049,49 @@ namespace OpenSim.Region.ClientStack.Linden
693// UUID owner_id = permissions["owner_id"].AsUUID(); 1049// UUID owner_id = permissions["owner_id"].AsUUID();
694// int owner_mask = permissions["owner_mask"].AsInteger(); 1050// int owner_mask = permissions["owner_mask"].AsInteger();
695// no longer used - end ------------------------ 1051// no longer used - end ------------------------
1052
1053
1054 SceneObjectPart prim
1055 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
1056
1057 prim.Scale = scale;
1058 rotations.Add(rotation);
1059 positions.Add(position);
1060 prim.UUID = UUID.Random();
1061 prim.CreatorID = creatorID;
1062 prim.OwnerID = owner_id;
1063 prim.GroupID = UUID.Zero;
1064 prim.LastOwnerID = creatorID;
1065 prim.CreationDate = Util.UnixTimeSinceEpoch();
1066
1067 if (grp == null)
1068 prim.Name = assetName;
1069 else
1070 prim.Name = assetName + "#" + i.ToString();
696 1071
697 UUID owner_id = m_HostCapsObj.AgentID; 1072 prim.EveryoneMask = 0;
1073 prim.GroupMask = 0;
698 1074
699 SceneObjectPart prim 1075 if (restrictPerms)
700 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 1076 {
1077 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1078 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1079 prim.NextOwnerMask = 0;
1080 }
1081 else
1082 {
1083 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1084 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1085 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1086 }
701 1087
702 prim.Scale = scale; 1088 if(istest)
703 //prim.OffsetPosition = position; 1089 prim.Description = "For testing only. Other uses are prohibited";
704 rotations.Add(rotation); 1090 else
705 positions.Add(position); 1091 prim.Description = "";
706 prim.UUID = UUID.Random(); 1092
707 prim.CreatorID = owner_id; 1093 prim.Material = material;
708 prim.OwnerID = owner_id; 1094 prim.PhysicsShapeType = physicsShapeType;
709 prim.GroupID = UUID.Zero;
710 prim.LastOwnerID = prim.OwnerID;
711 prim.CreationDate = Util.UnixTimeSinceEpoch();
712 prim.Name = assetName;
713 prim.Description = "";
714 1095
715// prim.BaseMask = (uint)base_mask; 1096// prim.BaseMask = (uint)base_mask;
716// prim.EveryoneMask = (uint)everyone_mask; 1097// prim.EveryoneMask = (uint)everyone_mask;
@@ -718,52 +1099,64 @@ namespace OpenSim.Region.ClientStack.Linden
718// prim.NextOwnerMask = (uint)next_owner_mask; 1099// prim.NextOwnerMask = (uint)next_owner_mask;
719// prim.OwnerMask = (uint)owner_mask; 1100// prim.OwnerMask = (uint)owner_mask;
720 1101
721 if (grp == null) 1102 if (grp == null)
722 grp = new SceneObjectGroup(prim); 1103 {
723 else 1104 grp = new SceneObjectGroup(prim);
724 grp.AddPart(prim); 1105 grp.LastOwnerID = creatorID;
725 } 1106 }
1107 else
1108 grp.AddPart(prim);
1109 }
726 1110
727 Vector3 rootPos = positions[0]; 1111 Vector3 rootPos = positions[0];
728 1112
729 if (grp.Parts.Length > 1) 1113 if (grp.Parts.Length > 1)
730 { 1114 {
731 // Fix first link number 1115 // Fix first link number
732 grp.RootPart.LinkNum++; 1116 grp.RootPart.LinkNum++;
733 1117
734 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1118 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
735 Quaternion tmprot; 1119 Quaternion tmprot;
736 Vector3 offset; 1120 Vector3 offset;
737 1121
738 // fix children rotations and positions 1122 // fix children rotations and positions
739 for (int i = 1; i < rotations.Count; i++) 1123 for (int i = 1; i < rotations.Count; i++)
740 { 1124 {
741 tmprot = rotations[i]; 1125 tmprot = rotations[i];
742 tmprot = rootRotConj * tmprot; 1126 tmprot = rootRotConj * tmprot;
743 1127
744 grp.Parts[i].RotationOffset = tmprot; 1128 grp.Parts[i].RotationOffset = tmprot;
745 1129
746 offset = positions[i] - rootPos; 1130 offset = positions[i] - rootPos;
747 1131
748 offset *= rootRotConj; 1132 offset *= rootRotConj;
749 grp.Parts[i].OffsetPosition = offset; 1133 grp.Parts[i].OffsetPosition = offset;
1134 }
1135
1136 grp.AbsolutePosition = rootPos;
1137 grp.UpdateGroupRotationR(rotations[0]);
1138 }
1139 else
1140 {
1141 grp.AbsolutePosition = rootPos;
1142 grp.UpdateGroupRotationR(rotations[0]);
750 } 1143 }
751 1144
752 grp.AbsolutePosition = rootPos; 1145 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
753 grp.UpdateGroupRotationR(rotations[0]);
754 } 1146 }
755 else 1147
1148 else // not a mesh model
756 { 1149 {
757 grp.AbsolutePosition = rootPos; 1150 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
758 grp.UpdateGroupRotationR(rotations[0]); 1151 return;
759 } 1152 }
760
761 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
762 } 1153 }
763 1154
764 AssetBase asset; 1155 AssetBase asset;
765 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1156 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
766 asset.Data = data; 1157 asset.Data = data;
1158 if (istest)
1159 asset.Local = true;
767 if (AddNewAsset != null) 1160 if (AddNewAsset != null)
768 AddNewAsset(asset); 1161 AddNewAsset(asset);
769 else if (m_assetService != null) 1162 else if (m_assetService != null)
@@ -771,11 +1164,17 @@ namespace OpenSim.Region.ClientStack.Linden
771 1164
772 InventoryItemBase item = new InventoryItemBase(); 1165 InventoryItemBase item = new InventoryItemBase();
773 item.Owner = m_HostCapsObj.AgentID; 1166 item.Owner = m_HostCapsObj.AgentID;
774 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1167 item.CreatorId = creatorIDstr;
775 item.CreatorData = String.Empty; 1168 item.CreatorData = String.Empty;
776 item.ID = inventoryItem; 1169 item.ID = inventoryItem;
777 item.AssetID = asset.FullID; 1170 item.AssetID = asset.FullID;
778 item.Description = assetDescription; 1171 if (istest)
1172 {
1173 item.Description = "For testing only. Other uses are prohibited";
1174 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1175 }
1176 else
1177 item.Description = assetDescription;
779 item.Name = assetName; 1178 item.Name = assetName;
780 item.AssetType = assType; 1179 item.AssetType = assType;
781 item.InvType = inType; 1180 item.InvType = inType;
@@ -783,18 +1182,61 @@ namespace OpenSim.Region.ClientStack.Linden
783 1182
784 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1183 // 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. 1184 // (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 1185
789 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1186 if (inType == (sbyte)CustomInventoryType.AnimationSet)
790 item.EveryOnePermissions = 0; 1187 {
791 item.NextPermissions = (uint)PermissionMask.All; 1188 AnimationSet.setCreateItemPermitions(item);
1189 }
1190
1191 else if (restrictPerms)
1192 {
1193 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1194 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1195 item.EveryOnePermissions = 0;
1196 item.NextPermissions = 0;
1197 }
1198 else
1199 {
1200 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1201 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1202 item.EveryOnePermissions = 0;
1203 item.NextPermissions = (uint)PermissionMask.Transfer;
1204 }
1205
792 item.CreationDate = Util.UnixTimeSinceEpoch(); 1206 item.CreationDate = Util.UnixTimeSinceEpoch();
793 1207
1208 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1209
794 if (AddNewInventoryItem != null) 1210 if (AddNewInventoryItem != null)
795 { 1211 {
796 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1212 if (istest)
1213 {
1214 m_Scene.AddInventoryItem(client, item);
1215/*
1216 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1217 if (client != null)
1218 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);
1219 */
1220 }
1221 else
1222 {
1223 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1224// if (client != null)
1225// {
1226// // let users see anything.. i don't so far
1227// string str;
1228// if (cost > 0)
1229// // dont remember where is money unit name to put here
1230// str = "Upload complete. charged " + cost.ToString() + "$";
1231// else
1232// str = "Upload complete";
1233// client.SendAgentAlertMessage(str, true);
1234// }
1235 }
797 } 1236 }
1237
1238 lock (m_ModelCost)
1239 m_FileAgentInventoryState = FileAgentInventoryState.idle;
798 } 1240 }
799 1241
800 /// <summary> 1242 /// <summary>
@@ -935,24 +1377,17 @@ namespace OpenSim.Region.ClientStack.Linden
935 { 1377 {
936 string message; 1378 string message;
937 copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message); 1379 copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message);
938 if (client != null) 1380 if (copyItem != null && client != null)
939 { 1381 {
940 if (copyItem != null) 1382 m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder);
941 { 1383 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 } 1384 }
950 } 1385 }
951 else 1386 else
952 { 1387 {
953 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID); 1388 m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID);
954 if (client != null) 1389 if (client != null)
955 client.SendAgentAlertMessage("Failed to retrieve item", false); 1390 client.SendAlertMessage("Failed to retrieve item");
956 } 1391 }
957 } 1392 }
958 catch (Exception e) 1393 catch (Exception e)
@@ -995,18 +1430,142 @@ namespace OpenSim.Region.ClientStack.Linden
995 return response; 1430 return response;
996 } 1431 }
997 1432
998 public string UpdateAgentInformation(string request, string path, 1433 public string GetObjectCost(string request, string path,
1434 string param, IOSHttpRequest httpRequest,
1435 IOSHttpResponse httpResponse)
1436 {
1437 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1438 OSDMap resp = new OSDMap();
1439
1440 OSDArray object_ids = (OSDArray)req["object_ids"];
1441
1442 for (int i = 0; i < object_ids.Count; i++)
1443 {
1444 UUID uuid = object_ids[i].AsUUID();
1445
1446 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1447
1448 if (part != null)
1449 {
1450 SceneObjectGroup grp = part.ParentGroup;
1451 if (grp != null)
1452 {
1453 float linksetCost;
1454 float linksetPhysCost;
1455 float partCost;
1456 float partPhysCost;
1457
1458 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1459
1460 OSDMap object_data = new OSDMap();
1461 object_data["linked_set_resource_cost"] = linksetCost;
1462 object_data["resource_cost"] = partCost;
1463 object_data["physics_cost"] = partPhysCost;
1464 object_data["linked_set_physics_cost"] = linksetPhysCost;
1465
1466 resp[uuid.ToString()] = object_data;
1467 }
1468 else
1469 {
1470 OSDMap object_data = new OSDMap();
1471 object_data["linked_set_resource_cost"] = 0;
1472 object_data["resource_cost"] = 0;
1473 object_data["physics_cost"] = 0;
1474 object_data["linked_set_physics_cost"] = 0;
1475
1476 resp[uuid.ToString()] = object_data;
1477 }
1478
1479 }
1480 }
1481
1482 string response = OSDParser.SerializeLLSDXmlString(resp);
1483 return response;
1484 }
1485
1486 public string ResourceCostSelected(string request, string path,
999 string param, IOSHttpRequest httpRequest, 1487 string param, IOSHttpRequest httpRequest,
1000 IOSHttpResponse httpResponse) 1488 IOSHttpResponse httpResponse)
1001 { 1489 {
1002 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); 1490 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1003 OSDMap accessPrefs = (OSDMap)req["access_prefs"]; 1491 OSDMap resp = new OSDMap();
1004 string desiredMaturity = accessPrefs["max"]; 1492
1493
1494 float phys=0;
1495 float stream=0;
1496 float simul=0;
1497
1498 if (req.ContainsKey("selected_roots"))
1499 {
1500 OSDArray object_ids = (OSDArray)req["selected_roots"];
1501
1502 // should go by SOG suming costs for all parts
1503 // ll v3 works ok with several objects select we get the list and adds ok
1504 // FS calls per object so results are wrong guess fs bug
1505 for (int i = 0; i < object_ids.Count; i++)
1506 {
1507 UUID uuid = object_ids[i].AsUUID();
1508 float Physc;
1509 float simulc;
1510 float streamc;
1511
1512 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1513 if (grp != null)
1514 {
1515 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1516 phys += Physc;
1517 stream += streamc;
1518 simul += simulc;
1519 }
1520 }
1521 }
1522 else if (req.ContainsKey("selected_prims"))
1523 {
1524 OSDArray object_ids = (OSDArray)req["selected_prims"];
1525
1526 // don't see in use in any of the 2 viewers
1527 // guess it should be for edit linked but... nothing
1528 // should go to SOP per part
1529 for (int i = 0; i < object_ids.Count; i++)
1530 {
1531 UUID uuid = object_ids[i].AsUUID();
1532
1533 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1534 if (part != null)
1535 {
1536 phys += part.PhysicsCost;
1537 stream += part.StreamingCost;
1538 simul += part.SimulationCost;
1539 }
1540 }
1541 }
1542
1543 // if (simul != 0)
1544 {
1545 OSDMap object_data = new OSDMap();
1546
1547 object_data["physics"] = phys;
1548 object_data["streaming"] = stream;
1549 object_data["simulation"] = simul;
1550
1551 resp["selected"] = object_data;
1552 }
1553
1554 string response = OSDParser.SerializeLLSDXmlString(resp);
1555 return response;
1556 }
1005 1557
1558 public string UpdateAgentInformation(string request, string path,
1559 string param, IOSHttpRequest httpRequest,
1560 IOSHttpResponse httpResponse)
1561 {
1562// OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1006 OSDMap resp = new OSDMap(); 1563 OSDMap resp = new OSDMap();
1007 OSDMap respAccessPrefs = new OSDMap(); 1564
1008 respAccessPrefs["max"] = desiredMaturity; // echoing the maturity back means success 1565 OSDMap accessPrefs = new OSDMap();
1009 resp["access_prefs"] = respAccessPrefs; 1566 accessPrefs["max"] = "A";
1567
1568 resp["access_prefs"] = accessPrefs;
1010 1569
1011 string response = OSDParser.SerializeLLSDXmlString(resp); 1570 string response = OSDParser.SerializeLLSDXmlString(resp);
1012 return response; 1571 return response;
@@ -1015,6 +1574,10 @@ namespace OpenSim.Region.ClientStack.Linden
1015 1574
1016 public class AssetUploader 1575 public class AssetUploader
1017 { 1576 {
1577 private static readonly ILog m_log =
1578 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1579
1580
1018 public event UpLoadedAsset OnUpLoad; 1581 public event UpLoadedAsset OnUpLoad;
1019 private UpLoadedAsset handlerUpLoad = null; 1582 private UpLoadedAsset handlerUpLoad = null;
1020 1583
@@ -1029,10 +1592,21 @@ namespace OpenSim.Region.ClientStack.Linden
1029 1592
1030 private string m_invType = String.Empty; 1593 private string m_invType = String.Empty;
1031 private string m_assetType = String.Empty; 1594 private string m_assetType = String.Empty;
1032 1595 private int m_cost;
1596 private string m_error = String.Empty;
1597
1598 private Timer m_timeoutTimer = new Timer();
1599 private UUID m_texturesFolder;
1600 private int m_nreqtextures;
1601 private int m_nreqmeshs;
1602 private int m_nreqinstances;
1603 private bool m_IsAtestUpload;
1604
1033 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1605 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
1034 UUID parentFolderID, string invType, string assetType, string path, 1606 UUID parentFolderID, string invType, string assetType, string path,
1035 IHttpServer httpServer, bool dumpAssetsToFile) 1607 IHttpServer httpServer, bool dumpAssetsToFile,
1608 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1609 bool IsAtestUpload)
1036 { 1610 {
1037 m_assetName = assetName; 1611 m_assetName = assetName;
1038 m_assetDes = description; 1612 m_assetDes = description;
@@ -1044,6 +1618,18 @@ namespace OpenSim.Region.ClientStack.Linden
1044 m_assetType = assetType; 1618 m_assetType = assetType;
1045 m_invType = invType; 1619 m_invType = invType;
1046 m_dumpAssetsToFile = dumpAssetsToFile; 1620 m_dumpAssetsToFile = dumpAssetsToFile;
1621 m_cost = totalCost;
1622
1623 m_texturesFolder = texturesFolder;
1624 m_nreqtextures = nreqtextures;
1625 m_nreqmeshs = nreqmeshs;
1626 m_nreqinstances = nreqinstances;
1627 m_IsAtestUpload = IsAtestUpload;
1628
1629 m_timeoutTimer.Elapsed += TimedOut;
1630 m_timeoutTimer.Interval = 120000;
1631 m_timeoutTimer.AutoReset = false;
1632 m_timeoutTimer.Start();
1047 } 1633 }
1048 1634
1049 /// <summary> 1635 /// <summary>
@@ -1058,12 +1644,14 @@ namespace OpenSim.Region.ClientStack.Linden
1058 UUID inv = inventoryItemID; 1644 UUID inv = inventoryItemID;
1059 string res = String.Empty; 1645 string res = String.Empty;
1060 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1646 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1647/*
1061 uploadComplete.new_asset = newAssetID.ToString(); 1648 uploadComplete.new_asset = newAssetID.ToString();
1062 uploadComplete.new_inventory_item = inv; 1649 uploadComplete.new_inventory_item = inv;
1063 uploadComplete.state = "complete"; 1650 uploadComplete.state = "complete";
1064 1651
1065 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1652 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1066 1653*/
1654 m_timeoutTimer.Stop();
1067 httpListener.RemoveStreamHandler("POST", uploaderPath); 1655 httpListener.RemoveStreamHandler("POST", uploaderPath);
1068 1656
1069 // TODO: probably make this a better set of extensions here 1657 // TODO: probably make this a better set of extensions here
@@ -1080,12 +1668,50 @@ namespace OpenSim.Region.ClientStack.Linden
1080 handlerUpLoad = OnUpLoad; 1668 handlerUpLoad = OnUpLoad;
1081 if (handlerUpLoad != null) 1669 if (handlerUpLoad != null)
1082 { 1670 {
1083 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1671 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1672 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload,
1673 ref m_error);
1674 }
1675 if (m_IsAtestUpload)
1676 {
1677 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1678 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1679 resperror.identifier = inv;
1680
1681 uploadComplete.error = resperror;
1682 uploadComplete.state = "Upload4Testing";
1683 }
1684 else
1685 {
1686 if (m_error == String.Empty)
1687 {
1688 uploadComplete.new_asset = newAssetID.ToString();
1689 uploadComplete.new_inventory_item = inv;
1690 // if (m_texturesFolder != UUID.Zero)
1691 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1692 uploadComplete.state = "complete";
1693 }
1694 else
1695 {
1696 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1697 resperror.message = m_error;
1698 resperror.identifier = inv;
1699
1700 uploadComplete.error = resperror;
1701 uploadComplete.state = "failed";
1702 }
1084 } 1703 }
1085 1704
1705 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1086 return res; 1706 return res;
1087 } 1707 }
1088 1708
1709 private void TimedOut(object sender, ElapsedEventArgs args)
1710 {
1711 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1712 httpListener.RemoveStreamHandler("POST", uploaderPath);
1713 }
1714
1089 ///Left this in and commented in case there are unforseen issues 1715 ///Left this in and commented in case there are unforseen issues
1090 //private void SaveAssetToFile(string filename, byte[] data) 1716 //private void SaveAssetToFile(string filename, byte[] data)
1091 //{ 1717 //{
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..546bcd9
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
@@ -0,0 +1,703 @@
1// Proprietary code of Avination Virtual Limited
2// (c) 2012 Melanie Thielker, Leal Duarte
3//
4
5using System;
6using System.IO;
7using System.Collections;
8using System.Collections.Generic;
9using System.Text;
10
11using OpenMetaverse;
12using OpenMetaverse.StructuredData;
13
14using OpenSim.Framework;
15using OpenSim.Region.Framework;
16using OpenSim.Region.Framework.Scenes;
17using OpenSim.Framework.Capabilities;
18
19using ComponentAce.Compression.Libs.zlib;
20
21using OSDArray = OpenMetaverse.StructuredData.OSDArray;
22using OSDMap = OpenMetaverse.StructuredData.OSDMap;
23
24namespace OpenSim.Region.ClientStack.Linden
25{
26 public struct ModelPrimLimits
27 {
28
29 }
30
31 public class ModelCost
32 {
33
34 // upload fee defaults
35 // fees are normalized to 1.0
36 // this parameters scale them to basic cost ( so 1.0 translates to 10 )
37
38 public float ModelMeshCostFactor = 0.0f; // scale total cost relative to basic (excluding textures)
39 public float ModelTextureCostFactor = 1.0f; // scale textures fee to basic.
40 public float ModelMinCostFactor = 0.0f; // 0.5f; // minimum total model free excluding textures
41
42 // itens costs in normalized values
43 // ie will be multiplied by basicCost and factors above
44 public float primCreationCost = 0.002f; // extra cost for each prim creation overhead
45 // weigthed size to normalized cost
46 public float bytecost = 1e-5f;
47
48 // mesh upload fees based on compressed data sizes
49 // several data sections are counted more that once
50 // to promote user optimization
51 // following parameters control how many extra times they are added
52 // to global size.
53 // LOD meshs
54 const float medSizeWth = 1f; // 2x
55 const float lowSizeWth = 1.5f; // 2.5x
56 const float lowestSizeWth = 2f; // 3x
57 // favor potencially physical optimized meshs versus automatic decomposition
58 const float physMeshSizeWth = 6f; // counts 7x
59 const float physHullSizeWth = 8f; // counts 9x
60
61 // stream cost area factors
62 // more or less like SL
63 const float highLodFactor = 17.36f;
64 const float midLodFactor = 277.78f;
65 const float lowLodFactor = 1111.11f;
66
67 // physics cost is below, identical to SL, assuming shape type convex
68 // server cost is below identical to SL assuming non scripted non physical object
69
70 // internal
71 const int bytesPerCoord = 6; // 3 coords, 2 bytes per each
72
73 // control prims dimensions
74 public float PrimScaleMin = 0.001f;
75 public float NonPhysicalPrimScaleMax = 256f;
76 public float PhysicalPrimScaleMax = 10f;
77 public int ObjectLinkedPartsMax = 512;
78
79 // storage for a single mesh asset cost parameters
80 private class ameshCostParam
81 {
82 // LOD sizes for size dependent streaming cost
83 public int highLODSize;
84 public int medLODSize;
85 public int lowLODSize;
86 public int lowestLODSize;
87 // normalized fee based on compressed data sizes
88 public float costFee;
89 // physics cost
90 public float physicsCost;
91 }
92
93 // calculates a mesh model costs
94 // returns false on error, with a reason on parameter error
95 // resources input LLSD request
96 // basicCost input region assets upload cost
97 // totalcost returns model total upload fee
98 // meshcostdata returns detailed costs for viewer
99 // avatarSkeleton if mesh includes a avatar skeleton
100 // useAvatarCollider if we should use physics mesh for avatar
101 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost,
102 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
103 {
104 totalcost = 0;
105 error = string.Empty;
106
107 bool avatarSkeleton = false;
108
109 if (resources == null ||
110 resources.instance_list == null ||
111 resources.instance_list.Array.Count == 0)
112 {
113 error = "missing model information.";
114 return false;
115 }
116
117 int numberInstances = resources.instance_list.Array.Count;
118
119 if( numberInstances > ObjectLinkedPartsMax )
120 {
121 error = "Model whould have more than " + ObjectLinkedPartsMax.ToString() + " linked prims";
122 return false;
123 }
124
125 meshcostdata.model_streaming_cost = 0.0;
126 meshcostdata.simulation_cost = 0.0;
127 meshcostdata.physics_cost = 0.0;
128 meshcostdata.resource_cost = 0.0;
129
130 meshcostdata.upload_price_breakdown.mesh_instance = 0;
131 meshcostdata.upload_price_breakdown.mesh_physics = 0;
132 meshcostdata.upload_price_breakdown.mesh_streaming = 0;
133 meshcostdata.upload_price_breakdown.model = 0;
134
135 int itmp;
136
137 // textures cost
138 if (resources.texture_list != null && resources.texture_list.Array.Count > 0)
139 {
140 float textures_cost = (float)(resources.texture_list.Array.Count * basicCost);
141 textures_cost *= ModelTextureCostFactor;
142
143 itmp = (int)(textures_cost + 0.5f); // round
144 meshcostdata.upload_price_breakdown.texture = itmp;
145 totalcost += itmp;
146 }
147
148 // meshs assets cost
149 float meshsfee = 0;
150 int numberMeshs = 0;
151 bool haveMeshs = false;
152
153 bool curskeleton;
154 bool curAvatarPhys;
155
156 List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
157
158 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
159 {
160 numberMeshs = resources.mesh_list.Array.Count;
161
162 for (int i = 0; i < numberMeshs; i++)
163 {
164 ameshCostParam curCost = new ameshCostParam();
165 byte[] data = (byte[])resources.mesh_list.Array[i];
166
167 if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error))
168 {
169 return false;
170 }
171
172 if (curskeleton)
173 {
174 if (avatarSkeleton)
175 {
176 error = "model can only contain a avatar skeleton";
177 return false;
178 }
179 avatarSkeleton = true;
180 }
181 meshsCosts.Add(curCost);
182 meshsfee += curCost.costFee;
183 }
184 haveMeshs = true;
185 }
186
187 // instances (prims) cost
188
189
190 int mesh;
191 int skipedSmall = 0;
192 for (int i = 0; i < numberInstances; i++)
193 {
194 Hashtable inst = (Hashtable)resources.instance_list.Array[i];
195
196 ArrayList ascale = (ArrayList)inst["scale"];
197 Vector3 scale;
198 double tmp;
199 tmp = (double)ascale[0];
200 scale.X = (float)tmp;
201 tmp = (double)ascale[1];
202 scale.Y = (float)tmp;
203 tmp = (double)ascale[2];
204 scale.Z = (float)tmp;
205
206 if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin)
207 {
208 skipedSmall++;
209 continue;
210 }
211
212 if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax)
213 {
214 error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale";
215 return false;
216 }
217
218 if (haveMeshs && inst.ContainsKey("mesh"))
219 {
220 mesh = (int)inst["mesh"];
221
222 if (mesh >= numberMeshs)
223 {
224 error = "Incoerent model information.";
225 return false;
226 }
227
228 // streamming cost
229
230 float sqdiam = scale.LengthSquared();
231
232 ameshCostParam curCost = meshsCosts[mesh];
233 float mesh_streaming = streamingCost(curCost, sqdiam);
234
235 meshcostdata.model_streaming_cost += mesh_streaming;
236 meshcostdata.physics_cost += curCost.physicsCost;
237 }
238 else // instance as no mesh ??
239 {
240 // to do later if needed
241 meshcostdata.model_streaming_cost += 0.5f;
242 meshcostdata.physics_cost += 1.0f;
243 }
244
245 // assume unscripted and static prim server cost
246 meshcostdata.simulation_cost += 0.5f;
247 // charge for prims creation
248 meshsfee += primCreationCost;
249 }
250
251 if (skipedSmall > 0)
252 {
253 if (skipedSmall > numberInstances / 2)
254 {
255 error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() +
256 "m minimum allowed size. Please check scalling";
257 return false;
258 }
259 else
260 warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() +
261 " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() +
262 "m minimum allowed size. Please check scalling ";
263 }
264
265 if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost)
266 meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
267 else
268 meshcostdata.resource_cost = meshcostdata.physics_cost;
269
270 if (meshcostdata.resource_cost < meshcostdata.simulation_cost)
271 meshcostdata.resource_cost = meshcostdata.simulation_cost;
272
273 // scale cost
274 // at this point a cost of 1.0 whould mean basic cost
275 meshsfee *= ModelMeshCostFactor;
276
277 if (meshsfee < ModelMinCostFactor)
278 meshsfee = ModelMinCostFactor;
279
280 // actually scale it to basic cost
281 meshsfee *= (float)basicCost;
282
283 meshsfee += 0.5f; // rounding
284
285 totalcost += (int)meshsfee;
286
287 // breakdown prices
288 // don't seem to be in use so removed code for now
289
290 return true;
291 }
292
293 // single mesh asset cost
294 private bool MeshCost(byte[] data, ameshCostParam cost,out bool skeleton, out bool avatarPhys, out string error)
295 {
296 cost.highLODSize = 0;
297 cost.medLODSize = 0;
298 cost.lowLODSize = 0;
299 cost.lowestLODSize = 0;
300 cost.physicsCost = 0.0f;
301 cost.costFee = 0.0f;
302
303 error = string.Empty;
304
305 skeleton = false;
306 avatarPhys = false;
307
308 if (data == null || data.Length == 0)
309 {
310 error = "Missing model information.";
311 return false;
312 }
313
314 OSD meshOsd = null;
315 int start = 0;
316
317 error = "Invalid model data";
318
319 using (MemoryStream ms = new MemoryStream(data))
320 {
321 try
322 {
323 OSD osd = OSDParser.DeserializeLLSDBinary(ms);
324 if (osd is OSDMap)
325 meshOsd = (OSDMap)osd;
326 else
327 return false;
328 }
329 catch (Exception e)
330 {
331 return false;
332 }
333 start = (int)ms.Position;
334 }
335
336 OSDMap map = (OSDMap)meshOsd;
337 OSDMap tmpmap;
338
339 int highlod_size = 0;
340 int medlod_size = 0;
341 int lowlod_size = 0;
342 int lowestlod_size = 0;
343 int skin_size = 0;
344
345 int hulls_size = 0;
346 int phys_nhulls;
347 int phys_hullsvertices = 0;
348
349 int physmesh_size = 0;
350 int phys_ntriangles = 0;
351
352 int submesh_offset = -1;
353
354 if (map.ContainsKey("skeleton"))
355 {
356 tmpmap = (OSDMap)map["skeleton"];
357 if (tmpmap.ContainsKey("offset") && tmpmap.ContainsKey("size"))
358 {
359 int sksize = tmpmap["size"].AsInteger();
360 if(sksize > 0)
361 skeleton = true;
362 }
363 }
364
365 if (map.ContainsKey("physics_convex"))
366 {
367 tmpmap = (OSDMap)map["physics_convex"];
368 if (tmpmap.ContainsKey("offset"))
369 submesh_offset = tmpmap["offset"].AsInteger() + start;
370 if (tmpmap.ContainsKey("size"))
371 hulls_size = tmpmap["size"].AsInteger();
372 }
373
374 if (submesh_offset < 0 || hulls_size == 0)
375 {
376 error = "Missing physics_convex block";
377 return false;
378 }
379
380 if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
381 {
382 error = "Bad physics_convex block";
383 return false;
384 }
385
386 submesh_offset = -1;
387
388 // only look for LOD meshs sizes
389
390 if (map.ContainsKey("high_lod"))
391 {
392 tmpmap = (OSDMap)map["high_lod"];
393 // see at least if there is a offset for this one
394 if (tmpmap.ContainsKey("offset"))
395 submesh_offset = tmpmap["offset"].AsInteger() + start;
396 if (tmpmap.ContainsKey("size"))
397 highlod_size = tmpmap["size"].AsInteger();
398 }
399
400 if (submesh_offset < 0 || highlod_size <= 0)
401 {
402 error = "Missing high_lod block";
403 return false;
404 }
405
406 bool haveprev = true;
407
408 if (map.ContainsKey("medium_lod"))
409 {
410 tmpmap = (OSDMap)map["medium_lod"];
411 if (tmpmap.ContainsKey("size"))
412 medlod_size = tmpmap["size"].AsInteger();
413 else
414 haveprev = false;
415 }
416
417 if (haveprev && map.ContainsKey("low_lod"))
418 {
419 tmpmap = (OSDMap)map["low_lod"];
420 if (tmpmap.ContainsKey("size"))
421 lowlod_size = tmpmap["size"].AsInteger();
422 else
423 haveprev = false;
424 }
425
426 if (haveprev && map.ContainsKey("lowest_lod"))
427 {
428 tmpmap = (OSDMap)map["lowest_lod"];
429 if (tmpmap.ContainsKey("size"))
430 lowestlod_size = tmpmap["size"].AsInteger();
431 }
432
433 if (map.ContainsKey("skin"))
434 {
435 tmpmap = (OSDMap)map["skin"];
436 if (tmpmap.ContainsKey("size"))
437 skin_size = tmpmap["size"].AsInteger();
438 }
439
440 cost.highLODSize = highlod_size;
441 cost.medLODSize = medlod_size;
442 cost.lowLODSize = lowlod_size;
443 cost.lowestLODSize = lowestlod_size;
444
445 submesh_offset = -1;
446
447 tmpmap = null;
448 if(map.ContainsKey("physics_mesh"))
449 tmpmap = (OSDMap)map["physics_mesh"];
450 else if (map.ContainsKey("physics_shape")) // old naming
451 tmpmap = (OSDMap)map["physics_shape"];
452
453 if(tmpmap != null)
454 {
455 if (tmpmap.ContainsKey("offset"))
456 submesh_offset = tmpmap["offset"].AsInteger() + start;
457 if (tmpmap.ContainsKey("size"))
458 physmesh_size = tmpmap["size"].AsInteger();
459
460 if (submesh_offset >= 0 || physmesh_size > 0)
461 {
462
463 if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
464 {
465 error = "Model data parsing error";
466 return false;
467 }
468 }
469 }
470
471 // upload is done in convex shape type so only one hull
472 phys_hullsvertices++;
473 cost.physicsCost = 0.04f * phys_hullsvertices;
474
475 float sfee;
476
477 sfee = data.Length; // start with total compressed data size
478
479 // penalize lod meshs that should be more builder optimized
480 sfee += medSizeWth * medlod_size;
481 sfee += lowSizeWth * lowlod_size;
482 sfee += lowestSizeWth * lowlod_size;
483
484 // physics
485 // favor potencial optimized meshs versus automatic decomposition
486 if (physmesh_size != 0)
487 sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull
488 else
489 sfee += physHullSizeWth * hulls_size;
490
491 // bytes to money
492 sfee *= bytecost;
493
494 cost.costFee = sfee;
495 return true;
496 }
497
498 // parses a LOD or physics mesh component
499 private bool submesh(byte[] data, int offset, int size, out int ntriangles)
500 {
501 ntriangles = 0;
502
503 OSD decodedMeshOsd = new OSD();
504 byte[] meshBytes = new byte[size];
505 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
506 try
507 {
508 using (MemoryStream inMs = new MemoryStream(meshBytes))
509 {
510 using (MemoryStream outMs = new MemoryStream())
511 {
512 using (ZOutputStream zOut = new ZOutputStream(outMs))
513 {
514 byte[] readBuffer = new byte[4096];
515 int readLen = 0;
516 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
517 {
518 zOut.Write(readBuffer, 0, readLen);
519 }
520 zOut.Flush();
521 outMs.Seek(0, SeekOrigin.Begin);
522
523 byte[] decompressedBuf = outMs.GetBuffer();
524 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
525 }
526 }
527 }
528 }
529 catch (Exception e)
530 {
531 return false;
532 }
533
534 OSDArray decodedMeshOsdArray = null;
535 if ((!decodedMeshOsd is OSDArray))
536 return false;
537
538 byte[] dummy;
539
540 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
541 foreach (OSD subMeshOsd in decodedMeshOsdArray)
542 {
543 if (subMeshOsd is OSDMap)
544 {
545 OSDMap subtmpmap = (OSDMap)subMeshOsd;
546 if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"]))
547 continue;
548
549 if (!subtmpmap.ContainsKey("Position"))
550 return false;
551
552 if (subtmpmap.ContainsKey("TriangleList"))
553 {
554 dummy = subtmpmap["TriangleList"].AsBinary();
555 ntriangles += dummy.Length / bytesPerCoord;
556 }
557 else
558 return false;
559 }
560 }
561
562 return true;
563 }
564
565 // parses convex hulls component
566 private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls)
567 {
568 nvertices = 0;
569 nhulls = 1;
570
571 OSD decodedMeshOsd = new OSD();
572 byte[] meshBytes = new byte[size];
573 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
574 try
575 {
576 using (MemoryStream inMs = new MemoryStream(meshBytes))
577 {
578 using (MemoryStream outMs = new MemoryStream())
579 {
580 using (ZOutputStream zOut = new ZOutputStream(outMs))
581 {
582 byte[] readBuffer = new byte[4096];
583 int readLen = 0;
584 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
585 {
586 zOut.Write(readBuffer, 0, readLen);
587 }
588 zOut.Flush();
589 outMs.Seek(0, SeekOrigin.Begin);
590
591 byte[] decompressedBuf = outMs.GetBuffer();
592 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
593 }
594 }
595 }
596 }
597 catch (Exception e)
598 {
599 return false;
600 }
601
602 OSDMap cmap = (OSDMap)decodedMeshOsd;
603 if (cmap == null)
604 return false;
605
606 byte[] dummy;
607
608 // must have one of this
609 if (cmap.ContainsKey("BoundingVerts"))
610 {
611 dummy = cmap["BoundingVerts"].AsBinary();
612 nvertices = dummy.Length / bytesPerCoord;
613 }
614 else
615 return false;
616
617/* upload is done with convex shape type
618 if (cmap.ContainsKey("HullList"))
619 {
620 dummy = cmap["HullList"].AsBinary();
621 nhulls += dummy.Length;
622 }
623
624
625 if (cmap.ContainsKey("Positions"))
626 {
627 dummy = cmap["Positions"].AsBinary();
628 nvertices = dummy.Length / bytesPerCoord;
629 }
630 */
631
632 return true;
633 }
634
635 // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length
636 private float streamingCost(ameshCostParam curCost, float sqdiam)
637 {
638 // compute efective areas
639 float ma = 262144f;
640
641 float mh = sqdiam * highLodFactor;
642 if (mh > ma)
643 mh = ma;
644 float mm = sqdiam * midLodFactor;
645 if (mm > ma)
646 mm = ma;
647
648 float ml = sqdiam * lowLodFactor;
649 if (ml > ma)
650 ml = ma;
651
652 float mlst = ma;
653
654 mlst -= ml;
655 ml -= mm;
656 mm -= mh;
657
658 if (mlst < 1.0f)
659 mlst = 1.0f;
660 if (ml < 1.0f)
661 ml = 1.0f;
662 if (mm < 1.0f)
663 mm = 1.0f;
664 if (mh < 1.0f)
665 mh = 1.0f;
666
667 ma = mlst + ml + mm + mh;
668
669 // get LODs compressed sizes
670 // giving 384 bytes bonus
671 int lst = curCost.lowestLODSize - 384;
672 int l = curCost.lowLODSize - 384;
673 int m = curCost.medLODSize - 384;
674 int h = curCost.highLODSize - 384;
675
676 // use previus higher LOD size on missing ones
677 if (m <= 0)
678 m = h;
679 if (l <= 0)
680 l = m;
681 if (lst <= 0)
682 lst = l;
683
684 // force minumum sizes
685 if (lst < 16)
686 lst = 16;
687 if (l < 16)
688 l = 16;
689 if (m < 16)
690 m = 16;
691 if (h < 16)
692 h = 16;
693
694 // compute cost weighted by relative effective areas
695 float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh;
696 cost /= ma;
697
698 cost *= 0.004f; // overall tunning parameter
699
700 return cost;
701 }
702 }
703}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index 9b9f6a7..feb3322 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -78,7 +78,6 @@ namespace OpenSim.Region.ClientStack.Linden
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
@@ -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,18 +231,12 @@ 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)
@@ -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>
@@ -395,55 +415,65 @@ namespace OpenSim.Region.ClientStack.Linden
395 return NoEvents(requestID, pAgentId); 415 return NoEvents(requestID, pAgentId);
396 } 416 }
397 417
398 OSD element; 418 OSD element = null;;
419 OSDArray array = new OSDArray();
420 int thisID = 0;
421 bool negativeID = false;
422
399 lock (queue) 423 lock (queue)
400 { 424 {
401 if (queue.Count == 0) 425 if (queue.Count == 0)
402 return NoEvents(requestID, pAgentId); 426 return NoEvents(requestID, pAgentId);
403 element = queue.Dequeue(); // 15s timeout
404 }
405 427
406 int thisID = 0; 428 lock (m_ids)
407 lock (m_ids) 429 thisID = m_ids[pAgentId];
408 thisID = m_ids[pAgentId];
409 430
410 OSDArray array = new OSDArray(); 431 if (thisID < 0)
411 if (element == null) // didn't have an event in 15s
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
422 array.Add(element);
423
424 lock (queue)
425 { 432 {
426 while (queue.Count > 0) 433 negativeID = true;
427 { 434 thisID = -thisID;
428 element = queue.Dequeue(); 435 }
436
437 while (queue.Count > 0)
438 {
439 element = queue.Dequeue();
440 // add elements until a marker is found
441 // so they get into a response
442 if (element == null)
443 break;
444 if (DebugLevel > 0)
445 LogOutboundDebugMessage(element, pAgentId);
446 array.Add(element);
447 thisID++;
448 }
449 }
429 450
430 if (DebugLevel > 0) 451 OSDMap events = null;
431 LogOutboundDebugMessage(element, pAgentId);
432 452
433 array.Add(element); 453 if (array.Count > 0)
434 thisID++; 454 {
435 } 455 events = new OSDMap();
436 } 456 events.Add("events", array);
457 events.Add("id", new OSDInteger(thisID));
437 } 458 }
438 459
439 OSDMap events = new OSDMap(); 460 if (negativeID && element == null)
440 events.Add("events", array); 461 {
462 Random rnd = new Random(Environment.TickCount);
463 thisID = rnd.Next(30000000);
464 if (thisID < 0)
465 thisID = -thisID;
466 }
441 467
442 events.Add("id", new OSDInteger(thisID));
443 lock (m_ids) 468 lock (m_ids)
444 { 469 {
445 m_ids[pAgentId] = thisID + 1; 470 m_ids[pAgentId] = thisID + 1;
446 } 471 }
472
473 // if there where no elements before a marker send a NoEvents
474 if (array.Count == 0)
475 return NoEvents(requestID, pAgentId);
476
447 Hashtable responsedata = new Hashtable(); 477 Hashtable responsedata = new Hashtable();
448 responsedata["int_response_code"] = 200; 478 responsedata["int_response_code"] = 200;
449 responsedata["content_type"] = "application/xml"; 479 responsedata["content_type"] = "application/xml";
@@ -461,260 +491,12 @@ namespace OpenSim.Region.ClientStack.Linden
461 responsedata["content_type"] = "text/plain"; 491 responsedata["content_type"] = "text/plain";
462 responsedata["keepalive"] = false; 492 responsedata["keepalive"] = false;
463 responsedata["reusecontext"] = false; 493 responsedata["reusecontext"] = false;
464 responsedata["str_response_string"] = "Upstream error: "; 494 responsedata["str_response_string"] = "<llsd></llsd>";
465 responsedata["error_status_text"] = "Upstream error:"; 495 responsedata["error_status_text"] = "<llsd></llsd>";
466 responsedata["http_protocol_version"] = "HTTP/1.0"; 496 responsedata["http_protocol_version"] = "HTTP/1.0";
467 return responsedata; 497 return responsedata;
468 } 498 }
469 499
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) 500 public void DisableSimulator(ulong handle, UUID avatarID)
719 { 501 {
720 OSD item = EventQueueHelper.DisableSimulator(handle); 502 OSD item = EventQueueHelper.DisableSimulator(handle);
@@ -827,4 +609,4 @@ namespace OpenSim.Region.ClientStack.Linden
827 Enqueue(item, avatarID); 609 Enqueue(item, avatarID);
828 } 610 }
829 } 611 }
830} \ No newline at end of file 612}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 384af74..799ad0b 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -76,9 +76,9 @@ namespace OpenSim.Region.ClientStack.Linden
76 76
77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); 77 llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); 78 llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
79 llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); 79 llsdSimInfo.Add("Port", OSD.FromInteger(endPoint.Port));
80 llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint) regionSizeX)); 80 llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
81 llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint) regionSizeY)); 81 llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
82 82
83 OSDArray arr = new OSDArray(1); 83 OSDArray arr = new OSDArray(1);
84 arr.Add(llsdSimInfo); 84 arr.Add(llsdSimInfo);
@@ -157,6 +157,12 @@ namespace OpenSim.Region.ClientStack.Linden
157 uint locationID, uint flags, string capsURL, UUID agentID, 157 uint locationID, uint flags, string capsURL, UUID agentID,
158 int regionSizeX, int regionSizeY) 158 int regionSizeX, int regionSizeY)
159 { 159 {
160 // not sure why flags get overwritten here
161 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
162 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
163 else
164 flags = (uint)TeleportFlags.ViaLocation;
165
160 OSDMap info = new OSDMap(); 166 OSDMap info = new OSDMap();
161 info.Add("AgentID", OSD.FromUUID(agentID)); 167 info.Add("AgentID", OSD.FromUUID(agentID));
162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? 168 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
@@ -165,7 +171,8 @@ namespace OpenSim.Region.ClientStack.Linden
165 info.Add("SimAccess", OSD.FromInteger(simAccess)); 171 info.Add("SimAccess", OSD.FromInteger(simAccess));
166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); 172 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 173 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
168 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 174// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
175 info.Add("TeleportFlags", OSD.FromUInteger(flags));
169 info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); 176 info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
170 info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); 177 info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
171 178
@@ -204,8 +211,8 @@ namespace OpenSim.Region.ClientStack.Linden
204 {"sim-ip-and-port", new OSDString(simIpAndPort)}, 211 {"sim-ip-and-port", new OSDString(simIpAndPort)},
205 {"seed-capability", new OSDString(seedcap)}, 212 {"seed-capability", new OSDString(seedcap)},
206 {"region-handle", OSD.FromULong(regionHandle)}, 213 {"region-handle", OSD.FromULong(regionHandle)},
207 {"region-size-x", OSD.FromInteger(regionSizeX)}, 214 {"region-size-x", OSD.FromUInteger((uint)regionSizeX)},
208 {"region-size-y", OSD.FromInteger(regionSizeY)} 215 {"region-size-y", OSD.FromUInteger((uint)regionSizeY)}
209 }; 216 };
210 217
211 return BuildEvent("EstablishAgentCommunication", body); 218 return BuildEvent("EstablishAgentCommunication", body);
@@ -412,7 +419,7 @@ namespace OpenSim.Region.ClientStack.Linden
412 public static OSD partPhysicsProperties(uint localID, byte physhapetype, 419 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
413 float density, float friction, float bounce, float gravmod) 420 float density, float friction, float bounce, float gravmod)
414 { 421 {
415 422
416 OSDMap physinfo = new OSDMap(6); 423 OSDMap physinfo = new OSDMap(6);
417 physinfo["LocalID"] = localID; 424 physinfo["LocalID"] = localID;
418 physinfo["Density"] = density; 425 physinfo["Density"] = density;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index f57d857..b5a70040 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;
@@ -57,12 +60,50 @@ namespace OpenSim.Region.ClientStack.Linden
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;
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
92 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
93 new OpenMetaverse.BlockingQueue<aPollRequest>();
94
95 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
96
63 97
64 #region Region Module interfaceBase Members 98 #region Region Module interfaceBase Members
65 99
100 ~GetMeshModule()
101 {
102 foreach (Thread t in m_workerThreads)
103 Watchdog.AbortThread(t.ManagedThreadId);
104
105 }
106
66 public Type ReplaceableInterface 107 public Type ReplaceableInterface
67 { 108 {
68 get { return null; } 109 get { return null; }
@@ -87,6 +128,7 @@ namespace OpenSim.Region.ClientStack.Linden
87 if (m_URL2 != string.Empty) 128 if (m_URL2 != string.Empty)
88 { 129 {
89 m_Enabled = true; 130 m_Enabled = true;
131
90 m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); 132 m_RedirectURL2 = config.GetString("GetMesh2RedirectURL");
91 } 133 }
92 } 134 }
@@ -97,6 +139,8 @@ namespace OpenSim.Region.ClientStack.Linden
97 return; 139 return;
98 140
99 m_scene = pScene; 141 m_scene = pScene;
142
143 m_assetService = pScene.AssetService;
100 } 144 }
101 145
102 public void RemoveRegion(Scene scene) 146 public void RemoveRegion(Scene scene)
@@ -105,6 +149,9 @@ namespace OpenSim.Region.ClientStack.Linden
105 return; 149 return;
106 150
107 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 151 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
152 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
153 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
154
108 m_scene = null; 155 m_scene = null;
109 } 156 }
110 157
@@ -115,6 +162,27 @@ namespace OpenSim.Region.ClientStack.Linden
115 162
116 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 163 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
117 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 164 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
165 // We'll reuse the same handler for all requests.
166 m_getMeshHandler = new GetMeshHandler(m_assetService);
167 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
168 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
169
170 if (m_workerThreads == null)
171 {
172 m_workerThreads = new Thread[2];
173
174 for (uint i = 0; i < 2; i++)
175 {
176 m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests,
177 String.Format("MeshWorkerThread{0}", i),
178 ThreadPriority.Normal,
179 false,
180 false,
181 null,
182 int.MaxValue);
183 }
184 }
185
118 } 186 }
119 187
120 188
@@ -124,44 +192,346 @@ namespace OpenSim.Region.ClientStack.Linden
124 192
125 #endregion 193 #endregion
126 194
195 private void DoMeshRequests()
196 {
197 while (true)
198 {
199 aPollRequest poolreq = m_queue.Dequeue();
127 200
128 public void RegisterCaps(UUID agentID, Caps caps) 201 poolreq.thepoll.Process(poolreq);
202 }
203 }
204
205 // 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.
206 public void ThrottleUpdate(ScenePresence p)
207 {
208 UUID user = p.UUID;
209 int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset);
210 PollServiceMeshEventArgs args;
211 if (m_pollservices.TryGetValue(user, out args))
212 {
213 args.UpdateThrottle(imagethrottle, p);
214 }
215 }
216
217 private class PollServiceMeshEventArgs : PollServiceEventArgs
129 { 218 {
130 UUID capID = UUID.Random(); 219 private List<Hashtable> requests =
131 bool getMeshRegistered = false; 220 new List<Hashtable>();
221 private Dictionary<UUID, aPollResponse> responses =
222 new Dictionary<UUID, aPollResponse>();
132 223
133 if (m_URL == string.Empty) 224 private Scene m_scene;
225 private MeshCapsDataThrottler m_throttler;
226 public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
227 base(null, uri, null, null, null, pId, int.MaxValue)
134 { 228 {
229 m_scene = scene;
230 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
231 // x is request id, y is userid
232 HasEvents = (x, y) =>
233 {
234 lock (responses)
235 {
236 bool ret = m_throttler.hasEvents(x, responses);
237 m_throttler.ProcessTime();
238 return ret;
239
240 }
241 };
242 GetEvents = (x, y) =>
243 {
244 lock (responses)
245 {
246 try
247 {
248 return responses[x].response;
249 }
250 finally
251 {
252 m_throttler.ProcessTime();
253 responses.Remove(x);
254 }
255 }
256 };
257 // x is request id, y is request data hashtable
258 Request = (x, y) =>
259 {
260 aPollRequest reqinfo = new aPollRequest();
261 reqinfo.thepoll = this;
262 reqinfo.reqID = x;
263 reqinfo.request = y;
264
265 m_queue.Enqueue(reqinfo);
266 };
267
268 // this should never happen except possible on shutdown
269 NoEvents = (x, y) =>
270 {
271 /*
272 lock (requests)
273 {
274 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
275 requests.Remove(request);
276 }
277 */
278 Hashtable response = new Hashtable();
279
280 response["int_response_code"] = 500;
281 response["str_response_string"] = "Script timeout";
282 response["content_type"] = "text/plain";
283 response["keepalive"] = false;
284 response["reusecontext"] = false;
285
286 return response;
287 };
288 }
289
290 public void Process(aPollRequest requestinfo)
291 {
292 Hashtable response;
293
294 UUID requestID = requestinfo.reqID;
295
296 // If the avatar is gone, don't bother to get the texture
297 if (m_scene.GetScenePresence(Id) == null)
298 {
299 response = new Hashtable();
300
301 response["int_response_code"] = 500;
302 response["str_response_string"] = "Script timeout";
303 response["content_type"] = "text/plain";
304 response["keepalive"] = false;
305 response["reusecontext"] = false;
306
307 lock (responses)
308 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
309
310 return;
311 }
312
313 response = m_getMeshHandler.Handle(requestinfo.request);
314 lock (responses)
315 {
316 responses[requestID] = new aPollResponse()
317 {
318 bytes = (int)response["int_bytes"],
319 lod = (int)response["int_lod"],
320 response = response
321 };
135 322
323 }
324 m_throttler.ProcessTime();
136 } 325 }
137 else if (m_URL == "localhost") 326
327 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
138 { 328 {
139 getMeshRegistered = true; 329 m_throttler.UpdateThrottle(pimagethrottle, p);
140 caps.RegisterHandler( 330 }
141 "GetMesh", 331 }
142 new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); 332
333 public void RegisterCaps(UUID agentID, Caps caps)
334 {
335// UUID capID = UUID.Random();
336 if (m_URL == "localhost")
337 {
338 string capUrl = "/CAPS/" + UUID.Random() + "/";
339
340 // Register this as a poll service
341 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
342
343 args.Type = PollServiceEventArgs.EventType.Mesh;
344 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
345
346 string hostName = m_scene.RegionInfo.ExternalHostName;
347 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
348 string protocol = "http";
349
350 if (MainServer.Instance.UseSSL)
351 {
352 hostName = MainServer.Instance.SSLCommonName;
353 port = MainServer.Instance.SSLPort;
354 protocol = "https";
355 }
356 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
357 m_pollservices[agentID] = args;
358 m_capsDict[agentID] = capUrl;
143 } 359 }
144 else 360 else
145 { 361 {
146 caps.RegisterHandler("GetMesh", m_URL); 362 caps.RegisterHandler("GetMesh", m_URL);
147 } 363 }
364 }
365
366 private void DeregisterCaps(UUID agentID, Caps caps)
367 {
368 string capUrl;
369 PollServiceMeshEventArgs args;
370 if (m_capsDict.TryGetValue(agentID, out capUrl))
371 {
372 MainServer.Instance.RemoveHTTPHandler("", capUrl);
373 m_capsDict.Remove(agentID);
374 }
375 if (m_pollservices.TryGetValue(agentID, out args))
376 {
377 m_pollservices.Remove(agentID);
378 }
379 }
380
381 internal sealed class MeshCapsDataThrottler
382 {
383
384 private volatile int currenttime = 0;
385 private volatile int lastTimeElapsed = 0;
386 private volatile int BytesSent = 0;
387 private int Lod3 = 0;
388 private int Lod2 = 0;
389 private int Lod1 = 0;
390 private int UserSetThrottle = 0;
391 private int UDPSetThrottle = 0;
392 private int CapSetThrottle = 0;
393 private float CapThrottleDistributon = 0.30f;
394 private readonly Scene m_scene;
395 private ThrottleOutPacketType Throttle;
396 private readonly UUID User;
397
398 public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene, UUID puser)
399 {
400 ThrottleBytes = pBytes;
401 lastTimeElapsed = Util.EnvironmentTickCount();
402 Throttle = ThrottleOutPacketType.Asset;
403 m_scene = pScene;
404 User = puser;
405 }
406
407
408 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
409 {
410 const float ThirtyPercent = 0.30f;
411 const float FivePercent = 0.05f;
412 PassTime();
413 // Note, this is called IN LOCK
414 bool haskey = responses.ContainsKey(key);
415
416 if (responses.Count > 2)
417 {
418 SplitThrottle(ThirtyPercent);
419 }
420 else
421 {
422 SplitThrottle(FivePercent);
423 }
148 424
149 if(m_URL2 == string.Empty) 425 if (!haskey)
426 {
427 return false;
428 }
429 aPollResponse response;
430 if (responses.TryGetValue(key, out response))
431 {
432 float LOD3Over = (((ThrottleBytes*CapThrottleDistributon)%50000) + 1);
433 float LOD2Over = (((ThrottleBytes*CapThrottleDistributon)%10000) + 1);
434 // Normal
435 if (BytesSent + response.bytes <= ThrottleBytes)
436 {
437 BytesSent += response.bytes;
438
439 return true;
440 }
441 // Lod3 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
442 else if (response.bytes > ThrottleBytes && Lod3 <= ((LOD3Over < 1)? 1: LOD3Over) )
443 {
444 Interlocked.Increment(ref Lod3);
445 BytesSent += response.bytes;
446
447 return true;
448 }
449 // Lod2 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
450 else if (response.bytes > ThrottleBytes && Lod2 <= ((LOD2Over < 1) ? 1 : LOD2Over))
451 {
452 Interlocked.Increment(ref Lod2);
453 BytesSent += response.bytes;
454
455 return true;
456 }
457 else
458 {
459 return false;
460 }
461 }
462
463 return haskey;
464 }
465 public void SubtractBytes(int bytes,int lod)
466 {
467 BytesSent -= bytes;
468 }
469 private void SplitThrottle(float percentMultiplier)
150 { 470 {
151 471
472 if (CapThrottleDistributon != percentMultiplier) // don't switch it if it's already set at the % multipler
473 {
474 CapThrottleDistributon = percentMultiplier;
475 ScenePresence p;
476 if (m_scene.TryGetScenePresence(User, out p)) // If we don't get a user they're not here anymore.
477 {
478// AlterThrottle(UserSetThrottle, p);
479 UpdateThrottle(UserSetThrottle, p);
480 }
481 }
152 } 482 }
153 else if (m_URL2 == "localhost") 483
484 public void ProcessTime()
154 { 485 {
155 if (!getMeshRegistered) 486 PassTime();
487 }
488
489
490 private void PassTime()
491 {
492 currenttime = Util.EnvironmentTickCount();
493 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
494 //processTimeBasedActions(responses);
495 if (currenttime - timeElapsed >= 1000)
156 { 496 {
157 caps.RegisterHandler( 497 lastTimeElapsed = Util.EnvironmentTickCount();
158 "GetMesh2", 498 BytesSent -= ThrottleBytes;
159 new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh2", agentID.ToString(), m_RedirectURL2)); 499 if (BytesSent < 0) BytesSent = 0;
500 if (BytesSent < ThrottleBytes)
501 {
502 Lod3 = 0;
503 Lod2 = 0;
504 Lod1 = 0;
505 }
160 } 506 }
161 } 507 }
162 else 508 private void AlterThrottle(int setting, ScenePresence p)
509 {
510 p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
511 }
512
513 public int ThrottleBytes
163 { 514 {
164 caps.RegisterHandler("GetMesh2", m_URL2); 515 get { return CapSetThrottle; }
516 set { CapSetThrottle = value; }
517 }
518
519 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
520 {
521 // Client set throttle !
522 UserSetThrottle = pimagethrottle;
523 CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
524// UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
525
526 float udp = 1.0f - CapThrottleDistributon;
527 if(udp < 0.7f)
528 udp = 0.7f;
529 UDPSetThrottle = (int) ((float)pimagethrottle * udp);
530 if (CapSetThrottle < 4068)
531 CapSetThrottle = 4068; // at least two discovery mesh
532 p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
533 ProcessTime();
534
165 } 535 }
166 } 536 }
167 537
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index bb932f2..79a3458 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,54 @@ 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
80 private string m_Url = "localhost";
81
82 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
83 new OpenMetaverse.BlockingQueue<aPollRequest>();
84
64 85
65 // TODO: Change this to a config option 86 // TODO: Change this to a config option
66 private string m_RedirectURL = null; 87 private string m_RedirectURL = null;
67 88
68 private string m_URL; 89 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
90
69 91
70 #region ISharedRegionModule Members 92 #region ISharedRegionModule Members
71 93
72 public void Initialise(IConfigSource source) 94 public void Initialise(IConfigSource source)
73 { 95 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"]; 96 IConfig config = source.Configs["ClientStack.LindenCaps"];
97
75 if (config == null) 98 if (config == null)
76 return; 99 return;
77 100/*
78 m_URL = config.GetString("Cap_GetTexture", string.Empty); 101 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist 102 // Cap doesn't exist
80 if (m_URL != string.Empty) 103 if (m_URL != string.Empty)
@@ -82,32 +105,98 @@ namespace OpenSim.Region.ClientStack.Linden
82 m_Enabled = true; 105 m_Enabled = true;
83 m_RedirectURL = config.GetString("GetTextureRedirectURL"); 106 m_RedirectURL = config.GetString("GetTextureRedirectURL");
84 } 107 }
108*/
109 m_Url = config.GetString("Cap_GetTexture", "localhost");
85 } 110 }
86 111
87 public void AddRegion(Scene s) 112 public void AddRegion(Scene s)
88 { 113 {
89 if (!m_Enabled)
90 return;
91
92 m_scene = s; 114 m_scene = s;
115 m_assetService = s.AssetService;
93 } 116 }
94 117
95 public void RemoveRegion(Scene s) 118 public void RemoveRegion(Scene s)
96 { 119 {
97 if (!m_Enabled)
98 return;
99
100 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 120 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
121 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
122 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
101 m_scene = null; 123 m_scene = null;
102 } 124 }
103 125
104 public void RegionLoaded(Scene s) 126 public void RegionLoaded(Scene s)
105 { 127 {
106 if (!m_Enabled) 128 // We'll reuse the same handler for all requests.
107 return; 129 m_getTextureHandler = new GetTextureHandler(m_assetService);
108 130
109 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
110 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 131 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
132 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
133 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
134
135 if (m_workerThreads == null)
136 {
137 m_workerThreads = new Thread[2];
138
139 for (uint i = 0; i < 2; i++)
140 {
141 m_workerThreads[i] = WorkManager.StartThread(DoTextureRequests,
142 String.Format("TextureWorkerThread{0}", i),
143 ThreadPriority.Normal,
144 false,
145 false,
146 null,
147 int.MaxValue);
148 }
149 }
150 }
151 private int ExtractImageThrottle(byte[] pthrottles)
152 {
153
154 byte[] adjData;
155 int pos = 0;
156
157 if (!BitConverter.IsLittleEndian)
158 {
159 byte[] newData = new byte[7 * 4];
160 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
161
162 for (int i = 0; i < 7; i++)
163 Array.Reverse(newData, i * 4, 4);
164
165 adjData = newData;
166 }
167 else
168 {
169 adjData = pthrottles;
170 }
171
172 // 0.125f converts from bits to bytes
173 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
174 //pos += 4;
175 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
176 //pos += 4;
177 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
178 // pos += 4;
179 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
180 // pos += 4;
181 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
182 // pos += 4;
183 pos = pos + 20;
184 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
185 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
186 return texture;
187 }
188
189 // 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.
190 public void ThrottleUpdate(ScenePresence p)
191 {
192 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
193 UUID user = p.UUID;
194 int imagethrottle = ExtractImageThrottle(throttles);
195 PollServiceTextureEventArgs args;
196 if (m_pollservices.TryGetValue(user,out args))
197 {
198 args.UpdateThrottle(imagethrottle);
199 }
111 } 200 }
112 201
113 public void PostInitialise() 202 public void PostInitialise()
@@ -125,28 +214,295 @@ namespace OpenSim.Region.ClientStack.Linden
125 214
126 #endregion 215 #endregion
127 216
128 public void RegisterCaps(UUID agentID, Caps caps) 217 ~GetTextureModule()
218 {
219 foreach (Thread t in m_workerThreads)
220 Watchdog.AbortThread(t.ManagedThreadId);
221
222 }
223
224 private class PollServiceTextureEventArgs : PollServiceEventArgs
129 { 225 {
130 UUID capID = UUID.Random(); 226 private List<Hashtable> requests =
227 new List<Hashtable>();
228 private Dictionary<UUID, aPollResponse> responses =
229 new Dictionary<UUID, aPollResponse>();
131 230
132 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 231 private Scene m_scene;
133 if (m_URL == "localhost") 232 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
233 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
234 base(null, "", null, null, null, pId, int.MaxValue)
134 { 235 {
135// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 236 m_scene = scene;
136 caps.RegisterHandler( 237 // x is request id, y is userid
137 "GetTexture", 238 HasEvents = (x, y) =>
138 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString(), m_RedirectURL)); 239 {
240 lock (responses)
241 {
242 bool ret = m_throttler.hasEvents(x, responses);
243 m_throttler.ProcessTime();
244 return ret;
245
246 }
247 };
248 GetEvents = (x, y) =>
249 {
250 lock (responses)
251 {
252 try
253 {
254 return responses[x].response;
255 }
256 finally
257 {
258 responses.Remove(x);
259 }
260 }
261 };
262 // x is request id, y is request data hashtable
263 Request = (x, y) =>
264 {
265 aPollRequest reqinfo = new aPollRequest();
266 reqinfo.thepoll = this;
267 reqinfo.reqID = x;
268 reqinfo.request = y;
269 reqinfo.send503 = false;
270
271 lock (responses)
272 {
273 if (responses.Count > 0)
274 {
275 if (m_queue.Count >= 4)
276 {
277 // Never allow more than 4 fetches to wait
278 reqinfo.send503 = true;
279 }
280 }
281 }
282 m_queue.Enqueue(reqinfo);
283 };
284
285 // this should never happen except possible on shutdown
286 NoEvents = (x, y) =>
287 {
288/*
289 lock (requests)
290 {
291 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
292 requests.Remove(request);
293 }
294*/
295 Hashtable response = new Hashtable();
296
297 response["int_response_code"] = 500;
298 response["str_response_string"] = "Script timeout";
299 response["content_type"] = "text/plain";
300 response["keepalive"] = false;
301 response["reusecontext"] = false;
302
303 return response;
304 };
139 } 305 }
140 else 306
307 public void Process(aPollRequest requestinfo)
308 {
309 Hashtable response;
310
311 UUID requestID = requestinfo.reqID;
312
313 if (requestinfo.send503)
314 {
315 response = new Hashtable();
316
317
318 response["int_response_code"] = 503;
319 response["str_response_string"] = "Throttled";
320 response["content_type"] = "text/plain";
321 response["keepalive"] = false;
322 response["reusecontext"] = false;
323
324 Hashtable headers = new Hashtable();
325 headers["Retry-After"] = 30;
326 response["headers"] = headers;
327
328 lock (responses)
329 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
330
331 return;
332 }
333
334 // If the avatar is gone, don't bother to get the texture
335 if (m_scene.GetScenePresence(Id) == null)
336 {
337 response = new Hashtable();
338
339 response["int_response_code"] = 500;
340 response["str_response_string"] = "Script timeout";
341 response["content_type"] = "text/plain";
342 response["keepalive"] = false;
343 response["reusecontext"] = false;
344
345 lock (responses)
346 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
347
348 return;
349 }
350
351 response = m_getTextureHandler.Handle(requestinfo.request);
352 lock (responses)
353 {
354 responses[requestID] = new aPollResponse()
355 {
356 bytes = (int) response["int_bytes"],
357 response = response
358 };
359
360 }
361 m_throttler.ProcessTime();
362 }
363
364 internal void UpdateThrottle(int pimagethrottle)
141 { 365 {
142// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 366 m_throttler.ThrottleBytes = pimagethrottle;
367 }
368 }
369
370 private void RegisterCaps(UUID agentID, Caps caps)
371 {
372 if (m_Url == "localhost")
373 {
374 string capUrl = "/CAPS/" + UUID.Random() + "/";
375
376 // Register this as a poll service
377 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
378
379 args.Type = PollServiceEventArgs.EventType.Texture;
380 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
381
382 string hostName = m_scene.RegionInfo.ExternalHostName;
383 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
384 string protocol = "http";
385
386 if (MainServer.Instance.UseSSL)
387 {
388 hostName = MainServer.Instance.SSLCommonName;
389 port = MainServer.Instance.SSLPort;
390 protocol = "https";
391 }
143 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>(); 392 IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
144 if (handler != null) 393 if (handler != null)
145 handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture", m_URL); 394 handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
146 else 395 else
147 caps.RegisterHandler("GetTexture", m_URL); 396 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
397 m_pollservices[agentID] = args;
398 m_capsDict[agentID] = capUrl;
399 }
400 else
401 {
402 caps.RegisterHandler("GetTexture", m_Url);
148 } 403 }
149 } 404 }
150 405
406 private void DeregisterCaps(UUID agentID, Caps caps)
407 {
408 PollServiceTextureEventArgs args;
409
410 MainServer.Instance.RemoveHTTPHandler("", m_Url);
411 m_capsDict.Remove(agentID);
412
413 if (m_pollservices.TryGetValue(agentID, out args))
414 {
415 m_pollservices.Remove(agentID);
416 }
417 }
418
419 private void DoTextureRequests()
420 {
421 while (true)
422 {
423 aPollRequest poolreq = m_queue.Dequeue();
424
425 poolreq.thepoll.Process(poolreq);
426 }
427 }
428 internal sealed class CapsDataThrottler
429 {
430
431 private volatile int currenttime = 0;
432 private volatile int lastTimeElapsed = 0;
433 private volatile int BytesSent = 0;
434 private int oversizedImages = 0;
435 public CapsDataThrottler(int pBytes, int max, int min)
436 {
437 ThrottleBytes = pBytes;
438 lastTimeElapsed = Util.EnvironmentTickCount();
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 + response.bytes <= ThrottleBytes)
458 {
459 BytesSent += response.bytes;
460 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
461 //m_actions.Add(timeBasedAction);
462 return true;
463 }
464 // Big textures
465 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
466 {
467 Interlocked.Increment(ref oversizedImages);
468 BytesSent += response.bytes;
469 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
470 //m_actions.Add(timeBasedAction);
471 return true;
472 }
473 else
474 {
475 return false;
476 }
477 }
478
479 return haskey;
480 }
481
482 public void ProcessTime()
483 {
484 PassTime();
485 }
486
487 private void PassTime()
488 {
489 currenttime = Util.EnvironmentTickCount();
490 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
491 //processTimeBasedActions(responses);
492 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
493 {
494 lastTimeElapsed = Util.EnvironmentTickCount();
495 BytesSent -= ThrottleBytes;
496 if (BytesSent < 0) BytesSent = 0;
497 if (BytesSent < ThrottleBytes)
498 {
499 oversizedImages = 0;
500 }
501 }
502 }
503 public int ThrottleBytes;
504 }
151 } 505 }
506
507
152} 508}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 45d33cd..1b68603 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -129,15 +129,15 @@ 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();
@@ -148,4 +148,4 @@ namespace OpenSim.Region.ClientStack.Linden
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/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index a133a69..5196368 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -64,6 +64,8 @@ namespace OpenSim.Region.ClientStack.Linden
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)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
index e258bcb..d07f66e 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden
155 m_features["MeshRezEnabled"] = true; 155 m_features["MeshRezEnabled"] = true;
156 m_features["MeshUploadEnabled"] = true; 156 m_features["MeshUploadEnabled"] = true;
157 m_features["MeshXferEnabled"] = true; 157 m_features["MeshXferEnabled"] = true;
158
158 m_features["PhysicsMaterialsEnabled"] = true; 159 m_features["PhysicsMaterialsEnabled"] = true;
159 160
160 OSDMap typesMap = new OSDMap(); 161 OSDMap typesMap = new OSDMap();
@@ -173,6 +174,10 @@ namespace OpenSim.Region.ClientStack.Linden
173 else 174 else
174 extrasMap = new OSDMap(); 175 extrasMap = new OSDMap();
175 176
177 extrasMap["AvatarSkeleton"] = true;
178 extrasMap["AnimationSet"] = true;
179
180 // TODO: Take these out of here into their respective modules, like map-server-url
176 if (m_SearchURL != string.Empty) 181 if (m_SearchURL != string.Empty)
177 extrasMap["search-server-url"] = m_SearchURL; 182 extrasMap["search-server-url"] = m_SearchURL;
178 if (!string.IsNullOrEmpty(m_DestinationGuideURL)) 183 if (!string.IsNullOrEmpty(m_DestinationGuideURL))
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs
index dd4a691..db16ccb 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 {
@@ -156,4 +157,5 @@ namespace OpenSim.Region.ClientStack.Linden.Caps.Tests
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..8fd8d1f 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -66,14 +66,19 @@ namespace OpenSim.Region.ClientStack.Linden
66 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
67 67
68 private IBakedTextureModule m_BakedTextureModule; 68 private IBakedTextureModule m_BakedTextureModule;
69 private string m_URL;
69 70
70 public void Initialise(IConfigSource source) 71 public void Initialise(IConfigSource source)
71 { 72 {
73 IConfig config = source.Configs["ClientStack.LindenCaps"];
74 if (config == null)
75 return;
76
77 m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty);
78
72 IConfig appearanceConfig = source.Configs["Appearance"]; 79 IConfig appearanceConfig = source.Configs["Appearance"];
73 if (appearanceConfig != null) 80 if (appearanceConfig != null)
74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 81 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
75
76
77 } 82 }
78 83
79 public void AddRegion(Scene s) 84 public void AddRegion(Scene s)
@@ -89,9 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
89 s.EventManager.OnRemovePresence -= DeRegisterPresence; 94 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null; 95 m_BakedTextureModule = null;
91 m_scene = null; 96 m_scene = null;
92 } 97 }
93
94
95 98
96 public void RegionLoaded(Scene s) 99 public void RegionLoaded(Scene s)
97 { 100 {
@@ -103,44 +106,52 @@ namespace OpenSim.Region.ClientStack.Linden
103 106
104 private void DeRegisterPresence(UUID agentId) 107 private void DeRegisterPresence(UUID agentId)
105 { 108 {
106 ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence))
108 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 }
111
112 } 109 }
113 110
114 private void RegisterNewPresence(ScenePresence presence) 111 private void RegisterNewPresence(ScenePresence presence)
115 { 112 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; 113// presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 } 114 }
119 115
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) 116/* not in use. work done in AvatarFactoryModule ValidateBakedTextureCache() and UpdateBakedTextureCache()
121 { 117 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
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 { 118 {
119 // if cacheItems.Length > 0 viewer is giving us current textures information.
120 // baked ones should had been uploaded and in assets cache as local itens
121
122
123 if (cacheItems.Length == 0)
124 return; // no textures information, nothing to do
125
126 ScenePresence p = null;
127 if (!m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
128 return; // what are we doing if there is no presence to cache for?
129
130 if (p.IsDeleted)
131 return; // does this really work?
132
133 int maxCacheitemsLoop = cacheItems.Length;
134 if (maxCacheitemsLoop > 20)
135 {
136 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
137 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
138 }
139
140 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
141
142
143 // some nice debug
144 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
145 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
146 {
147 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
148 cacheItems[iter].TextureID);
149 }
150
151 // p.Appearance.WearableCacheItems is in memory primary cashID to textures mapper
142 152
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; 153 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
154
144 if (existingitems == null) 155 if (existingitems == null)
145 { 156 {
146 if (m_BakedTextureModule != null) 157 if (m_BakedTextureModule != null)
@@ -154,38 +165,22 @@ namespace OpenSim.Region.ClientStack.Linden
154 p.Appearance.WearableCacheItems = savedcache; 165 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false; 166 p.Appearance.WearableCacheItemsDirty = false;
156 } 167 }
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 } 168 }
167 catch (WebException) 169
168 {
169 cacheItems = null;
170 }
171 catch (InvalidOperationException)
172 {
173 cacheItems = null;
174 } */
175 catch (Exception) 170 catch (Exception)
176 { 171 {
177 // The service logs a sufficient error message. 172 // The service logs a sufficient error message.
178 } 173 }
179 174
180 175
181 if (savedcache != null) 176 if (savedcache != null)
182 existingitems = savedcache; 177 existingitems = savedcache;
183 } 178 }
184 } 179 }
180
185 // Existing items null means it's a fully new appearance 181 // Existing items null means it's a fully new appearance
186 if (existingitems == null) 182 if (existingitems == null)
187 { 183 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++) 184 for (int i = 0; i < maxCacheitemsLoop; i++)
190 { 185 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 186 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
@@ -198,7 +193,7 @@ namespace OpenSim.Region.ClientStack.Linden
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE; 193 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue; 194 continue;
200 } 195 }
201 cacheItems[i].TextureID =face.TextureID; 196 cacheItems[i].TextureID = face.TextureID;
202 if (m_scene.AssetService != null) 197 if (m_scene.AssetService != null)
203 cacheItems[i].TextureAsset = 198 cacheItems[i].TextureAsset =
204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); 199 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
@@ -207,15 +202,10 @@ namespace OpenSim.Region.ClientStack.Linden
207 { 202 {
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); 203 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 } 204 }
210
211
212 } 205 }
213 } 206 }
214 else 207 else
215 208 {
216
217 {
218 // for each uploaded baked texture
219 for (int i = 0; i < maxCacheitemsLoop; i++) 209 for (int i = 0; i < maxCacheitemsLoop; i++)
220 { 210 {
221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) 211 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
@@ -246,23 +236,24 @@ namespace OpenSim.Region.ClientStack.Linden
246 } 236 }
247 } 237 }
248 } 238 }
249
250
251
252 p.Appearance.WearableCacheItems = cacheItems; 239 p.Appearance.WearableCacheItems = cacheItems;
253
254
255 240
256 if (m_BakedTextureModule != null) 241 if (m_BakedTextureModule != null)
257 { 242 {
258 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); 243 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
259 p.Appearance.WearableCacheItemsDirty = true; 244 p.Appearance.WearableCacheItemsDirty = true;
260 245
261 } 246 }
262 } 247 else
263 } 248 p.Appearance.WearableCacheItemsDirty = false;
264 }
265 249
250 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
251 {
252 m_log.Debug("[CacheitemsLeaving] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
253 cacheItems[iter].TextureID);
254 }
255 }
256 */
266 public void PostInitialise() 257 public void PostInitialise()
267 { 258 {
268 } 259 }
@@ -280,23 +271,26 @@ namespace OpenSim.Region.ClientStack.Linden
280 271
281 public void RegisterCaps(UUID agentID, Caps caps) 272 public void RegisterCaps(UUID agentID, Caps caps)
282 { 273 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( 274 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
284 caps, m_scene.AssetService, m_persistBakedTextures); 275 if (m_URL == "localhost")
276 {
277 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
278 caps, m_scene.AssetService, m_persistBakedTextures);
285 279
286 280 caps.RegisterHandler(
287
288 caps.RegisterHandler(
289 "UploadBakedTexture",
290 new RestStreamHandler(
291 "POST",
292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
293 avatarhandler.UploadBakedTexture,
294 "UploadBakedTexture", 281 "UploadBakedTexture",
295 agentID.ToString())); 282 new RestStreamHandler(
296 283 "POST",
297 284 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
298 285 avatarhandler.UploadBakedTexture,
299 286 "UploadBakedTexture",
287 agentID.ToString()));
288
289 }
290 else
291 {
292 caps.RegisterHandler("UploadBakedTexture", m_URL);
293 }
300 } 294 }
301 } 295 }
302} 296}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 025ffea..2a252e1 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;
47using OpenMetaverse;
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.
@@ -117,8 +118,9 @@ namespace OpenSim.Region.ClientStack.Linden
117 return; 118 return;
118 119
119 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); 120 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
120 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); 121// m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
121 122
123// if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
122 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) 124 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
123 { 125 {
124 m_Enabled = true; 126 m_Enabled = true;
@@ -312,7 +314,8 @@ namespace OpenSim.Region.ClientStack.Linden
312 { 314 {
313 if (!reqinfo.folders.Contains(folderID)) 315 if (!reqinfo.folders.Contains(folderID))
314 { 316 {
315 //TODO: Port COF handling from Avination 317 if (sp.COF != UUID.Zero && sp.COF == folderID)
318 highPriority = true;
316 reqinfo.folders.Add(folderID); 319 reqinfo.folders.Add(folderID);
317 } 320 }
318 } 321 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 4d0568d..15d6f7f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -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 e7dd9d3..6df55a6 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -100,6 +100,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
100 public event AvatarPickerRequest OnAvatarPickerRequest; 100 public event AvatarPickerRequest OnAvatarPickerRequest;
101 public event StartAnim OnStartAnim; 101 public event StartAnim OnStartAnim;
102 public event StopAnim OnStopAnim; 102 public event StopAnim OnStopAnim;
103 public event ChangeAnim OnChangeAnim;
103 public event Action<IClientAPI> OnRequestAvatarsData; 104 public event Action<IClientAPI> OnRequestAvatarsData;
104 public event LinkObjects OnLinkObjects; 105 public event LinkObjects OnLinkObjects;
105 public event DelinkObjects OnDelinkObjects; 106 public event DelinkObjects OnDelinkObjects;
@@ -127,6 +128,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
127 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; 128 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
128 public event UpdatePrimFlags OnUpdatePrimFlags; 129 public event UpdatePrimFlags OnUpdatePrimFlags;
129 public event UpdatePrimTexture OnUpdatePrimTexture; 130 public event UpdatePrimTexture OnUpdatePrimTexture;
131 public event ClientChangeObject onClientChangeObject;
130 public event UpdateVector OnUpdatePrimGroupPosition; 132 public event UpdateVector OnUpdatePrimGroupPosition;
131 public event UpdateVector OnUpdatePrimSinglePosition; 133 public event UpdateVector OnUpdatePrimSinglePosition;
132 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 134 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
@@ -156,6 +158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
156 public event RequestTaskInventory OnRequestTaskInventory; 158 public event RequestTaskInventory OnRequestTaskInventory;
157 public event UpdateInventoryItem OnUpdateInventoryItem; 159 public event UpdateInventoryItem OnUpdateInventoryItem;
158 public event CopyInventoryItem OnCopyInventoryItem; 160 public event CopyInventoryItem OnCopyInventoryItem;
161 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
159 public event MoveInventoryItem OnMoveInventoryItem; 162 public event MoveInventoryItem OnMoveInventoryItem;
160 public event RemoveInventoryItem OnRemoveInventoryItem; 163 public event RemoveInventoryItem OnRemoveInventoryItem;
161 public event RemoveInventoryFolder OnRemoveInventoryFolder; 164 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -250,7 +253,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
250 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 253 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
251 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 254 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
252 public event ClassifiedDelete OnClassifiedDelete; 255 public event ClassifiedDelete OnClassifiedDelete;
253 public event ClassifiedDelete OnClassifiedGodDelete; 256 public event ClassifiedGodDelete OnClassifiedGodDelete;
254 public event EventNotificationAddRequest OnEventNotificationAddRequest; 257 public event EventNotificationAddRequest OnEventNotificationAddRequest;
255 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 258 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
256 public event EventGodDelete OnEventGodDelete; 259 public event EventGodDelete OnEventGodDelete;
@@ -281,10 +284,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
281 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 284 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
282 public event SimWideDeletesDelegate OnSimWideDeletes; 285 public event SimWideDeletesDelegate OnSimWideDeletes;
283 public event SendPostcard OnSendPostcard; 286 public event SendPostcard OnSendPostcard;
287 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
284 public event MuteListEntryUpdate OnUpdateMuteListEntry; 288 public event MuteListEntryUpdate OnUpdateMuteListEntry;
285 public event MuteListEntryRemove OnRemoveMuteListEntry; 289 public event MuteListEntryRemove OnRemoveMuteListEntry;
286 public event GodlikeMessage onGodlikeMessage; 290 public event GodlikeMessage onGodlikeMessage;
287 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 291 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
292 public event GenericCall2 OnUpdateThrottles;
288 293
289#pragma warning disable 0067 294#pragma warning disable 0067
290 public event GenericMessage OnGenericMessage; 295 public event GenericMessage OnGenericMessage;
@@ -333,7 +338,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 private PriorityQueue m_entityProps; 338 private PriorityQueue m_entityProps;
334 private Prioritizer m_prioritizer; 339 private Prioritizer m_prioritizer;
335 private bool m_disableFacelights = false; 340 private bool m_disableFacelights = false;
336 private volatile bool m_justEditedTerrain = false; 341
342 private bool m_VelocityInterpolate = false;
343 private const uint MaxTransferBytesPerPacket = 600;
344
337 /// <value> 345 /// <value>
338 /// List used in construction of data blocks for an object update packet. This is to stop us having to 346 /// List used in construction of data blocks for an object update packet. This is to stop us having to
339 /// continually recreate it. 347 /// continually recreate it.
@@ -345,14 +353,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
345 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 353 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
346 /// ownerless phantom. 354 /// ownerless phantom.
347 /// 355 ///
348 /// All manipulation of this set has to occur under a lock 356 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
349 /// 357 ///
350 /// </value> 358 /// </value>
351 protected HashSet<uint> m_killRecord; 359// protected HashSet<uint> m_killRecord;
352 360
353// protected HashSet<uint> m_attachmentsSent; 361// protected HashSet<uint> m_attachmentsSent;
354 362
355 private int m_animationSequenceNumber = 1; 363 private bool m_deliverPackets = true;
364
356 private bool m_SendLogoutPacketWhenClosing = true; 365 private bool m_SendLogoutPacketWhenClosing = true;
357 366
358 /// <summary> 367 /// <summary>
@@ -398,6 +407,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
398 get { return m_startpos; } 407 get { return m_startpos; }
399 set { m_startpos = value; } 408 set { m_startpos = value; }
400 } 409 }
410 public bool DeliverPackets
411 {
412 get { return m_deliverPackets; }
413 set {
414 m_deliverPackets = value;
415 m_udpClient.m_deliverPackets = value;
416 }
417 }
401 public UUID AgentId { get { return m_agentId; } } 418 public UUID AgentId { get { return m_agentId; } }
402 public ISceneAgent SceneAgent { get; set; } 419 public ISceneAgent SceneAgent { get; set; }
403 public UUID ActiveGroupId { get { return m_activeGroupID; } private set { m_activeGroupID = value; } } 420 public UUID ActiveGroupId { get { return m_activeGroupID; } private set { m_activeGroupID = value; } }
@@ -405,6 +422,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
405 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } private set { m_activeGroupPowers = value; } } 422 public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } private set { m_activeGroupPowers = value; } }
406 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 423 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
407 424
425 public int PingTimeMS
426 {
427 get
428 {
429 if (UDPClient != null)
430 return UDPClient.PingTimeMS;
431 return 0;
432 }
433 }
434
408 /// <summary> 435 /// <summary>
409 /// Entity update queues 436 /// Entity update queues
410 /// </summary> 437 /// </summary>
@@ -426,7 +453,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
426 public string Name { get { return FirstName + " " + LastName; } } 453 public string Name { get { return FirstName + " " + LastName; } }
427 454
428 public uint CircuitCode { get { return m_circuitCode; } } 455 public uint CircuitCode { get { return m_circuitCode; } }
429 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 456 public int NextAnimationSequenceNumber
457 {
458 get { return m_udpServer.NextAnimationSequenceNumber; }
459 }
430 460
431 /// <summary> 461 /// <summary>
432 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to 462 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
@@ -447,7 +477,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 set { m_disableFacelights = value; } 477 set { m_disableFacelights = value; }
448 } 478 }
449 479
480 public List<uint> SelectedObjects {get; private set;}
481
450 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 482 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
483
451 484
452 #endregion Properties 485 #endregion Properties
453 486
@@ -465,6 +498,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
465// DebugPacketLevel = 1; 498// DebugPacketLevel = 1;
466 499
467 CloseSyncLock = new Object(); 500 CloseSyncLock = new Object();
501 SelectedObjects = new List<uint>();
468 502
469 RegisterInterface<IClientIM>(this); 503 RegisterInterface<IClientIM>(this);
470 RegisterInterface<IClientInventory>(this); 504 RegisterInterface<IClientInventory>(this);
@@ -474,7 +508,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
474 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 508 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
475 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 509 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
476 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 510 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
477 m_killRecord = new HashSet<uint>(); 511// m_killRecord = new HashSet<uint>();
478// m_attachmentsSent = new HashSet<uint>(); 512// m_attachmentsSent = new HashSet<uint>();
479 513
480 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 514 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -504,12 +538,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
504 538
505 #region Client Methods 539 #region Client Methods
506 540
541
542 /// <summary>
543 /// Close down the client view
544 /// </summary>
507 public void Close() 545 public void Close()
508 { 546 {
509 Close(false); 547 Close(true, false);
510 } 548 }
511 549
512 public void Close(bool force) 550 public void Close(bool sendStop, bool force)
513 { 551 {
514 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 552 // 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. 553 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -526,7 +564,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
526 } 564 }
527 565
528 IsActive = false; 566 IsActive = false;
529 CloseWithoutChecks(); 567 CloseWithoutChecks(sendStop);
530 } 568 }
531 } 569 }
532 570
@@ -539,12 +577,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
539 /// 577 ///
540 /// Callers must lock ClosingSyncLock before calling. 578 /// Callers must lock ClosingSyncLock before calling.
541 /// </remarks> 579 /// </remarks>
542 public void CloseWithoutChecks() 580 public void CloseWithoutChecks(bool sendStop)
543 { 581 {
544 m_log.DebugFormat( 582 m_log.DebugFormat(
545 "[CLIENT]: Close has been called for {0} attached to scene {1}", 583 "[CLIENT]: Close has been called for {0} attached to scene {1}",
546 Name, m_scene.RegionInfo.RegionName); 584 Name, m_scene.RegionInfo.RegionName);
547 585
586 if (sendStop)
587 {
588 // Send the STOP packet
589 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
590 OutPacket(disable, ThrottleOutPacketType.Unknown);
591 }
592
548 // Shutdown the image manager 593 // Shutdown the image manager
549 ImageManager.Close(); 594 ImageManager.Close();
550 595
@@ -566,7 +611,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
566 611
567 // Disable UDP handling for this client 612 // Disable UDP handling for this client
568 m_udpClient.Shutdown(); 613 m_udpClient.Shutdown();
569 614
615
570 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 616 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
571 //GC.Collect(); 617 //GC.Collect();
572 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 618 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -858,6 +904,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
858 904
859 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 905 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
860 { 906 {
907 m_thisAgentUpdateArgs.CameraAtAxis.X = float.MinValue;
908 m_thisAgentUpdateArgs.ControlFlags = uint.MaxValue;
909
861 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); 910 AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete);
862 mov.SimData.ChannelVersion = m_channelVersion; 911 mov.SimData.ChannelVersion = m_channelVersion;
863 mov.AgentData.SessionID = m_sessionId; 912 mov.AgentData.SessionID = m_sessionId;
@@ -893,7 +942,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
893 reply.ChatData.OwnerID = ownerID; 942 reply.ChatData.OwnerID = ownerID;
894 reply.ChatData.SourceID = fromAgentID; 943 reply.ChatData.SourceID = fromAgentID;
895 944
896 OutPacket(reply, ThrottleOutPacketType.Task); 945 OutPacket(reply, ThrottleOutPacketType.Unknown);
897 } 946 }
898 947
899 /// <summary> 948 /// <summary>
@@ -926,32 +975,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
926 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 975 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
927 msg.MessageBlock.BinaryBucket = im.binaryBucket; 976 msg.MessageBlock.BinaryBucket = im.binaryBucket;
928 977
929 if (im.message.StartsWith("[grouptest]")) 978 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 } 979 }
956 } 980 }
957 981
@@ -1182,6 +1206,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1182 OutPacket(GATRP, ThrottleOutPacketType.Task); 1206 OutPacket(GATRP, ThrottleOutPacketType.Task);
1183 } 1207 }
1184 1208
1209
1210 public virtual bool CanSendLayerData()
1211 {
1212 int n = m_udpClient.GetCatBytesInSendQueue(ThrottleOutPacketType.Land);
1213 if ( n > 100000)
1214 return false;
1215 return true;
1216 }
1217
1185 /// <summary> 1218 /// <summary>
1186 /// Send the region heightmap to the client 1219 /// Send the region heightmap to the client
1187 /// This method is only called when not doing intellegent terrain patch sending and 1220 /// This method is only called when not doing intellegent terrain patch sending and
@@ -1192,6 +1225,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1192 public virtual void SendLayerData(float[] map) 1225 public virtual void SendLayerData(float[] map)
1193 { 1226 {
1194 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData"); 1227 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData(), "LLClientView.DoSendLayerData");
1228
1229 // Send it sync, and async. It's not that much data
1230 // and it improves user experience just so much!
1231// DoSendLayerData(map);
1195 } 1232 }
1196 1233
1197 /// <summary> 1234 /// <summary>
@@ -1205,16 +1242,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1205 try 1242 try
1206 { 1243 {
1207 // Send LayerData in typerwriter pattern 1244 // Send LayerData in typerwriter pattern
1208 //for (int y = 0; y < 16; y++)
1209 //{
1210 // for (int x = 0; x < 16; x++)
1211 // {
1212 // SendLayerData(x, y, map);
1213 // }
1214 //}
1215 1245
1216 // Send LayerData in a spiral pattern. Fun! 1246 for (int y = 0; y < 16; y++)
1217 SendLayerTopRight(map, 0, 0, map.SizeX/Constants.TerrainPatchSize-1, map.SizeY/Constants.TerrainPatchSize-1); 1247 {
1248 for (int x = 0; x < 16; x++)
1249 {
1250 SendLayerData(x, y, map);
1251 }
1252 }
1218 } 1253 }
1219 catch (Exception e) 1254 catch (Exception e)
1220 { 1255 {
@@ -1222,52 +1257,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1222 } 1257 }
1223 } 1258 }
1224 1259
1225 private void SendLayerTopRight(TerrainData map, int x1, int y1, int x2, int y2)
1226 {
1227 // Row
1228 for (int i = x1; i <= x2; i++)
1229 SendLayerData(i, y1, map);
1230
1231 // Column
1232 for (int j = y1 + 1; j <= y2; j++)
1233 SendLayerData(x2, j, map);
1234
1235 if (x2 - x1 > 0 && y2 - y1 > 0)
1236 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1237 }
1238
1239 void SendLayerBottomLeft(TerrainData map, int x1, int y1, int x2, int y2)
1240 {
1241 // Row in reverse
1242 for (int i = x2; i >= x1; i--)
1243 SendLayerData(i, y2, map);
1244
1245 // Column in reverse
1246 for (int j = y2 - 1; j >= y1; j--)
1247 SendLayerData(x1, j, map);
1248
1249 if (x2 - x1 > 0 && y2 - y1 > 0)
1250 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1251 }
1252
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
1271 // Legacy form of invocation that passes around a bare data array. 1260 // 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. 1261 // 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, 1262 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
@@ -1316,6 +1305,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1316 } 1305 }
1317 1306
1318 /// <summary> 1307 /// <summary>
1308
1319 /// Sends a terrain packet for the point specified. 1309 /// 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. 1310 /// 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. 1311 /// We just use the terrain from the region we know about.
@@ -1367,34 +1357,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1367 } 1357 }
1368 } 1358 }
1369 1359
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
1376 // It's possible for an editing user to flood themselves with edited packets but the majority
1377 // of use cases are such that only a tiny percentage of users will be editing the terrain.
1378 // Other, non-editing users will see the edits much slower.
1379
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
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) 1360 private void SendTheLayerPacket(LayerDataPacket layerpack)
1387 { 1361 {
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); 1362 OutPacket(layerpack, ThrottleOutPacketType.Land);
1397 }
1398 } 1363 }
1399 1364
1400 /// <summary> 1365 /// <summary>
@@ -1735,11 +1700,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1735 pc.PingID.OldestUnacked = 0; 1700 pc.PingID.OldestUnacked = 0;
1736 1701
1737 OutPacket(pc, ThrottleOutPacketType.Unknown); 1702 OutPacket(pc, ThrottleOutPacketType.Unknown);
1703 UDPClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1738 } 1704 }
1739 1705
1740 public void SendKillObject(List<uint> localIDs) 1706 public void SendKillObject(List<uint> localIDs)
1741 { 1707 {
1742// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1708 // think we do need this
1709 // foreach (uint id in localIDs)
1710 // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1711
1712 // remove pending entities
1713 lock (m_entityProps.SyncRoot)
1714 m_entityProps.Remove(localIDs);
1715 lock (m_entityUpdates.SyncRoot)
1716 m_entityUpdates.Remove(localIDs);
1743 1717
1744 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1718 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1745 // TODO: don't create new blocks if recycling an old packet 1719 // TODO: don't create new blocks if recycling an old packet
@@ -1752,28 +1726,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1752 kill.Header.Reliable = true; 1726 kill.Header.Reliable = true;
1753 kill.Header.Zerocoded = true; 1727 kill.Header.Zerocoded = true;
1754 1728
1755 if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null) 1729 OutPacket(kill, ThrottleOutPacketType.Task);
1756 { 1730 }
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 {
1766 foreach (uint localID in localIDs)
1767 m_killRecord.Add(localID);
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);
1774 }
1775 }
1776 }
1777 1731
1778 /// <summary> 1732 /// <summary>
1779 /// Send information about the items contained in a folder to the client. 1733 /// Send information about the items contained in a folder to the client.
@@ -1895,7 +1849,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1895 newBlock.CreationDate = item.CreationDate; 1849 newBlock.CreationDate = item.CreationDate;
1896 newBlock.SalePrice = item.SalePrice; 1850 newBlock.SalePrice = item.SalePrice;
1897 newBlock.SaleType = item.SaleType; 1851 newBlock.SaleType = item.SaleType;
1898 newBlock.Flags = item.Flags; 1852 newBlock.Flags = item.Flags & 0x2000ff;
1899 1853
1900 newBlock.CRC = 1854 newBlock.CRC =
1901 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, 1855 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
@@ -2151,7 +2105,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2151 itemBlock.GroupID = item.GroupID; 2105 itemBlock.GroupID = item.GroupID;
2152 itemBlock.GroupOwned = item.GroupOwned; 2106 itemBlock.GroupOwned = item.GroupOwned;
2153 itemBlock.GroupMask = item.GroupPermissions; 2107 itemBlock.GroupMask = item.GroupPermissions;
2154 itemBlock.Flags = item.Flags; 2108 itemBlock.Flags = item.Flags & 0x2000ff;
2155 itemBlock.SalePrice = item.SalePrice; 2109 itemBlock.SalePrice = item.SalePrice;
2156 itemBlock.SaleType = item.SaleType; 2110 itemBlock.SaleType = item.SaleType;
2157 itemBlock.CreationDate = item.CreationDate; 2111 itemBlock.CreationDate = item.CreationDate;
@@ -2218,7 +2172,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2218 bulkUpdate.ItemData[0].GroupID = item.GroupID; 2172 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2219 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; 2173 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2220 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; 2174 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2221 bulkUpdate.ItemData[0].Flags = item.Flags; 2175 bulkUpdate.ItemData[0].Flags = item.Flags & 0x2000ff;
2222 bulkUpdate.ItemData[0].SalePrice = item.SalePrice; 2176 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2223 bulkUpdate.ItemData[0].SaleType = item.SaleType; 2177 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2224 2178
@@ -2234,9 +2188,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2234 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2188 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2235 } 2189 }
2236 2190
2237 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2238 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2191 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2239 { 2192 {
2193 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2194 }
2195
2196 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2197 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2198 {
2240 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2199 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2241 2200
2242 UpdateCreateInventoryItemPacket InventoryReply 2201 UpdateCreateInventoryItemPacket InventoryReply
@@ -2246,6 +2205,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2246 // TODO: don't create new blocks if recycling an old packet 2205 // TODO: don't create new blocks if recycling an old packet
2247 InventoryReply.AgentData.AgentID = AgentId; 2206 InventoryReply.AgentData.AgentID = AgentId;
2248 InventoryReply.AgentData.SimApproved = true; 2207 InventoryReply.AgentData.SimApproved = true;
2208 InventoryReply.AgentData.TransactionID = transactionID;
2249 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2209 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2250 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2210 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2251 InventoryReply.InventoryData[0].ItemID = Item.ID; 2211 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2266,7 +2226,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2266 InventoryReply.InventoryData[0].GroupID = Item.GroupID; 2226 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2267 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; 2227 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2268 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; 2228 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2269 InventoryReply.InventoryData[0].Flags = Item.Flags; 2229 InventoryReply.InventoryData[0].Flags = Item.Flags & 0x2000ff;
2270 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; 2230 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2271 InventoryReply.InventoryData[0].SaleType = Item.SaleType; 2231 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2272 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; 2232 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
@@ -2315,16 +2275,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2315 replytask.InventoryData.TaskID = taskID; 2275 replytask.InventoryData.TaskID = taskID;
2316 replytask.InventoryData.Serial = serial; 2276 replytask.InventoryData.Serial = serial;
2317 replytask.InventoryData.Filename = fileName; 2277 replytask.InventoryData.Filename = fileName;
2318 OutPacket(replytask, ThrottleOutPacketType.Asset); 2278 OutPacket(replytask, ThrottleOutPacketType.Task);
2319 } 2279 }
2320 2280
2321 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2281 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2322 { 2282 {
2283 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2284 if (isTaskInventory)
2285 type = ThrottleOutPacketType.Task;
2286
2323 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2287 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2324 sendXfer.XferID.ID = xferID; 2288 sendXfer.XferID.ID = xferID;
2325 sendXfer.XferID.Packet = packet; 2289 sendXfer.XferID.Packet = packet;
2326 sendXfer.DataPacket.Data = data; 2290 sendXfer.DataPacket.Data = data;
2327 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2291 OutPacket(sendXfer, type);
2328 } 2292 }
2329 2293
2330 public void SendAbortXferPacket(ulong xferID) 2294 public void SendAbortXferPacket(ulong xferID)
@@ -2514,6 +2478,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2514 OutPacket(sound, ThrottleOutPacketType.Task); 2478 OutPacket(sound, ThrottleOutPacketType.Task);
2515 } 2479 }
2516 2480
2481 public void SendTransferAbort(TransferRequestPacket transferRequest)
2482 {
2483 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2484 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2485 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2486 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2487 OutPacket(abort, ThrottleOutPacketType.Task);
2488 }
2489
2517 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2490 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2518 { 2491 {
2519 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2492 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2819,6 +2792,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2819 float friction = part.Friction; 2792 float friction = part.Friction;
2820 float bounce = part.Restitution; 2793 float bounce = part.Restitution;
2821 float gravmod = part.GravityModifier; 2794 float gravmod = part.GravityModifier;
2795
2822 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2796 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2823 } 2797 }
2824 } 2798 }
@@ -2889,8 +2863,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2889 LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2863 LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2890 return; 2864 return;
2891 } 2865 }
2866 int WearableOut = 0;
2867 bool isWearable = false;
2868
2869 if (req.AssetInf != null)
2870 isWearable =
2871 ((AssetType) req.AssetInf.Type ==
2872 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2892 2873
2893 //m_log.Debug("sending asset " + req.RequestAssetID); 2874
2875 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2876
2877
2878 //if (isWearable)
2879 // m_log.Debug((AssetType)req.AssetInf.Type);
2880
2894 TransferInfoPacket Transfer = new TransferInfoPacket(); 2881 TransferInfoPacket Transfer = new TransferInfoPacket();
2895 Transfer.TransferInfo.ChannelType = 2; 2882 Transfer.TransferInfo.ChannelType = 2;
2896 Transfer.TransferInfo.Status = 0; 2883 Transfer.TransferInfo.Status = 0;
@@ -2912,7 +2899,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2912 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2899 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2913 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2900 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2914 Transfer.Header.Zerocoded = true; 2901 Transfer.Header.Zerocoded = true;
2915 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2902 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2916 2903
2917 if (req.NumPackets == 1) 2904 if (req.NumPackets == 1)
2918 { 2905 {
@@ -2923,12 +2910,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2923 TransferPacket.TransferData.Data = req.AssetInf.Data; 2910 TransferPacket.TransferData.Data = req.AssetInf.Data;
2924 TransferPacket.TransferData.Status = 1; 2911 TransferPacket.TransferData.Status = 1;
2925 TransferPacket.Header.Zerocoded = true; 2912 TransferPacket.Header.Zerocoded = true;
2926 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2913 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2927 } 2914 }
2928 else 2915 else
2929 { 2916 {
2930 int processedLength = 0; 2917 int processedLength = 0;
2931 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2918// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2919
2920 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2932 int packetNumber = 0; 2921 int packetNumber = 0;
2933 2922
2934 while (processedLength < req.AssetInf.Data.Length) 2923 while (processedLength < req.AssetInf.Data.Length)
@@ -2954,7 +2943,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2954 TransferPacket.TransferData.Status = 1; 2943 TransferPacket.TransferData.Status = 1;
2955 } 2944 }
2956 TransferPacket.Header.Zerocoded = true; 2945 TransferPacket.Header.Zerocoded = true;
2957 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2946 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2958 2947
2959 processedLength += chunkSize; 2948 processedLength += chunkSize;
2960 packetNumber++; 2949 packetNumber++;
@@ -2999,7 +2988,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2999 reply.Data.ParcelID = parcelID; 2988 reply.Data.ParcelID = parcelID;
3000 reply.Data.OwnerID = land.OwnerID; 2989 reply.Data.OwnerID = land.OwnerID;
3001 reply.Data.Name = Utils.StringToBytes(land.Name); 2990 reply.Data.Name = Utils.StringToBytes(land.Name);
3002 reply.Data.Desc = Utils.StringToBytes(land.Description); 2991 if (land != null && land.Description != null && land.Description != String.Empty)
2992 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2993 else
2994 reply.Data.Desc = new Byte[0];
3003 reply.Data.ActualArea = land.Area; 2995 reply.Data.ActualArea = land.Area;
3004 reply.Data.BillableArea = land.Area; // TODO: what is this? 2996 reply.Data.BillableArea = land.Area; // TODO: what is this?
3005 2997
@@ -3706,24 +3698,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3706 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3698 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3707 AgentWearablesUpdatePacket.WearableDataBlock awb; 3699 AgentWearablesUpdatePacket.WearableDataBlock awb;
3708 int idx = 0; 3700 int idx = 0;
3709 for (int i = 0; i < wearables.Length; i++) 3701
3710 { 3702 for (int i = 0; i < wearables.Length; i++)
3711 for (int j = 0; j < wearables[i].Count; j++) 3703 {
3712 { 3704 for (int j = 0; j < wearables[i].Count; j++)
3713 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3705 {
3714 awb.WearableType = (byte)i; 3706 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3715 awb.AssetID = wearables[i][j].AssetID; 3707 awb.WearableType = (byte) i;
3716 awb.ItemID = wearables[i][j].ItemID; 3708 awb.AssetID = wearables[i][j].AssetID;
3717 aw.WearableData[idx] = awb; 3709 awb.ItemID = wearables[i][j].ItemID;
3718 idx++; 3710 aw.WearableData[idx] = awb;
3719 3711 idx++;
3720// m_log.DebugFormat( 3712
3721// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3713 // m_log.DebugFormat(
3722// awb.ItemID, awb.AssetID, i, Name); 3714 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3723 } 3715 // awb.ItemID, awb.AssetID, i, Name);
3724 } 3716 }
3717 }
3725 3718
3726 OutPacket(aw, ThrottleOutPacketType.Task); 3719 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3727 } 3720 }
3728 3721
3729 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3722 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3749,8 +3742,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3749 avp.Sender.ID = agentID; 3742 avp.Sender.ID = agentID;
3750 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; 3743 avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
3751 avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0]; 3744 avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0];
3745
3746// this need be use in future ?
3747// avp.AppearanceData[0].AppearanceVersion = 0;
3748// avp.AppearanceData[0].CofVersion = 0;
3749
3752 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3750 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3753 OutPacket(avp, ThrottleOutPacketType.Task); 3751 OutPacket(avp, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3754 } 3752 }
3755 3753
3756 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) 3754 public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
@@ -3778,7 +3776,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3778 ani.AnimationSourceList[i].ObjectID = objectIDs[i]; 3776 ani.AnimationSourceList[i].ObjectID = objectIDs[i];
3779 } 3777 }
3780 ani.Header.Reliable = false; 3778 ani.Header.Reliable = false;
3781 OutPacket(ani, ThrottleOutPacketType.Task); 3779 OutPacket(ani, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3782 } 3780 }
3783 3781
3784 #endregion 3782 #endregion
@@ -3807,7 +3805,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3807 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1]; 3805 objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
3808 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence); 3806 objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);
3809 3807
3810 OutPacket(objupdate, ThrottleOutPacketType.Task); 3808 OutPacket(objupdate, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3811 3809
3812 // We need to record the avatar local id since the root prim of an attachment points to this. 3810 // We need to record the avatar local id since the root prim of an attachment points to this.
3813// m_attachmentsSent.Add(avatar.LocalId); 3811// m_attachmentsSent.Add(avatar.LocalId);
@@ -3866,6 +3864,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3866 /// </summary> 3864 /// </summary>
3867 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3865 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3868 { 3866 {
3867/*
3869 if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3868 if (entity.UUID == m_agentId && !updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3870 { 3869 {
3871 ImprovedTerseObjectUpdatePacket packet 3870 ImprovedTerseObjectUpdatePacket packet
@@ -3876,15 +3875,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3876 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; 3875 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
3877 packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false); 3876 packet.ObjectData[0] = CreateImprovedTerseBlock(entity, false);
3878 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 3877 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3878 return;
3879 } 3879 }
3880 else 3880*/
3881 if (entity is SceneObjectPart)
3881 { 3882 {
3882 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3883 SceneObjectPart e = (SceneObjectPart)entity;
3883 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3884 SceneObjectGroup g = e.ParentGroup;
3884 3885 if (g.HasPrivateAttachmentPoint && g.OwnerID != AgentId)
3885 lock (m_entityUpdates.SyncRoot) 3886 return; // Don't send updates for other people's HUDs
3886 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3887 } 3887 }
3888
3889 //double priority = m_prioritizer.GetUpdatePriority(this, entity);
3890 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3891
3892 lock (m_entityUpdates.SyncRoot)
3893 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3888 } 3894 }
3889 3895
3890 /// <summary> 3896 /// <summary>
@@ -3894,8 +3900,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3894 /// The original update time is used for the merged update. 3900 /// The original update time is used for the merged update.
3895 /// </summary> 3901 /// </summary>
3896 private void ResendPrimUpdate(EntityUpdate update) 3902 private void ResendPrimUpdate(EntityUpdate update)
3897 { 3903 {
3898 // If the update exists in priority queue, it will be updated. 3904 // If the update exists in priority queue, it will be updated.
3899 // If it does not exist then it will be added with the current (rather than its original) priority 3905 // If it does not exist then it will be added with the current (rather than its original) priority
3900 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); 3906 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3901 3907
@@ -3919,7 +3925,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3919 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber); 3925 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3920 3926
3921 // Count this as a resent packet since we are going to requeue all of the updates contained in it 3927 // 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); 3928 Interlocked.Increment(ref m_udpClient.PacketsResent);
3923 3929
3924 // We're not going to worry about interlock yet since its not currently critical that this total count 3930 // We're not going to worry about interlock yet since its not currently critical that this total count
3925 // is 100% correct 3931 // is 100% correct
@@ -3928,18 +3934,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3928 foreach (EntityUpdate update in updates) 3934 foreach (EntityUpdate update in updates)
3929 ResendPrimUpdate(update); 3935 ResendPrimUpdate(update);
3930 } 3936 }
3931 3937
3932// OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
3933// OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>> compressedUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdateCompressedPacket.ObjectDataBlock>>();
3934// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3935// OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<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
3943 private void ProcessEntityUpdates(int maxUpdates) 3938 private void ProcessEntityUpdates(int maxUpdates)
3944 { 3939 {
3945 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3940 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3952,15 +3947,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3952 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); 3947 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>>(); 3948 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3954 3949
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 3950 // Check to see if this is a flush
3965 if (maxUpdates <= 0) 3951 if (maxUpdates <= 0)
3966 { 3952 {
@@ -3971,54 +3957,72 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3971 3957
3972 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3958 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3973 // condition where a kill can be processed before an out-of-date update for the same object. 3959 // condition where a kill can be processed before an out-of-date update for the same object.
3974 lock (m_killRecord) 3960 float avgTimeDilation = 1.0f;
3961 IEntityUpdate iupdate;
3962 Int32 timeinqueue; // this is just debugging code & can be dropped later
3963
3964 while (updatesThisCall < maxUpdates)
3975 { 3965 {
3976 float avgTimeDilation = 1.0f; 3966 lock (m_entityUpdates.SyncRoot)
3977 IEntityUpdate iupdate; 3967 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3978 Int32 timeinqueue; // this is just debugging code & can be dropped later 3968 break;
3969
3970 EntityUpdate update = (EntityUpdate)iupdate;
3971
3972 avgTimeDilation += update.TimeDilation;
3973 avgTimeDilation *= 0.5f;
3979 3974
3980 while (updatesThisCall < maxUpdates) 3975 if (update.Entity is SceneObjectPart)
3981 { 3976 {
3982 lock (m_entityUpdates.SyncRoot) 3977 SceneObjectPart part = (SceneObjectPart)update.Entity;
3983 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3984 break;
3985 3978
3986 EntityUpdate update = (EntityUpdate)iupdate; 3979 if (part.ParentGroup.IsDeleted || part.ParentGroup.inTransit)
3987 3980 continue;
3988 avgTimeDilation += update.TimeDilation;
3989 avgTimeDilation *= 0.5f;
3990 3981
3991 if (update.Entity is SceneObjectPart) 3982 if (part.ParentGroup.IsAttachment)
3992 { 3983 { // Someone else's HUD, why are we getting these?
3993 SceneObjectPart part = (SceneObjectPart)update.Entity; 3984 if (part.ParentGroup.OwnerID != AgentId && part.ParentGroup.HasPrivateAttachmentPoint)
3994 3985 continue;
3995 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3986 ScenePresence sp;
3996 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3987 // Owner is not in the sim, don't update it to
3997 // safety measure. 3988 // anyone
3998 // 3989 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
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 {
4007 // m_log.WarnFormat(
4008 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
4009 // part.LocalId, Name);
4010 continue; 3990 continue;
4011 } 3991
4012 3992 List<SceneObjectGroup> atts = sp.GetAttachments();
4013 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3993 bool found = false;
3994 foreach (SceneObjectGroup att in atts)
4014 { 3995 {
4015 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3996 if (att == part.ParentGroup)
4016 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
4017 { 3997 {
4018 part.Shape.LightEntry = false; 3998 found = true;
3999 break;
4019 } 4000 }
4020 } 4001 }
4021 4002
4003 // It's an attachment of a valid avatar, but
4004 // doesn't seem to be attached, skip
4005 if (!found)
4006 continue;
4007
4008 // On vehicle crossing, the attachments are received
4009 // while the avatar is still a child. Don't send
4010 // updates here because the LocalId has not yet
4011 // been updated and the viewer will derender the
4012 // attachments until the avatar becomes root.
4013 if (sp.IsChildAgent)
4014 continue;
4015
4016 }
4017
4018 if (part.ParentGroup.IsAttachment && m_disableFacelights)
4019 {
4020 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
4021 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
4022 {
4023 part.Shape.LightEntry = false;
4024 }
4025
4022 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 4026 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
4023 { 4027 {
4024 // Ensure that mesh has at least 8 valid faces 4028 // Ensure that mesh has at least 8 valid faces
@@ -4027,233 +4031,212 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4027 part.Shape.ProfileHollow = 27500; 4031 part.Shape.ProfileHollow = 27500;
4028 } 4032 }
4029 } 4033 }
4030 4034
4031 #region UpdateFlags to packet type conversion 4035 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
4032
4033 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
4034
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 { 4036 {
4041 canUseCompressed = false; 4037 // Ensure that mesh has at least 8 valid faces
4038 part.Shape.ProfileBegin = 12500;
4039 part.Shape.ProfileEnd = 0;
4040 part.Shape.ProfileHollow = 27500;
4042 } 4041 }
4043 4042 }
4044 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 4043 else if (update.Entity is ScenePresence)
4044 {
4045 ScenePresence presence = (ScenePresence)update.Entity;
4046 if (presence.IsDeleted)
4047 continue;
4048 // If ParentUUID is not UUID.Zero and ParentID is 0, this
4049 // avatar is in the process of crossing regions while
4050 // sat on an object. In this state, we don't want any
4051 // updates because they will visually orbit the avatar.
4052 // Update will be forced once crossing is completed anyway.
4053 if (presence.ParentUUID != UUID.Zero && presence.ParentID == 0)
4054 continue;
4055 }
4056
4057 ++updatesThisCall;
4058
4059 #region UpdateFlags to packet type conversion
4060
4061 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
4062
4063 bool canUseCompressed = true;
4064 bool canUseImproved = true;
4065
4066 // Compressed object updates only make sense for LL primitives
4067 if (!(update.Entity is SceneObjectPart))
4068 {
4069 canUseCompressed = false;
4070 }
4071
4072 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
4073 {
4074 canUseCompressed = false;
4075 canUseImproved = false;
4076 }
4077 else
4078 {
4079 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
4080 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
4081 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
4082 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4045 { 4083 {
4046 canUseCompressed = false; 4084 canUseCompressed = false;
4047 canUseImproved = false;
4048 } 4085 }
4049 else 4086
4087 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
4088 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
4089 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
4090 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
4091 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
4092 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
4093 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
4094 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
4095 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
4096 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
4097 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
4098 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
4099 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
4100 updateFlags.HasFlag(PrimUpdateFlags.Joint))
4050 { 4101 {
4051 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 4102 canUseImproved = false;
4052 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
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 {
4074 canUseImproved = false;
4075 }
4076 } 4103 }
4104 }
4077 4105
4078 #endregion UpdateFlags to packet type conversion 4106 #endregion UpdateFlags to packet type conversion
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 {
4087 ObjectUpdatePacket.ObjectDataBlock updateBlock;
4088 4107
4089 if (update.Entity is ScenePresence) 4108 #region Block Construction
4090 {
4091 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
4092 }
4093 else
4094 {
4095 SceneObjectPart part = (SceneObjectPart)update.Entity;
4096 updateBlock = CreatePrimUpdateBlock(part, AgentId);
4097
4098 // If the part has become a private hud since the update was scheduled then we do not
4099 // want to send it to other avatars.
4100 if (part.ParentGroup.IsAttachment
4101 && part.ParentGroup.HasPrivateAttachmentPoint
4102 && part.ParentGroup.AttachedAvatar != AgentId)
4103 continue;
4104
4105 // If the part has since been deleted, then drop the update. In the case of attachments,
4106 // this is to avoid spurious updates to other viewers since post-processing of attachments
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 }
4114 4109
4115 objectUpdateBlocks.Value.Add(updateBlock); 4110 // TODO: Remove this once we can build compressed updates
4116 objectUpdates.Value.Add(update); 4111 canUseCompressed = false;
4117 }
4118 else if (!canUseImproved)
4119 {
4120 SceneObjectPart part = (SceneObjectPart)update.Entity;
4121 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
4122 = CreateCompressedUpdateBlock(part, updateFlags);
4123
4124 // If the part has since been deleted, then drop the update. In the case of attachments,
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 4112
4133 compressedUpdateBlocks.Value.Add(compressedBlock); 4113 if (!canUseImproved && !canUseCompressed)
4134 compressedUpdates.Value.Add(update); 4114 {
4115 if (update.Entity is ScenePresence)
4116 {
4117 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
4135 } 4118 }
4136 else 4119 else
4137 { 4120 {
4138 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4121 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
4139 { 4122 }
4140 // Self updates go into a special list 4123 }
4141 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 4124 else if (!canUseImproved)
4142 terseAgentUpdates.Value.Add(update); 4125 {
4143 } 4126 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
4144 else 4127 }
4145 { 4128 else
4146 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock 4129 {
4147 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); 4130 if (update.Entity is ScenePresence)
4131 // ALL presence updates go into a special list
4132 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4133 else
4134 // Everything else goes here
4135 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4136 }
4148 4137
4149 // Everything else goes here 4138 #endregion Block Construction
4150 if (update.Entity is SceneObjectPart) 4139 }
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 4140
4171 terseUpdateBlocks.Value.Add(terseUpdateBlock); 4141 #region Packet Sending
4172 terseUpdates.Value.Add(update); 4142
4173 } 4143// const float TIME_DILATION = 1.0f;
4174 } 4144 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4145
4146 if (terseAgentUpdateBlocks.IsValueCreated)
4147 {
4148 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
4149
4150 ImprovedTerseObjectUpdatePacket packet
4151 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4152 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4153 packet.RegionData.TimeDilation = timeDilation;
4154 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4155
4156 for (int i = 0; i < blocks.Count; i++)
4157 packet.ObjectData[i] = blocks[i];
4158
4159 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4160 }
4175 4161
4176 ++updatesThisCall; 4162 if (objectUpdateBlocks.IsValueCreated)
4163 {
4164 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4177 4165
4178 #endregion Block Construction 4166 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4179 } 4167 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4168 packet.RegionData.TimeDilation = timeDilation;
4169 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4180 4170
4181 #region Packet Sending 4171 for (int i = 0; i < blocks.Count; i++)
4182 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 4172 packet.ObjectData[i] = blocks[i];
4173
4174 OutPacket(packet, ThrottleOutPacketType.Task, true);
4175 }
4176
4177 if (compressedUpdateBlocks.IsValueCreated)
4178 {
4179 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4180
4181 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4182 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4183 packet.RegionData.TimeDilation = timeDilation;
4184 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4183 4185
4184 if (terseAgentUpdateBlocks.IsValueCreated) 4186 for (int i = 0; i < blocks.Count; i++)
4185 { 4187 packet.ObjectData[i] = blocks[i];
4186 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4188
4189 OutPacket(packet, ThrottleOutPacketType.Task, true);
4190 }
4191
4192 if (terseUpdateBlocks.IsValueCreated)
4193 {
4194 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4195
4196 ImprovedTerseObjectUpdatePacket packet
4197 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4198 PacketType.ImprovedTerseObjectUpdate);
4199 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4200 packet.RegionData.TimeDilation = timeDilation;
4201 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4202
4203 for (int i = 0; i < blocks.Count; i++)
4204 packet.ObjectData[i] = blocks[i];
4187 4205
4188 ImprovedTerseObjectUpdatePacket packet 4206 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4189 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4207 }
4190 4208
4191 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4209 #endregion Packet Sending
4192 packet.RegionData.TimeDilation = timeDilation; 4210 }
4193 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4194 4211
4195 for (int i = 0; i < blocks.Count; i++) 4212 // hack.. dont use
4196 packet.ObjectData[i] = blocks[i]; 4213 public void SendPartFullUpdate(ISceneEntity ent, uint? parentID)
4197 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4214 {
4198 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4215 if (ent is SceneObjectPart)
4199 } 4216 {
4217 SceneObjectPart part = (SceneObjectPart)ent;
4218 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4219 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4220 packet.RegionData.TimeDilation = 1;
4221 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
4200 4222
4201 if (objectUpdateBlocks.IsValueCreated) 4223 ObjectUpdatePacket.ObjectDataBlock blk = CreatePrimUpdateBlock(part, this.m_agentId);
4224 if (parentID.HasValue)
4202 { 4225 {
4203 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 4226 blk.ParentID = parentID.Value;
4204
4205 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4206 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
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 }
4215
4216 if (compressedUpdateBlocks.IsValueCreated)
4217 {
4218 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.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 } 4227 }
4230 4228
4231 if (terseUpdateBlocks.IsValueCreated) 4229 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 4230
4239 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4231 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 } 4232 }
4249 4233
4250// m_log.DebugFormat( 4234// m_log.DebugFormat(
4251// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}", 4235// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}",
4252// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name); 4236// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name);
4253// 4237//
4254 #endregion Packet Sending
4255 } 4238 }
4256 4239
4257 public void ReprioritizeUpdates() 4240 public void ReprioritizeUpdates()
4258 { 4241 {
4259 lock (m_entityUpdates.SyncRoot) 4242 lock (m_entityUpdates.SyncRoot)
@@ -4572,11 +4555,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4572 4555
4573 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4556 // 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 4557 // of the object rather than the properties when the packet was created
4575 OutPacket(packet, ThrottleOutPacketType.Task, true, 4558 // HACK : Remove intelligent resending until it's fixed in core
4576 delegate(OutgoingPacket oPacket) 4559 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4577 { 4560 // delegate(OutgoingPacket oPacket)
4578 ResendPropertyUpdates(updates, oPacket); 4561 // {
4579 }); 4562 // ResendPropertyUpdates(updates, oPacket);
4563 // });
4564 OutPacket(packet, ThrottleOutPacketType.Task, true);
4580 4565
4581 // pbcnt += blocks.Count; 4566 // pbcnt += blocks.Count;
4582 // ppcnt++; 4567 // ppcnt++;
@@ -4602,11 +4587,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4602 // of the object rather than the properties when the packet was created 4587 // of the object rather than the properties when the packet was created
4603 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4588 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4604 updates.Add(familyUpdates.Value[i]); 4589 updates.Add(familyUpdates.Value[i]);
4605 OutPacket(packet, ThrottleOutPacketType.Task, true, 4590 // HACK : Remove intelligent resending until it's fixed in core
4606 delegate(OutgoingPacket oPacket) 4591 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4607 { 4592 // delegate(OutgoingPacket oPacket)
4608 ResendPropertyUpdates(updates, oPacket); 4593 // {
4609 }); 4594 // ResendPropertyUpdates(updates, oPacket);
4595 // });
4596 OutPacket(packet, ThrottleOutPacketType.Task, true);
4610 4597
4611 // fpcnt++; 4598 // fpcnt++;
4612 // fbcnt++; 4599 // fbcnt++;
@@ -4939,7 +4926,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4939 packet.ParcelData.Data = data; 4926 packet.ParcelData.Data = data;
4940 packet.ParcelData.SequenceID = sequence_id; 4927 packet.ParcelData.SequenceID = sequence_id;
4941 packet.Header.Zerocoded = true; 4928 packet.Header.Zerocoded = true;
4942 OutPacket(packet, ThrottleOutPacketType.Task); 4929// OutPacket(packet, ThrottleOutPacketType.Task);
4930 OutPacket(packet, ThrottleOutPacketType.Land);
4943 } 4931 }
4944 4932
4945 public void SendLandProperties( 4933 public void SendLandProperties(
@@ -5004,7 +4992,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5004 4992
5005 if (landData.SimwideArea > 0) 4993 if (landData.SimwideArea > 0)
5006 { 4994 {
5007 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4995 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4996 // Never report more than sim total capacity
4997 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4998 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
5008 updateMessage.SimWideMaxPrims = simulatorCapacity; 4999 updateMessage.SimWideMaxPrims = simulatorCapacity;
5009 } 5000 }
5010 else 5001 else
@@ -5039,7 +5030,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5039 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>(); 5030 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
5040 if (eq != null) 5031 if (eq != null)
5041 { 5032 {
5042 eq.ParcelProperties(updateMessage, this.AgentId); 5033
5034 OSD message_body = updateMessage.Serialize();
5035 // Add new fields here until OMV has them
5036 OSDMap bodyMap = (OSDMap)message_body;
5037 OSDArray parcelDataArray = (OSDArray)bodyMap["ParcelData"];
5038 OSDMap parcelData = (OSDMap)parcelDataArray[0];
5039 parcelData["SeeAVs"] = OSD.FromBoolean(landData.SeeAVs);
5040 parcelData["AnyAVSounds"] = OSD.FromBoolean(landData.AnyAVSounds);
5041 parcelData["GroupAVSounds"] = OSD.FromBoolean(landData.GroupAVSounds);
5042 OSDMap message = new OSDMap();
5043 message.Add("message", OSD.FromString("ParcelProperties"));
5044 message.Add("body", message_body);
5045
5046 eq.Enqueue (message, this.AgentId);
5047
5048// eq.ParcelProperties(updateMessage, this.AgentId);
5043 } 5049 }
5044 else 5050 else
5045 { 5051 {
@@ -5133,14 +5139,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5133 5139
5134 if (notifyCount > 0) 5140 if (notifyCount > 0)
5135 { 5141 {
5136 if (notifyCount > 32) 5142// if (notifyCount > 32)
5137 { 5143// {
5138 m_log.InfoFormat( 5144// m_log.InfoFormat(
5139 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 5145// "[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); 5146// + " - a developer might want to investigate whether this is a hard limit", 32);
5141 5147//
5142 notifyCount = 32; 5148// notifyCount = 32;
5143 } 5149// }
5144 5150
5145 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 5151 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
5146 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 5152 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -5195,41 +5201,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5195 { 5201 {
5196 ScenePresence presence = (ScenePresence)entity; 5202 ScenePresence presence = (ScenePresence)entity;
5197 5203
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; 5204 position = presence.OffsetPosition;
5205 velocity = presence.Velocity; 5205 rotation = presence.Rotation;
5206 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; 5206 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; 5207 rotation = presence.Rotation;
5224 5208
5225 if (!presence.IsSatOnObject) 5209 attachPoint = 0;
5226 { 5210// m_log.DebugFormat(
5227 rotation.X = 0; 5211// "[LLCLIENTVIEW]: Sending terse update to {0} with position {1} in {2}", Name, presence.OffsetPosition, m_scene.Name);
5228 rotation.Y = 0; 5212
5229 } 5213 // attachPoint = presence.State; // Core: commented
5214 collisionPlane = presence.CollisionPlane;
5215 velocity = presence.Velocity;
5216 acceleration = Vector3.Zero;
5230 5217
5231 if (sendTexture) 5218 if (sendTexture)
5219 {
5232 textureEntry = presence.Appearance.Texture.GetBytes(); 5220 textureEntry = presence.Appearance.Texture.GetBytes();
5221 }
5233 else 5222 else
5234 textureEntry = null; 5223 textureEntry = null;
5235 } 5224 }
@@ -5333,34 +5322,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5333 5322
5334 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5323 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5335 { 5324 {
5325 Vector3 offsetPosition = data.OffsetPosition;
5326 Quaternion rotation = data.Rotation;
5327 uint parentID = data.ParentID;
5328
5336// m_log.DebugFormat( 5329// 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); 5330// "[LLCLIENTVIEW]: Sending full update to {0} with pos {1}, vel {2} in {3}", Name, data.OffsetPosition, data.Velocity, m_scene.Name);
5338 5331
5339 byte[] objectData = new byte[76]; 5332 byte[] objectData = new byte[76];
5340 5333
5341 data.CollisionPlane.ToBytes(objectData, 0); 5334 Vector3 velocity = new Vector3(0, 0, 0);
5342 data.OffsetPosition.ToBytes(objectData, 16); 5335 Vector3 acceleration = new Vector3(0, 0, 0);
5343 data.Velocity.ToBytes(objectData, 28); 5336 rotation.Normalize();
5344// data.Acceleration.ToBytes(objectData, 40);
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 {
5358 rot.X = 0;
5359 rot.Y = 0;
5360 }
5361 5337
5362 rot.ToBytes(objectData, 52); 5338 data.CollisionPlane.ToBytes(objectData, 0);
5363 //data.AngularVelocity.ToBytes(objectData, 64); 5339 offsetPosition.ToBytes(objectData, 16);
5340 velocity.ToBytes(objectData, 28);
5341 acceleration.ToBytes(objectData, 40);
5342 rotation.ToBytes(objectData, 52);
5343 data.AngularVelocity.ToBytes(objectData, 64);
5364 5344
5365 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5345 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
5366 5346
@@ -5386,7 +5366,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5386 update.PCode = (byte)PCode.Avatar; 5366 update.PCode = (byte)PCode.Avatar;
5387 update.ProfileCurve = 1; 5367 update.ProfileCurve = 1;
5388 update.PSBlock = Utils.EmptyBytes; 5368 update.PSBlock = Utils.EmptyBytes;
5389 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5369 update.Scale = data.Appearance.AvatarSize;
5370// update.Scale.Z -= 0.2f;
5371
5390 update.Text = Utils.EmptyBytes; 5372 update.Text = Utils.EmptyBytes;
5391 update.TextColor = new byte[4]; 5373 update.TextColor = new byte[4];
5392 5374
@@ -5397,10 +5379,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5397 update.TextureEntry = Utils.EmptyBytes; 5379 update.TextureEntry = Utils.EmptyBytes;
5398// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5380// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5399 5381
5382/* 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)( 5383 update.UpdateFlags = (uint)(
5401 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5384 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5402 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5385 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5403 PrimFlags.ObjectOwnerModify); 5386 PrimFlags.ObjectOwnerModify);
5387*/
5388 update.UpdateFlags = 0;
5404 5389
5405 return update; 5390 return update;
5406 } 5391 }
@@ -5411,15 +5396,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5411 data.RelativePosition.ToBytes(objectData, 0); 5396 data.RelativePosition.ToBytes(objectData, 0);
5412 data.Velocity.ToBytes(objectData, 12); 5397 data.Velocity.ToBytes(objectData, 12);
5413 data.Acceleration.ToBytes(objectData, 24); 5398 data.Acceleration.ToBytes(objectData, 24);
5414 try 5399
5415 { 5400 Quaternion rotation = data.RotationOffset;
5416 data.RotationOffset.ToBytes(objectData, 36); 5401 rotation.Normalize();
5417 } 5402 rotation.ToBytes(objectData, 36);
5418 catch (Exception e)
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); 5403 data.AngularVelocity.ToBytes(objectData, 48);
5424 5404
5425 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5405 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5433,7 +5413,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5433 //update.JointType = 0; 5413 //update.JointType = 0;
5434 update.Material = data.Material; 5414 update.Material = data.Material;
5435 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim 5415 update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
5436 5416/*
5437 if (data.ParentGroup.IsAttachment) 5417 if (data.ParentGroup.IsAttachment)
5438 { 5418 {
5439 update.NameValue 5419 update.NameValue
@@ -5458,6 +5438,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5458 // case for attachments may contain conflicting values that can end up crashing the viewer. 5438 // case for attachments may contain conflicting values that can end up crashing the viewer.
5459 update.State = data.ParentGroup.RootPart.Shape.State; 5439 update.State = data.ParentGroup.RootPart.Shape.State;
5460 } 5440 }
5441*/
5442
5443 if (data.ParentGroup.IsAttachment)
5444 {
5445 if (data.IsRoot)
5446 {
5447 update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID);
5448 }
5449 else
5450 update.NameValue = Utils.EmptyBytes;
5451
5452 int st = (int)data.ParentGroup.AttachmentPoint;
5453 update.State = (byte)(((st & 0xf0) >> 4) + ((st & 0x0f) << 4)); ;
5454 }
5455 else
5456 {
5457 update.NameValue = Utils.EmptyBytes;
5458 update.State = data.Shape.State; // not sure about this
5459 }
5460
5461 5461
5462 update.ObjectData = objectData; 5462 update.ObjectData = objectData;
5463 update.ParentID = data.ParentID; 5463 update.ParentID = data.ParentID;
@@ -5579,8 +5579,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5579 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5579 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5580 // for each AgentUpdate packet. 5580 // for each AgentUpdate packet.
5581 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5581 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5582 5582
5583 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5583 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5584 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5585 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5584 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5586 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5585 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5587 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5586 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5588 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5732,6 +5734,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5732 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5734 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5733 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5735 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5734 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5736 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5737 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5735 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5738 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5736 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5739 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5737 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5740 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5798,6 +5801,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5798 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5801 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5799 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5802 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5800 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5803 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5804 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5801 5805
5802 AddGenericPacketHandler("autopilot", HandleAutopilot); 5806 AddGenericPacketHandler("autopilot", HandleAutopilot);
5803 } 5807 }
@@ -5809,7 +5813,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5809 #region Scene/Avatar 5813 #region Scene/Avatar
5810 5814
5811 // Threshold for body rotation to be a significant agent update 5815 // Threshold for body rotation to be a significant agent update
5812 private const float QDELTA = 0.000001f; 5816 // use the abs of cos
5817 private const float QDELTABody = 1.0f - 0.0001f;
5818 private const float QDELTAHead = 1.0f - 0.0001f;
5813 // Threshold for camera rotation to be a significant agent update 5819 // Threshold for camera rotation to be a significant agent update
5814 private const float VDELTA = 0.01f; 5820 private const float VDELTA = 0.01f;
5815 5821
@@ -5832,18 +5838,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5832 /// <param name='x'></param> 5838 /// <param name='x'></param>
5833 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) 5839 private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x)
5834 { 5840 {
5835 float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); 5841 float qdelta1 = Math.Abs(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation));
5836 //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); 5842 //qdelta2 = Math.Abs(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation));
5837 5843
5838 bool movementSignificant = 5844 bool movementSignificant =
5839 (qdelta1 > QDELTA) // significant if body rotation above threshold 5845 (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed
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 5846 || (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 5847 || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed
5846 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed 5848 || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed
5849 || (qdelta1 < QDELTABody) // significant if body rotation above(below cos) threshold
5850 // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack
5851 // || (qdelta2 < QDELTAHead) // significant if head rotation above(below cos) threshold
5852 || (Math.Abs(x.Far - m_thisAgentUpdateArgs.Far) >= 32) // significant if far distance changed
5847 ; 5853 ;
5848 //if (movementSignificant) 5854 //if (movementSignificant)
5849 //{ 5855 //{
@@ -5886,55 +5892,63 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5886 return cameraSignificant; 5892 return cameraSignificant;
5887 } 5893 }
5888 5894
5889 private bool HandleAgentUpdate(IClientAPI sener, Packet packet) 5895 private bool HandleAgentUpdate(IClientAPI sender, Packet packet)
5890 { 5896 {
5891 // We got here, which means that something in agent update was significant 5897 // We got here, which means that something in agent update was significant
5892 5898
5893 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; 5899 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5894 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; 5900 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5895 5901
5896 if (x.AgentID != AgentId || x.SessionID != SessionId) 5902 if (x.AgentID != AgentId || x.SessionID != SessionId)
5903 {
5904 PacketPool.Instance.ReturnPacket(packet);
5897 return false; 5905 return false;
5906 }
5907
5908 TotalAgentUpdates++;
5898 5909
5899 // Before we update the current m_thisAgentUpdateArgs, let's check this again
5900 // to see what exactly changed
5901 bool movement = CheckAgentMovementUpdateSignificance(x); 5910 bool movement = CheckAgentMovementUpdateSignificance(x);
5902 bool camera = CheckAgentCameraUpdateSignificance(x); 5911 bool camera = CheckAgentCameraUpdateSignificance(x);
5903 5912
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? 5913 // Was there a significant movement/state change?
5922 if (movement) 5914 if (movement)
5923 { 5915 {
5916 m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation;
5917 m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags;
5918 m_thisAgentUpdateArgs.Far = x.Far;
5919 m_thisAgentUpdateArgs.Flags = x.Flags;
5920 m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation;
5921// m_thisAgentUpdateArgs.SessionID = x.SessionID;
5922 m_thisAgentUpdateArgs.State = x.State;
5923
5924 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5925 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5926
5924 if (handlerPreAgentUpdate != null) 5927 if (handlerPreAgentUpdate != null)
5925 OnPreAgentUpdate(this, m_thisAgentUpdateArgs); 5928 OnPreAgentUpdate(this, m_thisAgentUpdateArgs);
5926 5929
5927 if (handlerAgentUpdate != null) 5930 if (handlerAgentUpdate != null)
5928 OnAgentUpdate(this, m_thisAgentUpdateArgs); 5931 OnAgentUpdate(this, m_thisAgentUpdateArgs);
5932
5933 handlerAgentUpdate = null;
5934 handlerPreAgentUpdate = null;
5929 } 5935 }
5936
5930 // Was there a significant camera(s) change? 5937 // Was there a significant camera(s) change?
5931 if (camera) 5938 if (camera)
5939 {
5940 m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5941 m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter;
5942 m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5943 m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5944
5945 UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate;
5946
5932 if (handlerAgentCameraUpdate != null) 5947 if (handlerAgentCameraUpdate != null)
5933 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); 5948 handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs);
5934 5949
5935 handlerAgentUpdate = null; 5950 handlerAgentCameraUpdate = null;
5936 handlerPreAgentUpdate = null; 5951 }
5937 handlerAgentCameraUpdate = null;
5938 5952
5939 PacketPool.Instance.ReturnPacket(packet); 5953 PacketPool.Instance.ReturnPacket(packet);
5940 5954
@@ -6150,6 +6164,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6150 return true; 6164 return true;
6151 } 6165 }
6152 6166
6167 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
6168 {
6169 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
6170 if (p.AgentData.SessionID != SessionId ||
6171 p.AgentData.AgentID != AgentId)
6172 return true;
6173
6174 m_VelocityInterpolate = false;
6175 return true;
6176 }
6177
6178 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
6179 {
6180 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
6181 if (p.AgentData.SessionID != SessionId ||
6182 p.AgentData.AgentID != AgentId)
6183 return true;
6184
6185 m_VelocityInterpolate = true;
6186 return true;
6187 }
6188
6189
6153 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 6190 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
6154 { 6191 {
6155 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 6192 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6503,7 +6540,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6503 { 6540 {
6504 // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, 6541 // 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. 6542 // 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) 6543 if (OnModifyTerrain != null)
6508 { 6544 {
6509 for (int i = 0; i < modify.ParcelData.Length; i++) 6545 for (int i = 0; i < modify.ParcelData.Length; i++)
@@ -6519,7 +6555,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6519 } 6555 }
6520 } 6556 }
6521 } 6557 }
6522 m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again
6523 } 6558 }
6524 6559
6525 return true; 6560 return true;
@@ -6581,16 +6616,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6581 for (int i = 0; i < appear.VisualParam.Length; i++) 6616 for (int i = 0; i < appear.VisualParam.Length; i++)
6582 visualparams[i] = appear.VisualParam[i].ParamValue; 6617 visualparams[i] = appear.VisualParam[i].ParamValue;
6583 //var b = appear.WearableData[0]; 6618 //var b = appear.WearableData[0];
6584 6619
6585 Primitive.TextureEntry te = null; 6620 Primitive.TextureEntry te = null;
6586 if (appear.ObjectData.TextureEntry.Length > 1) 6621 if (appear.ObjectData.TextureEntry.Length > 1)
6587 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6622 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6588 6623
6589 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length]; 6624 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6590 for (int i=0; i<appear.WearableData.Length;i++) 6625 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)}; 6626 cacheitems[i] = new WearableCacheItem(){
6592 6627 CacheId = appear.WearableData[i].CacheID,
6628 TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)
6629 };
6593 6630
6631
6594 6632
6595 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems); 6633 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6596 } 6634 }
@@ -6794,13 +6832,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6794 return true; 6832 return true;
6795 } 6833 }
6796 6834
6797 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack) 6835 private bool HandleCompleteAgentMovement(IClientAPI sender, Packet Pack)
6798 { 6836 {
6837 m_log.DebugFormat("[LLClientView] HandleCompleteAgentMovement");
6838
6799 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion; 6839 Action<IClientAPI, bool> handlerCompleteMovementToRegion = OnCompleteMovementToRegion;
6800 if (handlerCompleteMovementToRegion != null) 6840 if (handlerCompleteMovementToRegion != null)
6801 { 6841 {
6802 handlerCompleteMovementToRegion(sender, true); 6842 handlerCompleteMovementToRegion(sender, true);
6803 } 6843 }
6844 else
6845 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6846
6804 handlerCompleteMovementToRegion = null; 6847 handlerCompleteMovementToRegion = null;
6805 6848
6806 return true; 6849 return true;
@@ -6818,7 +6861,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6818 return true; 6861 return true;
6819 } 6862 }
6820 #endregion 6863 #endregion
6821 6864/*
6822 StartAnim handlerStartAnim = null; 6865 StartAnim handlerStartAnim = null;
6823 StopAnim handlerStopAnim = null; 6866 StopAnim handlerStopAnim = null;
6824 6867
@@ -6842,6 +6885,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6842 } 6885 }
6843 } 6886 }
6844 return true; 6887 return true;
6888*/
6889 ChangeAnim handlerChangeAnim = null;
6890
6891 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6892 {
6893 handlerChangeAnim = OnChangeAnim;
6894 if (handlerChangeAnim != null)
6895 {
6896 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6897 }
6898 }
6899
6900 handlerChangeAnim = OnChangeAnim;
6901 if (handlerChangeAnim != null)
6902 {
6903 handlerChangeAnim(UUID.Zero, false, true);
6904 }
6905
6906 return true;
6845 } 6907 }
6846 6908
6847 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6909 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -7087,6 +7149,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7087 #endregion 7149 #endregion
7088 7150
7089 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 7151 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
7152 GenericCall2 handler = OnUpdateThrottles;
7153 if (handler != null)
7154 {
7155 handler();
7156 }
7090 return true; 7157 return true;
7091 } 7158 }
7092 7159
@@ -7359,6 +7426,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7359 7426
7360 for (int i = 0; i < incomingselect.ObjectData.Length; i++) 7427 for (int i = 0; i < incomingselect.ObjectData.Length; i++)
7361 { 7428 {
7429 if (!SelectedObjects.Contains(incomingselect.ObjectData[i].ObjectLocalID))
7430 SelectedObjects.Add(incomingselect.ObjectData[i].ObjectLocalID);
7362 handlerObjectSelect = OnObjectSelect; 7431 handlerObjectSelect = OnObjectSelect;
7363 if (handlerObjectSelect != null) 7432 if (handlerObjectSelect != null)
7364 { 7433 {
@@ -7385,6 +7454,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7385 7454
7386 for (int i = 0; i < incomingdeselect.ObjectData.Length; i++) 7455 for (int i = 0; i < incomingdeselect.ObjectData.Length; i++)
7387 { 7456 {
7457 if (!SelectedObjects.Contains(incomingdeselect.ObjectData[i].ObjectLocalID))
7458 SelectedObjects.Add(incomingdeselect.ObjectData[i].ObjectLocalID);
7388 handlerObjectDeselect = OnObjectDeselect; 7459 handlerObjectDeselect = OnObjectDeselect;
7389 if (handlerObjectDeselect != null) 7460 if (handlerObjectDeselect != null)
7390 { 7461 {
@@ -7511,7 +7582,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7511 physdata.Bounce = phsblock.Restitution; 7582 physdata.Bounce = phsblock.Restitution;
7512 physdata.Density = phsblock.Density; 7583 physdata.Density = phsblock.Density;
7513 physdata.Friction = phsblock.Friction; 7584 physdata.Friction = phsblock.Friction;
7514 physdata.GravitationModifier = phsblock.GravityMultiplier; 7585 physdata.GravitationModifier = phsblock.GravityMultiplier;
7515 } 7586 }
7516 7587
7517 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7588 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -8097,6 +8168,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8097 // surrounding scene 8168 // surrounding scene
8098 if ((ImageType)block.Type == ImageType.Baked) 8169 if ((ImageType)block.Type == ImageType.Baked)
8099 args.Priority *= 2.0f; 8170 args.Priority *= 2.0f;
8171 int wearableout = 0;
8100 8172
8101 ImageManager.EnqueueReq(args); 8173 ImageManager.EnqueueReq(args);
8102 } 8174 }
@@ -9106,7 +9178,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9106 if ((locX >= m_scene.RegionInfo.WorldLocX) 9178 if ((locX >= m_scene.RegionInfo.WorldLocX)
9107 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX)) 9179 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
9108 && (locY >= m_scene.RegionInfo.WorldLocY) 9180 && (locY >= m_scene.RegionInfo.WorldLocY)
9109 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) ) 9181 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)))
9110 { 9182 {
9111 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle; 9183 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
9112 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX; 9184 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
@@ -9146,16 +9218,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9146 9218
9147 #region Parcel related packets 9219 #region Parcel related packets
9148 9220
9221 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
9222 // to be done with minimal resources as possible
9223 // variables temporary here while in test
9224
9225 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
9226 bool RegionHandleRequestsInService = false;
9227
9149 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 9228 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
9150 { 9229 {
9151 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 9230 UUID currentUUID;
9152 9231
9153 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 9232 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
9154 if (handlerRegionHandleRequest != null) 9233
9234 if (handlerRegionHandleRequest == null)
9235 return true;
9236
9237 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
9238
9239 lock (RegionHandleRequests)
9155 { 9240 {
9156 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 9241 if (RegionHandleRequestsInService)
9242 {
9243 // we are already busy doing a previus request
9244 // so enqueue it
9245 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
9246 return true;
9247 }
9248
9249 // else do it
9250 currentUUID = rhrPack.RequestBlock.RegionID;
9251 RegionHandleRequestsInService = true;
9157 } 9252 }
9158 return true; 9253
9254 while (true)
9255 {
9256 handlerRegionHandleRequest(this, currentUUID);
9257
9258 lock (RegionHandleRequests)
9259 {
9260 // exit condition, nothing to do or closed
9261 // current code seems to assume we may loose the handler at anytime,
9262 // so keep checking it
9263 handlerRegionHandleRequest = OnRegionHandleRequest;
9264
9265 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
9266 {
9267 RegionHandleRequests.Clear();
9268 RegionHandleRequestsInService = false;
9269 return true;
9270 }
9271 currentUUID = RegionHandleRequests.Dequeue();
9272 }
9273 }
9274
9275 return true; // actually unreached
9159 } 9276 }
9160 9277
9161 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 9278 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -10425,7 +10542,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10425 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10542 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
10426 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10543 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
10427 UpdateMuteListEntry.MuteData.MuteType, 10544 UpdateMuteListEntry.MuteData.MuteType,
10428 UpdateMuteListEntry.AgentData.AgentID); 10545 UpdateMuteListEntry.MuteData.MuteFlags);
10429 return true; 10546 return true;
10430 } 10547 }
10431 return false; 10548 return false;
@@ -10440,8 +10557,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10440 { 10557 {
10441 handlerRemoveMuteListEntry(this, 10558 handlerRemoveMuteListEntry(this,
10442 RemoveMuteListEntry.MuteData.MuteID, 10559 RemoveMuteListEntry.MuteData.MuteID,
10443 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10560 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
10444 RemoveMuteListEntry.AgentData.AgentID);
10445 return true; 10561 return true;
10446 } 10562 }
10447 return false; 10563 return false;
@@ -10485,10 +10601,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10485 return false; 10601 return false;
10486 } 10602 }
10487 10603
10604 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10605 {
10606 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10607 (ChangeInventoryItemFlagsPacket)packet;
10608 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10609 if (handlerChangeInventoryItemFlags != null)
10610 {
10611 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10612 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10613 return true;
10614 }
10615 return false;
10616 }
10617
10488 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10618 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10489 { 10619 {
10490 return true; 10620 return true;
10491 } 10621 }
10622
10623 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10624 {
10625 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10626
10627 #region Packet Session and User Check
10628 if (m_checkPackets)
10629 {
10630 if (packet.AgentData.SessionID != SessionId ||
10631 packet.AgentData.AgentID != AgentId)
10632 return true;
10633 }
10634 #endregion
10635 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10636 List<InventoryItemBase> items = new List<InventoryItemBase>();
10637 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10638 {
10639 InventoryItemBase b = new InventoryItemBase();
10640 b.ID = n.OldItemID;
10641 b.Folder = n.OldFolderID;
10642 items.Add(b);
10643 }
10644
10645 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10646 if (handlerMoveItemsAndLeaveCopy != null)
10647 {
10648 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10649 }
10650
10651 return true;
10652 }
10492 10653
10493 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10654 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10494 { 10655 {
@@ -10915,6 +11076,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10915 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 11076 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10916 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 11077 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10917 11078
11079 Scene scene = (Scene)m_scene;
11080 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
11081 {
11082 ScenePresence p;
11083 if (scene.TryGetScenePresence(sender.AgentId, out p))
11084 {
11085 if (p.GodLevel >= 200)
11086 {
11087 groupProfileReply.GroupData.OpenEnrollment = true;
11088 groupProfileReply.GroupData.MembershipFee = 0;
11089 }
11090 }
11091 }
11092
10918 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 11093 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10919 } 11094 }
10920 return true; 11095 return true;
@@ -11488,11 +11663,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11488 11663
11489 StartLure handlerStartLure = OnStartLure; 11664 StartLure handlerStartLure = OnStartLure;
11490 if (handlerStartLure != null) 11665 if (handlerStartLure != null)
11491 handlerStartLure(startLureRequest.Info.LureType, 11666 {
11492 Utils.BytesToString( 11667 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11493 startLureRequest.Info.Message), 11668 {
11494 startLureRequest.TargetData[0].TargetID, 11669 handlerStartLure(startLureRequest.Info.LureType,
11495 this); 11670 Utils.BytesToString(
11671 startLureRequest.Info.Message),
11672 startLureRequest.TargetData[i].TargetID,
11673 this);
11674 }
11675 }
11496 return true; 11676 return true;
11497 } 11677 }
11498 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11678 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11606,10 +11786,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11606 } 11786 }
11607 #endregion 11787 #endregion
11608 11788
11609 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11789 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11610 if (handlerClassifiedGodDelete != null) 11790 if (handlerClassifiedGodDelete != null)
11611 handlerClassifiedGodDelete( 11791 handlerClassifiedGodDelete(
11612 classifiedGodDelete.Data.ClassifiedID, 11792 classifiedGodDelete.Data.ClassifiedID,
11793 classifiedGodDelete.Data.QueryID,
11613 this); 11794 this);
11614 return true; 11795 return true;
11615 } 11796 }
@@ -11912,6 +12093,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11912 /// <param name="simclient"></param> 12093 /// <param name="simclient"></param>
11913 /// <param name="packet"></param> 12094 /// <param name="packet"></param>
11914 /// <returns></returns> 12095 /// <returns></returns>
12096 // TODO: Convert old handler to use new method
12097/*
11915 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 12098 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11916 { 12099 {
11917 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 12100 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
@@ -11919,6 +12102,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11919 12102
11920 if (cachedtex.AgentData.SessionID != SessionId) 12103 if (cachedtex.AgentData.SessionID != SessionId)
11921 return false; 12104 return false;
12105
11922 12106
11923 12107
11924 // TODO: don't create new blocks if recycling an old packet 12108 // TODO: don't create new blocks if recycling an old packet
@@ -11966,32 +12150,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11966 } 12150 }
11967 } 12151 }
11968 12152
11969 if (cacheItems != null) 12153 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
12154 if (handlerCachedTextureRequest != null)
11970 { 12155 {
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. 12156 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11972 // Copy the baked textures to the sim's assets cache (local only). 12157 }
11973 foreach (WearableCacheItem item in cacheItems) 12158
11974 { 12159 return true;
11975 if (cache.GetCached(item.TextureID.ToString()) == null) 12160 }
11976 { 12161*/
11977 item.TextureAsset.Temporary = true; 12162
11978 item.TextureAsset.Local = true; 12163 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11979 cache.Store(item.TextureAsset); 12164 {
11980 } 12165 //m_log.Debug("texture cached: " + packet.ToString());
11981 } 12166 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
12167 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
12168
12169 if (cachedtex.AgentData.SessionID != SessionId)
12170 return false;
12171
12172 // TODO: don't create new blocks if recycling an old packet
12173 cachedresp.AgentData.AgentID = AgentId;
12174 cachedresp.AgentData.SessionID = m_sessionId;
12175 cachedresp.AgentData.SerialNum = cachedtex.AgentData.SerialNum;
12176 cachedresp.WearableData =
12177 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11982 12178
11983 // Return the cached textures 12179 int maxWearablesLoop = cachedtex.WearableData.Length;
12180 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
12181 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
12182
12183 int cacheHits = 0;
12184
12185 // 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
12186
12187 WearableCacheItem[] cacheItems = null;
12188
12189 ScenePresence p = m_scene.GetScenePresence(AgentId);
12190
12191 if (p != null && p.Appearance != null)
12192 {
12193 cacheItems = p.Appearance.WearableCacheItems;
12194 }
12195
12196 if (cacheItems != null)
12197 {
11984 for (int i = 0; i < maxWearablesLoop; i++) 12198 for (int i = 0; i < maxWearablesLoop; i++)
11985 { 12199 {
11986 WearableCacheItem item = 12200 int idx = cachedtex.WearableData[i].TextureIndex;
11987 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex, cacheItems);
11988
11989 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12201 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11990 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 12202 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11991 cachedresp.WearableData[i].HostName = new byte[0]; 12203 cachedresp.WearableData[i].HostName = new byte[0];
11992 if (item != null && cachedtex.WearableData[i].ID == item.CacheId) 12204 if (cachedtex.WearableData[i].ID == cacheItems[idx].CacheId)
11993 { 12205 {
11994 cachedresp.WearableData[i].TextureID = item.TextureID; 12206 cachedresp.WearableData[i].TextureID = cacheItems[idx].TextureID;
12207 cacheHits++;
11995 } 12208 }
11996 else 12209 else
11997 { 12210 {
@@ -12001,7 +12214,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12001 } 12214 }
12002 else 12215 else
12003 { 12216 {
12004 // Cached textures not available
12005 for (int i = 0; i < maxWearablesLoop; i++) 12217 for (int i = 0; i < maxWearablesLoop; i++)
12006 { 12218 {
12007 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 12219 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
@@ -12010,13 +12222,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12010 cachedresp.WearableData[i].HostName = new byte[0]; 12222 cachedresp.WearableData[i].HostName = new byte[0];
12011 } 12223 }
12012 } 12224 }
12013 12225
12226 m_log.DebugFormat("texture cached: hits {0}", cacheHits);
12227
12014 cachedresp.Header.Zerocoded = true; 12228 cachedresp.Header.Zerocoded = true;
12015 OutPacket(cachedresp, ThrottleOutPacketType.Task); 12229 OutPacket(cachedresp, ThrottleOutPacketType.Task);
12016 12230
12017 return true; 12231 return true;
12018 } 12232 }
12019 12233
12020 /// <summary> 12234 /// <summary>
12021 /// Send a response back to a client when it asks the asset server (via the region server) if it has 12235 /// 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. 12236 /// its appearance texture cached.
@@ -12080,209 +12294,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12080 } 12294 }
12081 else 12295 else
12082 { 12296 {
12083// m_log.DebugFormat( 12297 ClientChangeObject updatehandler = onClientChangeObject;
12084// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
12085// i, block.Type, part.Name, part.LocalId);
12086 12298
12087// // Do this once since fetch parts creates a new array. 12299 if (updatehandler != null)
12088// SceneObjectPart[] parts = part.ParentGroup.Parts; 12300 {
12089// for (int j = 0; j < parts.Length; j++) 12301 ObjectChangeData udata = new ObjectChangeData();
12090// {
12091// part.StoreUndoState();
12092// parts[j].IgnoreUndoUpdate = true;
12093// }
12094 12302
12095 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 12303 /*ubit from ll JIRA:
12304 * 0x01 position
12305 * 0x02 rotation
12306 * 0x04 scale
12307
12308 * 0x08 LINK_SET
12309 * 0x10 UNIFORM for scale
12310 */
12096 12311
12097 switch (block.Type) 12312 // translate to internal changes
12098 { 12313 // not all cases .. just the ones older code did
12099 case 1:
12100 Vector3 pos1 = new Vector3(block.Data, 0);
12101 12314
12102 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12315 switch (block.Type)
12103 if (handlerUpdatePrimSinglePosition != null) 12316 {
12104 { 12317 case 1: //change position sp
12105 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12318 udata.position = new Vector3(block.Data, 0);
12106 handlerUpdatePrimSinglePosition(localId, pos1, this);
12107 }
12108 break;
12109 12319
12110 case 2: 12320 udata.change = ObjectChangeType.primP;
12111 Quaternion rot1 = new Quaternion(block.Data, 0, true); 12321 updatehandler(localId, udata, this);
12322 break;
12112 12323
12113 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 12324 case 2: // rotation sp
12114 if (handlerUpdatePrimSingleRotation != null) 12325 udata.rotation = new Quaternion(block.Data, 0, true);
12115 {
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 12326
12121 case 3: 12327 udata.change = ObjectChangeType.primR;
12122 Vector3 rotPos = new Vector3(block.Data, 0); 12328 updatehandler(localId, udata, this);
12123 Quaternion rot2 = new Quaternion(block.Data, 12, true); 12329 break;
12124 12330
12125 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 12331 case 3: // position plus rotation
12126 if (handlerUpdatePrimSingleRotationPosition != null) 12332 udata.position = new Vector3(block.Data, 0);
12127 { 12333 udata.rotation = new Quaternion(block.Data, 12, true);
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 12334
12134 case 4: 12335 udata.change = ObjectChangeType.primPR;
12135 case 20: 12336 updatehandler(localId, udata, this);
12136 Vector3 scale4 = new Vector3(block.Data, 0); 12337 break;
12137 12338
12138 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 12339 case 4: // scale sp
12139 if (handlerUpdatePrimScale != null) 12340 udata.scale = new Vector3(block.Data, 0);
12140 { 12341 udata.change = ObjectChangeType.primS;
12141 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
12142 handlerUpdatePrimScale(localId, scale4, this);
12143 }
12144 break;
12145 12342
12146 case 5: 12343 updatehandler(localId, udata, this);
12147 Vector3 scale1 = new Vector3(block.Data, 12); 12344 break;
12148 Vector3 pos11 = new Vector3(block.Data, 0);
12149 12345
12150 handlerUpdatePrimScale = OnUpdatePrimScale; 12346 case 0x14: // uniform scale sp
12151 if (handlerUpdatePrimScale != null) 12347 udata.scale = new Vector3(block.Data, 0);
12152 {
12153 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12154 handlerUpdatePrimScale(localId, scale1, this);
12155 12348
12156 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12349 udata.change = ObjectChangeType.primUS;
12157 if (handlerUpdatePrimSinglePosition != null) 12350 updatehandler(localId, udata, this);
12158 { 12351 break;
12159 handlerUpdatePrimSinglePosition(localId, pos11, this);
12160 }
12161 }
12162 break;
12163 12352
12164 case 9: 12353 case 5: // scale and position sp
12165 Vector3 pos2 = new Vector3(block.Data, 0); 12354 udata.position = new Vector3(block.Data, 0);
12355 udata.scale = new Vector3(block.Data, 12);
12166 12356
12167 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 12357 udata.change = ObjectChangeType.primPS;
12358 updatehandler(localId, udata, this);
12359 break;
12168 12360
12169 if (handlerUpdateVector != null) 12361 case 0x15: //uniform scale and position
12170 { 12362 udata.position = new Vector3(block.Data, 0);
12171 handlerUpdateVector(localId, pos2, this); 12363 udata.scale = new Vector3(block.Data, 12);
12172 }
12173 break;
12174 12364
12175 case 10: 12365 udata.change = ObjectChangeType.primPUS;
12176 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12366 updatehandler(localId, udata, this);
12367 break;
12177 12368
12178 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12369 // now group related (bit 4)
12179 if (handlerUpdatePrimRotation != null) 12370 case 9: //( 8 + 1 )group position
12180 { 12371 udata.position = new Vector3(block.Data, 0);
12181 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
12182 handlerUpdatePrimRotation(localId, rot3, this);
12183 }
12184 break;
12185 12372
12186 case 11: 12373 udata.change = ObjectChangeType.groupP;
12187 Vector3 pos3 = new Vector3(block.Data, 0); 12374 updatehandler(localId, udata, this);
12188 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12375 break;
12189 12376
12190 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12377 case 0x0A: // (8 + 2) group rotation
12191 if (handlerUpdatePrimGroupRotation != null) 12378 udata.rotation = new Quaternion(block.Data, 0, true);
12192 {
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 12379
12202 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12380 udata.change = ObjectChangeType.groupR;
12203 if (handlerUpdatePrimGroupScale != null) 12381 updatehandler(localId, udata, this);
12204 { 12382 break;
12205 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
12206 handlerUpdatePrimGroupScale(localId, scale7, this);
12207 }
12208 break;
12209 12383
12210 case 13: 12384 case 0x0B: //( 8 + 2 + 1) group rotation and position
12211 Vector3 scale2 = new Vector3(block.Data, 12); 12385 udata.position = new Vector3(block.Data, 0);
12212 Vector3 pos4 = new Vector3(block.Data, 0); 12386 udata.rotation = new Quaternion(block.Data, 12, true);
12213 12387
12214 handlerUpdatePrimScale = OnUpdatePrimScale; 12388 udata.change = ObjectChangeType.groupPR;
12215 if (handlerUpdatePrimScale != null) 12389 updatehandler(localId, udata, this);
12216 { 12390 break;
12217 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
12218 handlerUpdatePrimScale(localId, scale2, this);
12219 12391
12220 // Change the position based on scale (for bug number 246) 12392 case 0x0C: // (8 + 4) group scale
12221 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12393 // only afects root prim and only sent by viewer editor object tab scaling
12222 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12394 // mouse edition only allows uniform scaling
12223 if (handlerUpdatePrimSinglePosition != null) 12395 // SL MAY CHANGE THIS in viewers
12224 {
12225 handlerUpdatePrimSinglePosition(localId, pos4, this);
12226 }
12227 }
12228 break;
12229 12396
12230 case 29: 12397 udata.scale = new Vector3(block.Data, 0);
12231 Vector3 scale5 = new Vector3(block.Data, 12);
12232 Vector3 pos5 = new Vector3(block.Data, 0);
12233 12398
12234 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12399 udata.change = ObjectChangeType.groupS;
12235 if (handlerUpdatePrimGroupScale != null) 12400 updatehandler(localId, udata, this);
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 12401
12243 if (handlerUpdateVector != null) 12402 break;
12244 {
12245 handlerUpdateVector(localId, pos5, this);
12246 }
12247 12403
12248 part.IgnoreUndoUpdate = false; 12404 case 0x0D: //(8 + 4 + 1) group scale and position
12249 } 12405 // exception as above
12250 12406
12251 break; 12407 udata.position = new Vector3(block.Data, 0);
12408 udata.scale = new Vector3(block.Data, 12);
12252 12409
12253 case 21: 12410 udata.change = ObjectChangeType.groupPS;
12254 Vector3 scale6 = new Vector3(block.Data, 12); 12411 updatehandler(localId, udata, this);
12255 Vector3 pos6 = new Vector3(block.Data, 0); 12412 break;
12256 12413
12257 handlerUpdatePrimScale = OnUpdatePrimScale; 12414 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
12258 if (handlerUpdatePrimScale != null) 12415 udata.scale = new Vector3(block.Data, 0);
12259 {
12260 part.StoreUndoState(false);
12261 part.IgnoreUndoUpdate = true;
12262 12416
12263 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12417 udata.change = ObjectChangeType.groupUS;
12264 handlerUpdatePrimScale(localId, scale6, this); 12418 updatehandler(localId, udata, this);
12265 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12419 break;
12266 if (handlerUpdatePrimSinglePosition != null)
12267 {
12268 handlerUpdatePrimSinglePosition(localId, pos6, this);
12269 }
12270 12420
12271 part.IgnoreUndoUpdate = false; 12421 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
12272 } 12422 udata.position = new Vector3(block.Data, 0);
12273 break; 12423 udata.scale = new Vector3(block.Data, 12);
12274 12424
12275 default: 12425 udata.change = ObjectChangeType.groupPUS;
12276 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12426 updatehandler(localId, udata, this);
12277 break; 12427 break;
12428
12429 default:
12430 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12431 break;
12432 }
12278 } 12433 }
12279 12434
12280// for (int j = 0; j < parts.Length; j++)
12281// parts[j].IgnoreUndoUpdate = false;
12282 } 12435 }
12283 } 12436 }
12284 } 12437 }
12285
12286 return true; 12438 return true;
12287 } 12439 }
12288 12440
@@ -12342,7 +12494,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12342 /// <param name="throttles"></param> 12494 /// <param name="throttles"></param>
12343 public void SetChildAgentThrottle(byte[] throttles) 12495 public void SetChildAgentThrottle(byte[] throttles)
12344 { 12496 {
12345 m_udpClient.SetThrottles(throttles); 12497 SetChildAgentThrottle(throttles, 1.0f);
12498 }
12499
12500 public void SetChildAgentThrottle(byte[] throttles,float factor)
12501 {
12502 m_udpClient.SetThrottles(throttles, factor);
12503 GenericCall2 handler = OnUpdateThrottles;
12504 if (handler != null)
12505 {
12506 handler();
12507 }
12508 }
12509
12510 /// <summary>
12511 /// Sets the throttles from values supplied caller
12512 /// </summary>
12513 /// <param name="throttles"></param>
12514 public void SetAgentThrottleSilent(int throttle, int setting)
12515 {
12516 m_udpClient.ForceThrottleSetting(throttle,setting);
12517 }
12518
12519 public int GetAgentThrottleSilent(int throttle)
12520 {
12521 return m_udpClient.GetThrottleSetting(throttle);
12346 } 12522 }
12347 12523
12348 /// <summary> 12524 /// <summary>
@@ -12450,8 +12626,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12450 uint regionY = 0; 12626 uint regionY = 0;
12451 12627
12452 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY); 12628 Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out regionX, out regionY);
12453 locx = Convert.ToSingle(args[0]) - (float)regionX; 12629 locx = (float)(Convert.ToDouble(args[0]) - (double)regionX);
12454 locy = Convert.ToSingle(args[1]) - (float)regionY; 12630 locy = (float)(Convert.ToDouble(args[1]) - (double)regionY);
12455 locz = Convert.ToSingle(args[2]); 12631 locz = Convert.ToSingle(args[2]);
12456 12632
12457 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo; 12633 Action<Vector3, bool, bool> handlerAutoPilotGo = OnAutoPilotGo;
@@ -12736,7 +12912,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12736// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12912// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12737// requestID, taskID, (SourceType)sourceType, Name); 12913// requestID, taskID, (SourceType)sourceType, Name);
12738 12914
12915
12916 //Note, the bool returned from the below function is useless since it is always false.
12739 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12917 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12918
12740 } 12919 }
12741 12920
12742 /// <summary> 12921 /// <summary>
@@ -12819,7 +12998,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12819 /// <returns></returns> 12998 /// <returns></returns>
12820 private static int CalculateNumPackets(byte[] data) 12999 private static int CalculateNumPackets(byte[] data)
12821 { 13000 {
12822 const uint m_maxPacketSize = 600; 13001// const uint m_maxPacketSize = 600;
13002 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12823 int numPackets = 1; 13003 int numPackets = 1;
12824 13004
12825 if (data == null) 13005 if (data == null)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 0394e54..8d4117d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -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;
@@ -129,7 +131,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
129 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 131 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
130 132
131 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 133 /// <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>(); 134 public readonly DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>();
133 135
134 /// <summary>Current packet sequence number</summary> 136 /// <summary>Current packet sequence number</summary>
135 public int CurrentSequence; 137 public int CurrentSequence;
@@ -181,7 +183,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 /// <summary>Throttle buckets for each packet category</summary> 183 /// <summary>Throttle buckets for each packet category</summary>
182 private readonly TokenBucket[] m_throttleCategories; 184 private readonly TokenBucket[] m_throttleCategories;
183 /// <summary>Outgoing queues for throttled packets</summary> 185 /// <summary>Outgoing queues for throttled packets</summary>
184 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 186 private readonly 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 187 /// <summary>A container that can hold one packet for each outbox, used to store
186 /// dequeued packets that are being held for throttling</summary> 188 /// dequeued packets that are being held for throttling</summary>
187 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 189 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
@@ -193,6 +195,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
193 195
194 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 196 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
195 private int m_maxRTO = 60000; 197 private int m_maxRTO = 60000;
198 public bool m_deliverPackets = true;
199
200 private float m_burstTime;
201
202 public int m_lastStartpingTimeMS;
203 public int m_pingMS;
204
205 public int PingTimeMS
206 {
207 get
208 {
209 if (m_pingMS < 10)
210 return 10;
211 if(m_pingMS > 2000)
212 return 2000;
213 return m_pingMS;
214 }
215 }
196 216
197 /// <summary> 217 /// <summary>
198 /// This is the percentage of the udp texture queue to add to the task queue since 218 /// This is the percentage of the udp texture queue to add to the task queue since
@@ -234,29 +254,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 254
235 ProcessUnackedSends = true; 255 ProcessUnackedSends = true;
236 256
257 m_burstTime = rates.BrustTime;
258 float m_burst = rates.ClientMaxRate * m_burstTime;
259
237 // Create a token bucket throttle for this client that has the scene token bucket as a parent 260 // Create a token bucket throttle for this client that has the scene token bucket as a parent
238 m_throttleClient 261 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 262
243 // Create an array of token buckets for this clients different throttle categories 263 // Create an array of token buckets for this clients different throttle categories
244 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 264 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
245 265
246 m_cannibalrate = rates.CannibalizeTextureRate; 266 m_cannibalrate = rates.CannibalizeTextureRate;
247 267
268 m_burst = rates.Total * rates.BrustTime;
269
248 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 270 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
249 { 271 {
250 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 272 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
251 273
252 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 274 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
253 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 275 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
254
255 // Initialize the token buckets that control the throttling for each category 276 // Initialize the token buckets that control the throttling for each category
256 m_throttleCategories[i] 277 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 } 278 }
261 279
262 // Default the retransmission timeout to one second 280 // Default the retransmission timeout to one second
@@ -264,6 +282,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
264 282
265 // Initialize this to a sane value to prevent early disconnects 283 // Initialize this to a sane value to prevent early disconnects
266 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; 284 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
285 m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0;
267 } 286 }
268 287
269 /// <summary> 288 /// <summary>
@@ -302,9 +321,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
302 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 321 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
303 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 322 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
304 m_info.totalThrottle = (int)m_throttleClient.DripRate; 323 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; 324 return m_info;
309 } 325 }
310 326
@@ -389,6 +405,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
389 405
390 public void SetThrottles(byte[] throttleData) 406 public void SetThrottles(byte[] throttleData)
391 { 407 {
408 SetThrottles(throttleData, 1.0f);
409 }
410
411 public void SetThrottles(byte[] throttleData, float factor)
412 {
392 byte[] adjData; 413 byte[] adjData;
393 int pos = 0; 414 int pos = 0;
394 415
@@ -408,24 +429,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
408 } 429 }
409 430
410 // 0.125f converts from bits to bytes 431 // 0.125f converts from bits to bytes
411 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 432 float scale = 0.125f * factor;
412 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 433 int resend = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
413 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 434 int land = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
414 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 435 int wind = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
415 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 436 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
416 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 437 int task = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
417 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 438 int texture = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
439 int asset = (int)(BitConverter.ToSingle(adjData, pos) * scale);
440
418 441
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 442
427 // Make sure none of the throttles are set below our packet MTU, 443 // Make sure none of the throttles are set below our packet MTU,
428 // otherwise a throttle could become permanently clogged 444 // otherwise a throttle could become permanently clogged
445
446/* not using floats
429 resend = Math.Max(resend, LLUDPServer.MTU); 447 resend = Math.Max(resend, LLUDPServer.MTU);
430 land = Math.Max(land, LLUDPServer.MTU); 448 land = Math.Max(land, LLUDPServer.MTU);
431 wind = Math.Max(wind, LLUDPServer.MTU); 449 wind = Math.Max(wind, LLUDPServer.MTU);
@@ -433,52 +451,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP
433 task = Math.Max(task, LLUDPServer.MTU); 451 task = Math.Max(task, LLUDPServer.MTU);
434 texture = Math.Max(texture, LLUDPServer.MTU); 452 texture = Math.Max(texture, LLUDPServer.MTU);
435 asset = Math.Max(asset, LLUDPServer.MTU); 453 asset = Math.Max(asset, LLUDPServer.MTU);
454*/
436 455
437 // Since most textures are now delivered through http, make it possible 456 // 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 457 // to cannibalize some of the bw from the texture throttle to use for
439 // the task queue (e.g. object updates) 458 // the task queue (e.g. object updates)
440 task = task + (int)(m_cannibalrate * texture); 459 task = task + (int)(m_cannibalrate * texture);
441 texture = (int)((1 - m_cannibalrate) * texture); 460 texture = (int)((1 - m_cannibalrate) * texture);
442 461
443 //int total = resend + land + wind + cloud + task + texture + asset; 462 int total = resend + land + wind + cloud + task + texture + asset;
463
464 float m_burst = total * m_burstTime;
444 465
445 if (ThrottleDebugLevel > 0) 466 if (ThrottleDebugLevel > 0)
446 { 467 {
447 long total = resend + land + wind + cloud + task + texture + asset;
448 m_log.DebugFormat( 468 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}", 469 "[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); 470 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
451 } 471 }
452 472
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; 473 TokenBucket bucket;
461 474
462 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 475 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
463 bucket.RequestedDripRate = resend; 476 bucket.RequestedDripRate = resend;
477 bucket.RequestedBurst = m_burst;
464 478
465 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; 479 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
466 bucket.RequestedDripRate = land; 480 bucket.RequestedDripRate = land;
481 bucket.RequestedBurst = m_burst;
467 482
468 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; 483 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
469 bucket.RequestedDripRate = wind; 484 bucket.RequestedDripRate = wind;
485 bucket.RequestedBurst = m_burst;
470 486
471 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; 487 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
472 bucket.RequestedDripRate = cloud; 488 bucket.RequestedDripRate = cloud;
489 bucket.RequestedBurst = m_burst;
473 490
474 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; 491 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
475 bucket.RequestedDripRate = asset; 492 bucket.RequestedDripRate = asset;
493 bucket.RequestedBurst = m_burst;
476 494
477 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 495 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
478 bucket.RequestedDripRate = task; 496 bucket.RequestedDripRate = task;
497 bucket.RequestedBurst = m_burst;
479 498
480 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 499 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
481 bucket.RequestedDripRate = texture; 500 bucket.RequestedDripRate = texture;
501 bucket.RequestedBurst = m_burst;
482 502
483 // Reset the packed throttles cached data 503 // Reset the packed throttles cached data
484 m_packedThrottles = null; 504 m_packedThrottles = null;
@@ -496,25 +516,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
496 int i = 0; 516 int i = 0;
497 517
498 // multiply by 8 to convert bytes back to bits 518 // multiply by 8 to convert bytes back to bits
499 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier; 519 multiplier *= 8;
520
521 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier;
500 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 522 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
501 523
502 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier; 524 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier;
503 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 525 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
504 526
505 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier; 527 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier;
506 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 528 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
507 529
508 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier; 530 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier;
509 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 531 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
510 532
511 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier; 533 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier;
512 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 534 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
513 535
514 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier; 536 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier;
515 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 537 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
516 538
517 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier; 539 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier;
518 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 540 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
519 541
520 m_packedThrottles = data; 542 m_packedThrottles = data;
@@ -523,6 +545,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
523 return data; 545 return data;
524 } 546 }
525 547
548 public int GetCatBytesInSendQueue(ThrottleOutPacketType cat)
549 {
550 ;
551 int icat = (int)cat;
552 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
553 {
554 TokenBucket bucket = m_throttleCategories[icat];
555 return m_packetOutboxes[icat].Count;
556 }
557 else
558 return 0;
559 }
560
561
562 public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS)
563 {
564 int icat = (int)cat;
565 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
566 {
567 TokenBucket bucket = m_throttleCategories[icat];
568 return bucket.GetCatBytesCanSend(timeMS);
569 }
570 else
571 return 0;
572 }
573
526 /// <summary> 574 /// <summary>
527 /// Queue an outgoing packet if appropriate. 575 /// Queue an outgoing packet if appropriate.
528 /// </summary> 576 /// </summary>
@@ -534,32 +582,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
534 /// </returns> 582 /// </returns>
535 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) 583 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
536 { 584 {
585 return EnqueueOutgoing(packet, forceQueue, false);
586 }
587
588 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
589 {
537 int category = (int)packet.Category; 590 int category = (int)packet.Category;
538 591
539 if (category >= 0 && category < m_packetOutboxes.Length) 592 if (category >= 0 && category < m_packetOutboxes.Length)
540 { 593 {
541 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 594 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
595
596 if (m_deliverPackets == false)
597 {
598 queue.Enqueue(packet, highPriority);
599 return true;
600 }
601
542 TokenBucket bucket = m_throttleCategories[category]; 602 TokenBucket bucket = m_throttleCategories[category];
543 603
544 // Don't send this packet if there is already a packet waiting in the queue 604 // 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 605 if (queue.Count > 0 || m_nextPackets[category] != null)
546 // queued packets
547 if (queue.Count > 0)
548 { 606 {
549 queue.Enqueue(packet); 607 queue.Enqueue(packet, highPriority);
550 return true; 608 return true;
551 } 609 }
552 610
553
554 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) 611 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
555 { 612 {
556 // Enough tokens were removed from the bucket, the packet will not be queued 613 // enough tokens so it can be sent imediatly by caller
557 return false; 614 return false;
558 } 615 }
559 else 616 else
560 { 617 {
561 // Force queue specified or not enough tokens in the bucket, queue this packet 618 // Force queue specified or not enough tokens in the bucket, queue this packet
562 queue.Enqueue(packet); 619 queue.Enqueue(packet, highPriority);
563 return true; 620 return true;
564 } 621 }
565 } 622 }
@@ -588,8 +645,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
588 /// <returns>True if any packets were sent, otherwise false</returns> 645 /// <returns>True if any packets were sent, otherwise false</returns>
589 public bool DequeueOutgoing() 646 public bool DequeueOutgoing()
590 { 647 {
591 OutgoingPacket packet; 648// if (m_deliverPackets == false) return false;
592 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 649
650 OutgoingPacket packet = null;
651 DoubleLocklessQueue<OutgoingPacket> queue;
593 TokenBucket bucket; 652 TokenBucket bucket;
594 bool packetSent = false; 653 bool packetSent = false;
595 ThrottleOutPacketTypeFlags emptyCategories = 0; 654 ThrottleOutPacketTypeFlags emptyCategories = 0;
@@ -613,6 +672,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
613 m_udpServer.SendPacketFinal(nextPacket); 672 m_udpServer.SendPacketFinal(nextPacket);
614 m_nextPackets[i] = null; 673 m_nextPackets[i] = null;
615 packetSent = true; 674 packetSent = true;
675
676 if (m_packetOutboxes[i].Count < 5)
677 emptyCategories |= CategoryToFlag(i);
616 } 678 }
617 } 679 }
618 else 680 else
@@ -620,32 +682,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP
620 // No dequeued packet waiting to be sent, try to pull one off 682 // No dequeued packet waiting to be sent, try to pull one off
621 // this queue 683 // this queue
622 queue = m_packetOutboxes[i]; 684 queue = m_packetOutboxes[i];
623 if (queue.Dequeue(out packet)) 685 if (queue != null)
624 { 686 {
625 // A packet was pulled off the queue. See if we have 687 bool success = false;
626 // enough tokens in the bucket to send it out 688 try
627 if (bucket.RemoveTokens(packet.Buffer.DataLength))
628 { 689 {
629 // Send the packet 690 success = queue.Dequeue(out packet);
630 m_udpServer.SendPacketFinal(packet);
631 packetSent = true;
632 } 691 }
633 else 692 catch
634 { 693 {
635 // Save the dequeued packet for the next iteration 694 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
636 m_nextPackets[i] = packet;
637 } 695 }
696 if (success)
697 {
698 // A packet was pulled off the queue. See if we have
699 // enough tokens in the bucket to send it out
700 if (bucket.RemoveTokens(packet.Buffer.DataLength))
701 {
702 // Send the packet
703 m_udpServer.SendPacketFinal(packet);
704 packetSent = true;
705
706 if (queue.Count < 5)
707 emptyCategories |= CategoryToFlag(i);
708 }
709 else
710 {
711 // Save the dequeued packet for the next iteration
712 m_nextPackets[i] = packet;
713 }
638 714
639 // If the queue is empty after this dequeue, fire the queue 715 }
640 // empty callback now so it has a chance to fill before we 716 else
641 // get back here 717 {
642 if (queue.Count == 0) 718 // No packets in this queue. Fire the queue empty callback
719 // if it has not been called recently
643 emptyCategories |= CategoryToFlag(i); 720 emptyCategories |= CategoryToFlag(i);
721 }
644 } 722 }
645 else 723 else
646 { 724 {
647 // No packets in this queue. Fire the queue empty callback 725 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
648 // if it has not been called recently
649 emptyCategories |= CategoryToFlag(i); 726 emptyCategories |= CategoryToFlag(i);
650 } 727 }
651 } 728 }
@@ -712,6 +789,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
712 RTO = Math.Min(RTO * 2, m_maxRTO); 789 RTO = Math.Min(RTO * 2, m_maxRTO);
713 } 790 }
714 791
792
793 const int MIN_CALLBACK_MS = 10;
794
715 /// <summary> 795 /// <summary>
716 /// Does an early check to see if this queue empty callback is already 796 /// Does an early check to see if this queue empty callback is already
717 /// running, then asynchronously firing the event 797 /// running, then asynchronously firing the event
@@ -719,24 +799,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
719 /// <param name="categories">Throttle categories to fire the callback for</param> 799 /// <param name="categories">Throttle categories to fire the callback for</param>
720 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 800 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
721 { 801 {
722// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 802 if (!m_isQueueEmptyRunning)
723 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
724 { 803 {
725 m_isQueueEmptyRunning = true;
726
727 int start = Environment.TickCount & Int32.MaxValue; 804 int start = Environment.TickCount & Int32.MaxValue;
728 const int MIN_CALLBACK_MS = 30; 805
806 if (start < m_nextOnQueueEmpty)
807 return;
808
809 m_isQueueEmptyRunning = true;
729 810
730 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 811 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
731 if (m_nextOnQueueEmpty == 0) 812 if (m_nextOnQueueEmpty == 0)
732 m_nextOnQueueEmpty = 1; 813 m_nextOnQueueEmpty = 1;
733 814
734 // Use a value of 0 to signal that FireQueueEmpty is running 815 if (HasUpdates(categories))
735// m_nextOnQueueEmpty = 0;
736
737 m_categories = categories;
738
739 if (HasUpdates(m_categories))
740 { 816 {
741 if (!m_udpServer.OqrEngine.IsRunning) 817 if (!m_udpServer.OqrEngine.IsRunning)
742 { 818 {
@@ -756,7 +832,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
756 } 832 }
757 833
758 private bool m_isQueueEmptyRunning; 834 private bool m_isQueueEmptyRunning;
759 private ThrottleOutPacketTypeFlags m_categories = 0; 835
760 836
761 /// <summary> 837 /// <summary>
762 /// Fires the OnQueueEmpty callback and sets the minimum time that it 838 /// Fires the OnQueueEmpty callback and sets the minimum time that it
@@ -767,33 +843,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
767 /// signature</param> 843 /// signature</param>
768 public void FireQueueEmpty(object o) 844 public void FireQueueEmpty(object o)
769 { 845 {
770// m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name); 846 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
847 QueueEmpty callback = OnQueueEmpty;
771 848
772// int start = Environment.TickCount & Int32.MaxValue; 849 if (callback != null)
773// const int MIN_CALLBACK_MS = 30; 850 {
774 851 // if (m_udpServer.IsRunningOutbound)
775// if (m_udpServer.IsRunningOutbound) 852 // {
776// { 853 try { callback(categories); }
777 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 854 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
778 QueueEmpty callback = OnQueueEmpty; 855 // }
779 856 }
780 if (callback != null)
781 {
782// if (m_udpServer.IsRunningOutbound)
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 857
790// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 858 m_isQueueEmptyRunning = false;
791// if (m_nextOnQueueEmpty == 0) 859 }
792// m_nextOnQueueEmpty = 1;
793 860
794// } 861 internal void ForceThrottleSetting(int throttle, int setting)
862 {
863 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
864 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU);
865 }
795 866
796 m_isQueueEmptyRunning = false; 867 internal int GetThrottleSetting(int throttle)
868 {
869 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
870 return (int)m_throttleCategories[throttle].RequestedDripRate;
871 else
872 return 0;
797 } 873 }
798 874
799 /// <summary> 875 /// <summary>
@@ -839,4 +915,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
839 } 915 }
840 } 916 }
841 } 917 }
918
919 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
920 {
921 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
922
923 public override int Count
924 {
925 get
926 {
927 return base.Count + highQueue.Count;
928 }
929 }
930
931 public override bool Dequeue(out T item)
932 {
933 if (highQueue.Dequeue(out item))
934 return true;
935
936 return base.Dequeue(out item);
937 }
938
939 public void Enqueue(T item, bool highPriority)
940 {
941 if (highPriority)
942 highQueue.Enqueue(item);
943 else
944 Enqueue(item);
945 }
946 }
842} 947}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4528714..b5bdd46 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -284,7 +284,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
284 /// <summary>Handlers for incoming packets</summary> 284 /// <summary>Handlers for incoming packets</summary>
285 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 285 //PacketEventDictionary packetEvents = new PacketEventDictionary();
286 /// <summary>Incoming packets that are awaiting handling</summary> 286 /// <summary>Incoming packets that are awaiting handling</summary>
287 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 287 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
288
289 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
288 290
289 /// <summary>Bandwidth throttle for this UDP server</summary> 291 /// <summary>Bandwidth throttle for this UDP server</summary>
290 public TokenBucket Throttle { get; private set; } 292 public TokenBucket Throttle { get; private set; }
@@ -342,14 +344,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
342 /// <summary>Flag to signal when clients should send pings</summary> 344 /// <summary>Flag to signal when clients should send pings</summary>
343 protected bool m_sendPing; 345 protected bool m_sendPing;
344 346
347 private int m_animationSequenceNumber;
348
349 public int NextAnimationSequenceNumber
350 {
351 get
352 {
353 m_animationSequenceNumber++;
354 if (m_animationSequenceNumber > 2147482624)
355 m_animationSequenceNumber = 1;
356 return m_animationSequenceNumber;
357 }
358 }
359
360
361
362 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
363
345 /// <summary> 364 /// <summary>
346 /// Event used to signal when queued packets are available for sending. 365 /// Event used to signal when queued packets are available for sending.
347 /// </summary> 366 /// </summary>
348 /// <remarks> 367 /// <remarks>
349 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling. 368 /// 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. 369 /// Some data is sent immediately and not queued. That data would not trigger this event.
370 /// WRONG use. May be usefull in future revision
351 /// </remarks> 371 /// </remarks>
352 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); 372// private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
353 373
354 private Pool<IncomingPacket> m_incomingPacketPool; 374 private Pool<IncomingPacket> m_incomingPacketPool;
355 375
@@ -431,16 +451,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
431 451
432 // Measure the resolution of Environment.TickCount 452 // Measure the resolution of Environment.TickCount
433 TickCountResolution = 0f; 453 TickCountResolution = 0f;
434 for (int i = 0; i < 5; i++) 454 for (int i = 0; i < 10; i++)
435 { 455 {
436 int start = Environment.TickCount; 456 int start = Environment.TickCount;
437 int now = start; 457 int now = start;
438 while (now == start) 458 while (now == start)
439 now = Environment.TickCount; 459 now = Environment.TickCount;
440 TickCountResolution += (float)(now - start) * 0.2f; 460 TickCountResolution += (float)(now - start) * 0.1f;
441 } 461 }
442 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
443 TickCountResolution = (float)Math.Ceiling(TickCountResolution); 462 TickCountResolution = (float)Math.Ceiling(TickCountResolution);
463 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
444 464
445 #endregion Environment.TickCount Measurement 465 #endregion Environment.TickCount Measurement
446 466
@@ -448,6 +468,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
448 int sceneThrottleBps = 0; 468 int sceneThrottleBps = 0;
449 bool usePools = false; 469 bool usePools = false;
450 470
471
472
451 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 473 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
452 if (config != null) 474 if (config != null)
453 { 475 {
@@ -494,15 +516,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
494 } 516 }
495 #endregion BinaryStats 517 #endregion BinaryStats
496 518
497 // FIXME: Can't add info here because don't know scene yet. 519 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); 520 ThrottleRates = new ThrottleRates(configSource);
505 521
522 Random rnd = new Random(Util.EnvironmentTickCount());
523 m_animationSequenceNumber = rnd.Next(11474826);
524
506 if (usePools) 525 if (usePools)
507 EnablePools(); 526 EnablePools();
508 } 527 }
@@ -798,8 +817,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
798 if (UsePools) 817 if (UsePools)
799 EnablePoolStats(); 818 EnablePoolStats();
800 819
820
801 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); 821 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
802 commands.Register(); 822 commands.Register();
823
803 } 824 }
804 825
805 public bool HandlesRegion(Location x) 826 public bool HandlesRegion(Location x)
@@ -907,8 +928,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
907 928
908 PacketPool.Instance.ReturnPacket(packet); 929 PacketPool.Instance.ReturnPacket(packet);
909 930
910 if (packetQueued) 931 /// WRONG use. May be usefull in future revision
911 m_dataPresentEvent.Set(); 932// if (packetQueued)
933// m_dataPresentEvent.Set();
912 } 934 }
913 935
914 /// <summary> 936 /// <summary>
@@ -979,6 +1001,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
979 1001
980 #region Queue or Send 1002 #region Queue or Send
981 1003
1004 bool highPriority = false;
1005
1006 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
1007 {
1008 category = (ThrottleOutPacketType)((int)category & 127);
1009 highPriority = true;
1010 }
1011
982 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 1012 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
983 1013
984 // If we were not provided a method for handling unacked, use the UDPServer default method 1014 // If we were not provided a method for handling unacked, use the UDPServer default method
@@ -988,26 +1018,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
988 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will 1018 // 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 1019 // 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. 1020 // packet so that it isn't sent before a queued update packet.
991 bool forceQueue = (type == PacketType.KillObject);
992 1021
993// if (type == PacketType.ImprovedTerseObjectUpdate) 1022 bool requestQueue = type == PacketType.KillObject;
994// { 1023 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 { 1024 {
1003 SendPacketFinal(outgoingPacket); 1025 SendPacketFinal(outgoingPacket);
1004 return true; 1026 return true;
1005 } 1027 }
1006 else 1028
1007 { 1029 return false;
1008 return false;
1009 }
1010// }
1011 1030
1012 #endregion Queue or Send 1031 #endregion Queue or Send
1013 } 1032 }
@@ -1048,6 +1067,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1048 pc.PingID.OldestUnacked = 0; 1067 pc.PingID.OldestUnacked = 0;
1049 1068
1050 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); 1069 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1070 udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1051 } 1071 }
1052 1072
1053 public void CompletePing(LLUDPClient udpClient, byte pingID) 1073 public void CompletePing(LLUDPClient udpClient, byte pingID)
@@ -1145,7 +1165,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1145 int dataLength = buffer.DataLength; 1165 int dataLength = buffer.DataLength;
1146 1166
1147 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here 1167 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
1148 if (!isZerocoded) 1168 if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null)
1149 { 1169 {
1150 // Keep appending ACKs until there is no room left in the buffer or there are 1170 // Keep appending ACKs until there is no room left in the buffer or there are
1151 // no more ACKs to append 1171 // no more ACKs to append
@@ -1311,35 +1331,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1311 1331
1312 #region Packet to Client Mapping 1332 #region Packet to Client Mapping
1313 1333
1314 // UseCircuitCode handling 1334 // If there is already a client for this endpoint, don't process UseCircuitCode
1315 if (packet.Type == PacketType.UseCircuitCode) 1335 IClientAPI client = null;
1336 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1316 { 1337 {
1317 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1338 // UseCircuitCode handling
1318 // buffer. 1339 if (packet.Type == PacketType.UseCircuitCode)
1319 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1340 {
1341 // And if there is a UseCircuitCode pending, also drop it
1342 lock (m_pendingCache)
1343 {
1344 if (m_pendingCache.Contains(endPoint))
1345 return;
1346
1347 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1348 }
1320 1349
1321 Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode"); 1350 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1351 // buffer.
1352 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1322 1353
1323 return; 1354 Util.FireAndForget(HandleUseCircuitCode, array);
1355
1356 return;
1357 }
1324 } 1358 }
1325 else if (packet.Type == PacketType.CompleteAgentMovement) 1359
1360 // If this is a pending connection, enqueue, don't process yet
1361 lock (m_pendingCache)
1326 { 1362 {
1327 // Send ack straight away to let the viewer know that we got it. 1363 Queue<UDPPacketBuffer> queue;
1328 SendAckImmediate(endPoint, packet.Header.Sequence); 1364 if (m_pendingCache.TryGetValue(endPoint, out queue))
1365 {
1366 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1367 queue.Enqueue(buffer);
1368 return;
1369 }
1329 1370
1330 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1371/*
1331 // buffer. 1372 else if (packet.Type == PacketType.CompleteAgentMovement)
1332 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1373 {
1374 // Send ack straight away to let the viewer know that we got it.
1375 SendAckImmediate(endPoint, packet.Header.Sequence);
1333 1376
1334 Util.FireAndForget( 1377 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1335 HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion"); 1378 // buffer.
1379 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1336 1380
1337 return; 1381 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1382
1383 return;
1384 }
1385 */
1338 } 1386 }
1339 1387
1340 // Determine which agent this packet came from 1388 // Determine which agent this packet came from
1341 IClientAPI client; 1389 if (client == null || !(client is LLClientView))
1342 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1343 { 1390 {
1344 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1391 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1345 1392
@@ -1356,7 +1403,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1356 udpClient = ((LLClientView)client).UDPClient; 1403 udpClient = ((LLClientView)client).UDPClient;
1357 1404
1358 if (!udpClient.IsConnected) 1405 if (!udpClient.IsConnected)
1406 {
1407 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + Scene.RegionInfo.RegionName);
1359 return; 1408 return;
1409 }
1360 1410
1361 #endregion Packet to Client Mapping 1411 #endregion Packet to Client Mapping
1362 1412
@@ -1459,24 +1509,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1459 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1509 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1460 #endregion BinaryStats 1510 #endregion BinaryStats
1461 1511
1462 if (packet.Type == PacketType.AgentUpdate)
1463 {
1464 if (DiscardInboundAgentUpdates)
1465 return;
1466
1467 ((LLClientView)client).TotalAgentUpdates++;
1468 1512
1469 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; 1513//Ubit AgentUpdate mess removed from here
1470 1514
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 1515
1481 #region Ping Check Handling 1516 #region Ping Check Handling
1482 1517
@@ -1487,7 +1522,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1487 // We don't need to do anything else with ping checks 1522 // We don't need to do anything else with ping checks
1488 StartPingCheckPacket startPing = (StartPingCheckPacket)packet; 1523 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
1489 CompletePing(udpClient, startPing.PingID.PingID); 1524 CompletePing(udpClient, startPing.PingID.PingID);
1490 1525
1491 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000) 1526 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
1492 { 1527 {
1493 udpClient.SendPacketStats(); 1528 udpClient.SendPacketStats();
@@ -1497,7 +1532,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1497 } 1532 }
1498 else if (packet.Type == PacketType.CompletePingCheck) 1533 else if (packet.Type == PacketType.CompletePingCheck)
1499 { 1534 {
1500 // We don't currently track client ping times 1535 int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1536 int c = udpClient.m_pingMS;
1537 c = 800 * c + 200 * t;
1538 c /= 1000;
1539 udpClient.m_pingMS = c;
1501 return; 1540 return;
1502 } 1541 }
1503 1542
@@ -1517,7 +1556,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1517 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1556 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1518 } 1557 }
1519 1558
1520 packetInbox.Enqueue(incomingPacket); 1559// if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1560// incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1561 if (incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1562 packetInbox.EnqueueHigh(incomingPacket);
1563 else
1564 packetInbox.EnqueueLow(incomingPacket);
1565
1521 } 1566 }
1522 1567
1523 #region BinaryStats 1568 #region BinaryStats
@@ -1634,7 +1679,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1634 1679
1635 try 1680 try
1636 { 1681 {
1637 // DateTime startTime = DateTime.Now; 1682// DateTime startTime = DateTime.Now;
1638 object[] array = (object[])o; 1683 object[] array = (object[])o;
1639 endPoint = (IPEndPoint)array[0]; 1684 endPoint = (IPEndPoint)array[0];
1640 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1685 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
@@ -1646,6 +1691,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1646 AuthenticateResponse sessionInfo; 1691 AuthenticateResponse sessionInfo;
1647 if (IsClientAuthorized(uccp, out sessionInfo)) 1692 if (IsClientAuthorized(uccp, out sessionInfo))
1648 { 1693 {
1694 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1695
1649 // Begin the process of adding the client to the simulator 1696 // Begin the process of adding the client to the simulator
1650 client 1697 client
1651 = AddClient( 1698 = AddClient(
@@ -1654,20 +1701,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1654 uccp.CircuitCode.SessionID, 1701 uccp.CircuitCode.SessionID,
1655 endPoint, 1702 endPoint,
1656 sessionInfo); 1703 sessionInfo);
1657 1704
1705 // This will be true if the client is new, e.g. not
1706 // an existing child agent, and there is no circuit data
1707 if (client != null && aCircuit == null)
1708 {
1709 Scene.CloseAgent(client.AgentId, true);
1710 return;
1711 }
1712
1713 // Now we know we can handle more data
1714 Thread.Sleep(200);
1715
1716 // Obtain the pending queue and remove it from the cache
1717 Queue<UDPPacketBuffer> queue = null;
1718
1719 lock (m_pendingCache)
1720 {
1721 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1722 {
1723 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1724 return;
1725
1726 }
1727 m_pendingCache.Remove(endPoint);
1728 }
1729
1730 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1731
1732 // Reinject queued packets
1733 while (queue.Count > 0)
1734 {
1735 UDPPacketBuffer buf = queue.Dequeue();
1736 PacketReceived(buf);
1737 }
1738
1739 queue = null;
1740
1658 // Send ack straight away to let the viewer know that the connection is active. 1741 // 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 1742 // 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. 1743 // circuit code to the existing child agent. This is not particularly obvious.
1661 SendAckImmediate(endPoint, uccp.Header.Sequence); 1744 SendAckImmediate(endPoint, uccp.Header.Sequence);
1662 1745
1663 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1746 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1664 if (client != null) 1747 if (client != null)
1665 { 1748 {
1666 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1667 bool tp = (aCircuit.teleportFlags > 0); 1749 bool tp = (aCircuit.teleportFlags > 0);
1668 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from 1750 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1669 if (!tp && !client.SceneAgent.SentInitialDataToClient) 1751 if (!tp)
1670 client.SceneAgent.SendInitialDataToClient(); 1752 client.SceneAgent.SendInitialDataToMe();
1671 } 1753 }
1672 } 1754 }
1673 else 1755 else
@@ -1675,9 +1757,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1675 // Don't create clients for unauthorized requesters. 1757 // Don't create clients for unauthorized requesters.
1676 m_log.WarnFormat( 1758 m_log.WarnFormat(
1677 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1759 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1760
1678 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1761 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1679 } 1762
1680 1763 lock (m_pendingCache)
1764 m_pendingCache.Remove(endPoint);
1765 }
1766
1681 // m_log.DebugFormat( 1767 // m_log.DebugFormat(
1682 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", 1768 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1683 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); 1769 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
@@ -1694,8 +1780,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 e.StackTrace); 1780 e.StackTrace);
1695 } 1781 }
1696 } 1782 }
1697 1783/*
1698 private void HandleCompleteMovementIntoRegion(object o) 1784 private void HandleCompleteMovementIntoRegion(object o)
1699 { 1785 {
1700 IPEndPoint endPoint = null; 1786 IPEndPoint endPoint = null;
1701 IClientAPI client = null; 1787 IClientAPI client = null;
@@ -1804,6 +1890,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1804 e.StackTrace); 1890 e.StackTrace);
1805 } 1891 }
1806 } 1892 }
1893*/
1807 1894
1808 /// <summary> 1895 /// <summary>
1809 /// Send an ack immediately to the given endpoint. 1896 /// Send an ack immediately to the given endpoint.
@@ -1861,6 +1948,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1861 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 1948 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
1862 { 1949 {
1863 IClientAPI client = null; 1950 IClientAPI client = null;
1951 bool createNew = false;
1864 1952
1865 // We currently synchronize this code across the whole scene to avoid issues such as 1953 // 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 1954 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
@@ -1869,7 +1957,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1869 { 1957 {
1870 if (!Scene.TryGetClient(agentID, out client)) 1958 if (!Scene.TryGetClient(agentID, out client))
1871 { 1959 {
1960 createNew = true;
1961 }
1962 else
1963 {
1964 if (client.SceneAgent == null)
1965 {
1966 Scene.CloseAgent(agentID, true);
1967 createNew = true;
1968 }
1969 }
1970
1971 if (createNew)
1972 {
1872 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1973 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1974
1873 1975
1874 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1976 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1875 client.OnLogout += LogoutHandler; 1977 client.OnLogout += LogoutHandler;
@@ -1899,15 +2001,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1899 { 2001 {
1900 ClientLogoutsDueToNoReceives++; 2002 ClientLogoutsDueToNoReceives++;
1901 2003
1902 m_log.WarnFormat( 2004 if (client.SceneAgent != null)
1903 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", 2005 {
1904 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name); 2006 m_log.WarnFormat(
2007 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
2008 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
1905 2009
1906 if (!client.SceneAgent.IsChildAgent) 2010 if (!client.SceneAgent.IsChildAgent)
1907 client.Kick("Simulator logged you out due to connection timeout."); 2011 client.Kick("Simulator logged you out due to connection timeout.");
2012 }
1908 } 2013 }
1909 2014
1910 Scene.CloseAgent(client.AgentId, true); 2015 if (!Scene.CloseAgent(client.AgentId, true))
2016 client.Close(true,true);
1911 } 2017 }
1912 2018
1913 private void IncomingPacketHandler() 2019 private void IncomingPacketHandler()
@@ -1920,6 +2026,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1920 2026
1921 while (IsRunningInbound) 2027 while (IsRunningInbound)
1922 { 2028 {
2029 Scene.ThreadAlive(1);
1923 try 2030 try
1924 { 2031 {
1925 IncomingPacket incomingPacket = null; 2032 IncomingPacket incomingPacket = null;
@@ -1942,7 +2049,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1942 m_incomingPacketPool.ReturnObject(incomingPacket); 2049 m_incomingPacketPool.ReturnObject(incomingPacket);
1943 } 2050 }
1944 } 2051 }
1945 catch (Exception ex) 2052 catch(Exception ex)
1946 { 2053 {
1947 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); 2054 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
1948 } 2055 }
@@ -1971,6 +2078,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1971 2078
1972 while (base.IsRunningOutbound) 2079 while (base.IsRunningOutbound)
1973 { 2080 {
2081 Scene.ThreadAlive(2);
1974 try 2082 try
1975 { 2083 {
1976 m_packetSent = false; 2084 m_packetSent = false;
@@ -2029,13 +2137,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2029 2137
2030 // If nothing was sent, sleep for the minimum amount of time before a 2138 // If nothing was sent, sleep for the minimum amount of time before a
2031 // token bucket could get more tokens 2139 // token bucket could get more tokens
2032 //if (!m_packetSent) 2140
2033 // Thread.Sleep((int)TickCountResolution);
2034 //
2035 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
2036 // modern mono it reduces CPU base load since there is no more continuous polling.
2037 if (!m_packetSent) 2141 if (!m_packetSent)
2038 m_dataPresentEvent.WaitOne(100); 2142 Thread.Sleep((int)TickCountResolution);
2143
2144 // .... wrong core code removed
2145
2039 2146
2040 Watchdog.UpdateThread(); 2147 Watchdog.UpdateThread();
2041 } 2148 }
@@ -2206,8 +2313,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2206 Packet packet = incomingPacket.Packet; 2313 Packet packet = incomingPacket.Packet;
2207 LLClientView client = incomingPacket.Client; 2314 LLClientView client = incomingPacket.Client;
2208 2315
2209 if (client.IsActive) 2316// if (client.IsActive)
2210 { 2317// {
2211 m_currentIncomingClient = client; 2318 m_currentIncomingClient = client;
2212 2319
2213 try 2320 try
@@ -2234,13 +2341,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2234 { 2341 {
2235 m_currentIncomingClient = null; 2342 m_currentIncomingClient = null;
2236 } 2343 }
2237 } 2344// }
2238 else 2345// else
2239 { 2346// {
2240 m_log.DebugFormat( 2347// m_log.DebugFormat(
2241 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 2348// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
2242 packet.Type, client.Name, Scene.RegionInfo.RegionName); 2349// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
2243 } 2350// }
2244 2351
2245 IncomingPacketsProcessed++; 2352 IncomingPacketsProcessed++;
2246 } 2353 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
index ac6c0b4..4ff52eb 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
@@ -224,7 +224,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
224 ConsoleDisplayList cdl = new ConsoleDisplayList(); 224 ConsoleDisplayList cdl = new ConsoleDisplayList();
225 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled); 225 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled);
226 226
227 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; 227 long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate;
228 cdl.AddRow( 228 cdl.AddRow(
229 "Max scene throttle", 229 "Max scene throttle",
230 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); 230 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
@@ -505,7 +505,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
505 m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name); 505 m_console.OutputFormat("Debug settings for {0}", m_udpServer.Scene.Name);
506 ConsoleDisplayList cdl = new ConsoleDisplayList(); 506 ConsoleDisplayList cdl = new ConsoleDisplayList();
507 507
508 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate; 508 long maxSceneDripRate = (long)m_udpServer.Throttle.MaxDripRate;
509 cdl.AddRow( 509 cdl.AddRow(
510 "max-scene-throttle", 510 "max-scene-throttle",
511 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); 511 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f62dc15..7171974 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -206,16 +206,16 @@ namespace OpenMetaverse
206 const int SIO_UDP_CONNRESET = -1744830452; 206 const int SIO_UDP_CONNRESET = -1744830452;
207 207
208 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 208 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 209
214 m_udpSocket = new Socket( 210 m_udpSocket = new Socket(
215 AddressFamily.InterNetwork, 211 AddressFamily.InterNetwork,
216 SocketType.Dgram, 212 SocketType.Dgram,
217 ProtocolType.Udp); 213 ProtocolType.Udp);
218 214
215 // OpenSim may need this but in AVN, this messes up automated
216 // sim restarts badly
217 //m_udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
218
219 try 219 try
220 { 220 {
221 if (m_udpSocket.Ttl < 128) 221 if (m_udpSocket.Ttl < 128)
@@ -501,4 +501,4 @@ namespace OpenMetaverse
501 catch (ObjectDisposedException) { } 501 catch (ObjectDisposedException) { }
502 } 502 }
503 } 503 }
504} \ No newline at end of file 504}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
index 3c82a78..5e41dbd 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(
@@ -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..076551f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -69,6 +69,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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,7 +91,14 @@ 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 // 3000000 bps default max
96 ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 375000);
97 if (ClientMaxRate > 1000000)
98 ClientMaxRate = 1000000; // no more than 8Mbps
99
100 BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10);
101 BrustTime *= 1e-3f;
92 102
93 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); 103 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
94 MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000); 104 MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index 4616203..14099fe 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -43,25 +43,24 @@ 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
48 public int DebugLevel { get; set; }
49 47
50 /// <summary> 48// private Int32 m_identifier;
51 /// Number of ticks (ms) per quantum, drip rate and max burst 49
52 /// are defined over this interval. 50 protected const float m_timeScale = 1e-3f;
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 = 1400;
65 64
66 /// <summary>Time of the last drip, in system ticks</summary> 65 /// <summary>Time of the last drip, in system ticks</summary>
67 protected Int32 m_lastDrip; 66 protected Int32 m_lastDrip;
@@ -70,40 +69,57 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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//not in use
100 public float MaxDripRate { get; set; }
101
102 public float RequestedBurst
94 { 103 {
95 get { return m_burstRate; } 104 get { return m_burst; }
96 set { m_burstRate = (value < 0 ? 0 : value); } 105 set {
106 float rate = (value < 0 ? 0 : value);
107 if (rate < m_minimumDripRate)
108 rate = m_minimumDripRate;
109 else if (rate > m_minimumDripRate * m_quantumsPerBurst)
110 rate = m_minimumDripRate * m_quantumsPerBurst;
111
112 m_burst = rate;
113 }
97 } 114 }
98 115
99 public Int64 BurstRate 116 public float Burst
100 { 117 {
101 get { 118 get {
102 double rate = RequestedBurstRate * BurstRateModifier(); 119 float rate = RequestedBurst * BurstModifier();
103 if (rate < m_minimumDripRate * m_quantumsPerBurst) 120 if (rate < m_minimumDripRate)
104 rate = m_minimumDripRate * m_quantumsPerBurst; 121 rate = m_minimumDripRate;
105 122 return (float)rate;
106 return (Int64) rate;
107 } 123 }
108 } 124 }
109 125
@@ -115,78 +131,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP
115 /// Can never be above MaxDripRate. 131 /// Can never be above MaxDripRate.
116 /// Tokens are added to the bucket at any time 132 /// Tokens are added to the bucket at any time
117 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 133 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
118 /// the system tick interval (typically around 15-22ms) 134 /// 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 135 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 136
136 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 137 public virtual float RequestedDripRate
138 {
139 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
140 set {
141 m_dripRate = (value < 0 ? 0 : value);
142 m_totalDripRequest = m_dripRate;
137 143
138 if (Parent != null) 144 if (m_parent != null)
139 Parent.RegisterRequest(this, m_dripRate); 145 m_parent.RegisterRequest(this,m_dripRate);
140 } 146 }
141 } 147 }
142 148
143 /// <summary> 149 public virtual 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 { 150 {
153 get 151 get {
154 { 152 float rate = Math.Min(RequestedDripRate,TotalDripRequest);
155 double rate; 153 if (m_parent == null)
156 154 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 155
156 rate *= m_parent.DripRateModifier();
171 if (rate < m_minimumDripRate) 157 if (rate < m_minimumDripRate)
172 rate = m_minimumDripRate; 158 rate = m_minimumDripRate;
173 else if (MaxDripRate > 0 && rate > MaxDripRate)
174 rate = MaxDripRate;
175 159
176 return (Int64)rate; 160 return (float)rate;
177 } 161 }
178 } 162 }
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 163
186 /// <summary> 164 /// <summary>
187 /// The current total of the requested maximum burst rates of children buckets. 165 /// The current total of the requested maximum burst rates of children buckets.
188 /// </summary> 166 /// </summary>
189 public Int64 TotalDripRequest { get; protected set; } 167 protected float m_totalDripRequest;
168 public float TotalDripRequest
169 {
170 get { return m_totalDripRequest; }
171 set { m_totalDripRequest = value; }
172 }
173
174#endregion Properties
175
176#region Constructor
177
190 178
191 /// <summary> 179 /// <summary>
192 /// Default constructor 180 /// Default constructor
@@ -194,20 +182,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
194 /// <param name="identifier">Identifier for this token bucket</param> 182 /// <param name="identifier">Identifier for this token bucket</param>
195 /// <param name="parent">Parent bucket if this is a child bucket, or 183 /// <param name="parent">Parent bucket if this is a child bucket, or
196 /// null if this is a root bucket</param> 184 /// null if this is a root bucket</param>
197 /// <param name="requestedDripRate"> 185 /// <param name="maxBurst">Maximum size of the bucket in bytes, or
198 /// Requested rate that the bucket fills, in bytes per 186 /// zero if this bucket has no maximum capacity</param>
199 /// second. If zero, the bucket always remains full. 187 /// <param name="dripRate">Rate that the bucket fills, in bytes per
200 /// </param> 188 /// second. If zero, the bucket always remains full</param>
201 public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate) 189 public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst)
202 { 190 {
203 Identifier = identifier; 191 m_counter++;
204 192
205 Parent = parent; 193 Parent = parent;
206 RequestedDripRate = requestedDripRate; 194 RequestedDripRate = dripRate;
207 MaxDripRate = maxDripRate; 195 RequestedBurst = MaxBurst;
208 m_lastDrip = Util.EnvironmentTickCount(); 196 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
197 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
198 m_lastDrip = Util.EnvironmentTickCount() + 100000;
209 } 199 }
210 200
201#endregion Constructor
202
211 /// <summary> 203 /// <summary>
212 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning 204 /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning
213 /// no modification if the requested bandwidth is less than the 205 /// no modification if the requested bandwidth is less than the
@@ -215,22 +207,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
215 /// hierarchy. However, if any of the parents is over-booked, then 207 /// hierarchy. However, if any of the parents is over-booked, then
216 /// the modifier will be less than 1. 208 /// the modifier will be less than 1.
217 /// </summary> 209 /// </summary>
218 protected double DripRateModifier() 210 protected float DripRateModifier()
219 { 211 {
220 Int64 driprate = DripRate; 212 float driprate = DripRate;
221 double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 213 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 } 214 }
230 215
231 /// <summary> 216 /// <summary>
232 /// </summary> 217 /// </summary>
233 protected double BurstRateModifier() 218 protected float BurstModifier()
234 { 219 {
235 // for now... burst rate is always m_quantumsPerBurst (constant) 220 // for now... burst rate is always m_quantumsPerBurst (constant)
236 // larger than drip rate so the ratio of burst requests is the 221 // larger than drip rate so the ratio of burst requests is the
@@ -242,29 +227,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
242 /// Register drip rate requested by a child of this throttle. Pass the 227 /// Register drip rate requested by a child of this throttle. Pass the
243 /// changes up the hierarchy. 228 /// changes up the hierarchy.
244 /// </summary> 229 /// </summary>
245 public void RegisterRequest(TokenBucket child, Int64 request) 230 public void RegisterRequest(TokenBucket child, float request)
246 { 231 {
247 lock (m_children) 232 lock (m_children)
248 { 233 {
249 m_children[child] = request; 234 m_children[child] = request;
250 235
251 TotalDripRequest = 0; 236 m_totalDripRequest = 0;
252 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 237 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
253 TotalDripRequest += cref.Value; 238 m_totalDripRequest += cref.Value;
254 } 239 }
255 240
256 // Pass the new values up to the parent 241 // Pass the new values up to the parent
257 if (Parent != null) 242 if (m_parent != null)
258 { 243 m_parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest));
259 Int64 effectiveDripRate;
260
261 if (RequestedDripRate > 0)
262 effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest);
263 else
264 effectiveDripRate = TotalDripRequest;
265
266 Parent.RegisterRequest(this, effectiveDripRate);
267 }
268 } 244 }
269 245
270 /// <summary> 246 /// <summary>
@@ -277,9 +253,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
277 { 253 {
278 m_children.Remove(child); 254 m_children.Remove(child);
279 255
280 TotalDripRequest = 0; 256 m_totalDripRequest = 0;
281 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 257 foreach (KeyValuePair<TokenBucket, float> cref in m_children)
282 TotalDripRequest += cref.Value; 258 m_totalDripRequest += cref.Value;
283 } 259 }
284 260
285 // Pass the new values up to the parent 261 // Pass the new values up to the parent
@@ -293,7 +269,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
293 /// <param name="amount">Number of tokens to remove from the bucket</param> 269 /// <param name="amount">Number of tokens to remove from the bucket</param>
294 /// <returns>True if the requested number of tokens were removed from 270 /// <returns>True if the requested number of tokens were removed from
295 /// the bucket, otherwise false</returns> 271 /// the bucket, otherwise false</returns>
296 public bool RemoveTokens(Int64 amount) 272 public bool RemoveTokens(int amount)
297 { 273 {
298 // Deposit tokens for this interval 274 // Deposit tokens for this interval
299 Drip(); 275 Drip();
@@ -310,19 +286,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
310 return false; 286 return false;
311 } 287 }
312 288
313 /// <summary> 289 public int GetCatBytesCanSend(int timeMS)
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 { 290 {
319 m_tokenCount += count; 291// return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3);
320 292 return (int)(timeMS * m_dripRate * 1e-3);
321 // Deposit the overflow in the parent bucket, this is how we share
322 // unused bandwidth
323 Int64 burstrate = BurstRate;
324 if (m_tokenCount > burstrate)
325 m_tokenCount = burstrate;
326 } 293 }
327 294
328 /// <summary> 295 /// <summary>
@@ -337,21 +304,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
337 // with no drip rate... 304 // with no drip rate...
338 if (DripRate == 0) 305 if (DripRate == 0)
339 { 306 {
340 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier); 307 m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", m_counter);
341 return; 308 return;
342 } 309 }
343 310
344 // Determine the interval over which we are adding tokens, never add 311 Int32 now = Util.EnvironmentTickCount();
345 // more than a single quantum of tokens 312 Int32 deltaMS = now - m_lastDrip;
346 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); 313 m_lastDrip = now;
347 m_lastDrip = Util.EnvironmentTickCount();
348 314
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) 315 if (deltaMS <= 0)
352 return; 316 return;
353 317
354 Deposit(deltaMS * DripRate / m_ticksPerQuantum); 318 m_tokenCount += deltaMS * DripRate * m_timeScale;
319
320 float burst = Burst;
321 if (m_tokenCount > burst)
322 m_tokenCount = burst;
355 } 323 }
356 } 324 }
357 325
@@ -362,103 +330,79 @@ namespace OpenSim.Region.ClientStack.LindenUDP
362 public bool AdaptiveEnabled { get; set; } 330 public bool AdaptiveEnabled { get; set; }
363 331
364 /// <summary> 332 /// <summary>
365 /// Target drip rate for this bucket. 333 /// The minimum rate for flow control. Minimum drip rate is one
334 /// packet per second.
366 /// </summary> 335 /// </summary>
367 /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks> 336
368 public Int64 TargetDripRate 337 protected const float m_minimumFlow = 50000;
369 { 338
370 get { return m_targetDripRate; } 339 // <summary>
371 set 340 // The maximum rate for flow control. Drip rate can never be
341 // greater than this.
342 // </summary>
343
344 protected float m_maxDripRate = 0;
345 public float MaxDripRate
346 {
347 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
348 set
372 { 349 {
373 m_targetDripRate = Math.Max(value, m_minimumFlow); 350 m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow));
374 } 351 }
375 } 352 }
376 protected Int64 m_targetDripRate; 353
354 private bool m_enabled = false;
377 355
378 // <summary> 356 // <summary>
379 // Adjust drip rate in response to network conditions. 357 // Adjust drip rate in response to network conditions.
380 // </summary> 358 // </summary>
381 public virtual Int64 AdjustedDripRate 359 public virtual float AdjustedDripRate
382 { 360 {
383 get { return m_dripRate; } 361 get { return m_dripRate; }
384 set 362 set
385 { 363 {
386 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate); 364 m_dripRate = OpenSim.Framework.Util.Clamp<float>(value, m_minimumFlow, MaxDripRate);
387 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
388 365
389 if (Parent != null) 366 if (m_parent != null)
390 Parent.RegisterRequest(this, m_dripRate); 367 m_parent.RegisterRequest(this, m_dripRate);
391 } 368 }
392 } 369 }
393 370
394 /// <summary> 371
395 /// The minimum rate for adaptive flow control. 372 // <summary>
396 /// </summary> 373 //
397 protected Int64 m_minimumFlow = 32000; 374 // </summary>
398 375 public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled)
399 /// <summary> 376 : base(parent, maxDripRate, maxBurst)
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 { 377 {
410 AdaptiveEnabled = enabled; 378 m_enabled = enabled;
411 379
412 if (AdaptiveEnabled) 380 MaxDripRate = maxDripRate;
413 { 381
414// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); 382 if (enabled)
415 m_minimumFlow = minDripRate; 383 AdjustedDripRate = m_maxDripRate * .5f;
416 TargetDripRate = m_minimumFlow; 384 else
417 AdjustedDripRate = m_minimumFlow; 385 AdjustedDripRate = m_maxDripRate;
418 }
419 } 386 }
420 387
421 /// <summary> 388 /// <summary>
422 /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down. 389 /// 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> 390 /// <param name="packets">Number of packets that expired without successful delivery</param>
424 /// </summary> 391 /// </summary>
425 public void ExpirePackets(Int32 packets) 392 public void ExpirePackets(Int32 count)
426 { 393 {
427 if (AdaptiveEnabled) 394 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
428 { 395 if (m_enabled)
429 if (DebugLevel > 0) 396 AdjustedDripRate = (Int64)(AdjustedDripRate / Math.Pow(2, count));
430 m_log.WarnFormat(
431 "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}",
432 AdjustedDripRate, packets, Identifier);
433
434 // AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets));
435
436 // Compute the fallback solely on the rate allocated beyond the minimum, this
437 // should smooth out the fallback to the minimum rate
438 AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets));
439 }
440 } 397 }
441 398
442 /// <summary> 399 // <summary>
443 /// Reliable packets acked by the client adjust the drip rate up. 400 //
444 /// <param name="packets">Number of packets successfully acknowledged</param> 401 // </summary>
445 /// </summary> 402 public void AcknowledgePackets(Int32 count)
446 public void AcknowledgePackets(Int32 packets)
447 {
448 if (AdaptiveEnabled)
449 AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU;
450 }
451
452 /// <summary>
453 /// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted
454 /// throttles back to the minimum levels
455 /// <param>minDripRate--the new minimum flow</param>
456 /// </summary>
457 public void ResetMinimumAdaptiveFlow(Int64 minDripRate)
458 { 403 {
459 m_minimumFlow = minDripRate; 404 if (m_enabled)
460 TargetDripRate = m_minimumFlow; 405 AdjustedDripRate = AdjustedDripRate + count;
461 AdjustedDripRate = m_minimumFlow;
462 } 406 }
463 } 407 }
464} \ No newline at end of file 408}