aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs910
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs11
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs448
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs422
-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/UploadBakedTextureModule.cs196
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs267
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1534
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs121
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
16 files changed, 3825 insertions, 1209 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 8752404..8241e07 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;
@@ -54,14 +55,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
54namespace OpenSim.Region.ClientStack.Linden 55namespace OpenSim.Region.ClientStack.Linden
55{ 56{
56 public delegate void UpLoadedAsset( 57 public delegate void UpLoadedAsset(
57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 58 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
58 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);
59 62
60 public delegate UUID UpdateItem(UUID itemID, byte[] data); 63 public delegate UUID UpdateItem(UUID itemID, byte[] data);
61 64
62 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);
63 66
64 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 67 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
65 68
66 public delegate void NewAsset(AssetBase asset); 69 public delegate void NewAsset(AssetBase asset);
67 70
@@ -87,6 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden
87 90
88 private Scene m_Scene; 91 private Scene m_Scene;
89 private Caps m_HostCapsObj; 92 private Caps m_HostCapsObj;
93 private ModelCost m_ModelCost;
90 94
91 private static readonly string m_requestPath = "0000/"; 95 private static readonly string m_requestPath = "0000/";
92 // private static readonly string m_mapLayerPath = "0001/"; 96 // private static readonly string m_mapLayerPath = "0001/";
@@ -98,7 +102,8 @@ namespace OpenSim.Region.ClientStack.Linden
98 private static readonly string m_copyFromNotecardPath = "0007/"; 102 private static readonly string m_copyFromNotecardPath = "0007/";
99 // 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.
100 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 104 private static readonly string m_getObjectPhysicsDataPath = "0101/";
101 /* 0102 - 0103 RESERVED */ 105 private static readonly string m_getObjectCostPath = "0102/";
106 private static readonly string m_ResourceCostSelectedPath = "0103/";
102 private static readonly string m_UpdateAgentInformationPath = "0500/"; 107 private static readonly string m_UpdateAgentInformationPath = "0500/";
103 108
104 // These are callbacks which will be setup by the scene so that we can update scene data when we 109 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -114,12 +119,50 @@ namespace OpenSim.Region.ClientStack.Linden
114 private IAssetService m_assetService; 119 private IAssetService m_assetService;
115 private bool m_dumpAssetsToFile = false; 120 private bool m_dumpAssetsToFile = false;
116 private string m_regionName; 121 private string m_regionName;
122
117 private int m_levelUpload = 0; 123 private int m_levelUpload = 0;
118 124
125 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
126 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
127
128 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
129 // may not be visible till relog
130
131 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
132 private UUID m_testAssetsCreatorID = UUID.Zero;
133
134 private float m_PrimScaleMin = 0.001f;
135
136 private enum FileAgentInventoryState : int
137 {
138 idle = 0,
139 processRequest = 1,
140 waitUpload = 2,
141 processUpload = 3
142 }
143 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
144
119 public BunchOfCaps(Scene scene, Caps caps) 145 public BunchOfCaps(Scene scene, Caps caps)
120 { 146 {
121 m_Scene = scene; 147 m_Scene = scene;
122 m_HostCapsObj = caps; 148 m_HostCapsObj = caps;
149
150 // create a model upload cost provider
151 m_ModelCost = new ModelCost();
152 // tell it about scene object limits
153 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
154 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
155
156// m_ModelCost.ObjectLinkedPartsMax = ??
157// m_ModelCost.PrimScaleMin = ??
158
159 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
160 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
161 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
162 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
163 float modelPrimCreationCost = m_ModelCost.primCreationCost;
164 float modelMeshByteCost = m_ModelCost.bytecost;
165
123 IConfigSource config = m_Scene.Config; 166 IConfigSource config = m_Scene.Config;
124 if (config != null) 167 if (config != null)
125 { 168 {
@@ -134,6 +177,37 @@ namespace OpenSim.Region.ClientStack.Linden
134 { 177 {
135 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 178 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
136 } 179 }
180 // economy for model upload
181 IConfig EconomyConfig = config.Configs["Economy"];
182 if (EconomyConfig != null)
183 {
184 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
185 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
186 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
187 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
188 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
189 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
190
191 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
192
193 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
194 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
195 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
196 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
197 if (testcreator != "")
198 {
199 UUID id;
200 UUID.TryParse(testcreator, out id);
201 if (id != null)
202 m_testAssetsCreatorID = id;
203 }
204
205 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
206 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
207 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
208 m_ModelCost.primCreationCost = modelPrimCreationCost;
209 m_ModelCost.bytecost = modelMeshByteCost;
210 }
137 } 211 }
138 212
139 m_assetService = m_Scene.AssetService; 213 m_assetService = m_Scene.AssetService;
@@ -145,6 +219,8 @@ namespace OpenSim.Region.ClientStack.Linden
145 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 219 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
146 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 220 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
147 GetClient = m_Scene.SceneGraph.GetControllingClient; 221 GetClient = m_Scene.SceneGraph.GetControllingClient;
222
223 m_FileAgentInventoryState = FileAgentInventoryState.idle;
148 } 224 }
149 225
150 /// <summary> 226 /// <summary>
@@ -190,7 +266,6 @@ namespace OpenSim.Region.ClientStack.Linden
190 { 266 {
191 try 267 try
192 { 268 {
193 // I don't think this one works...
194 m_HostCapsObj.RegisterHandler( 269 m_HostCapsObj.RegisterHandler(
195 "NewFileAgentInventory", 270 "NewFileAgentInventory",
196 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 271 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -209,6 +284,10 @@ namespace OpenSim.Region.ClientStack.Linden
209 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 284 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
210 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 285 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
211 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 286 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
287 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
288 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
289 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
290 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
212 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 291 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
213 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 292 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
214 293
@@ -264,6 +343,9 @@ namespace OpenSim.Region.ClientStack.Linden
264 m_log.DebugFormat( 343 m_log.DebugFormat(
265 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 344 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
266 345
346 if (!m_HostCapsObj.WaitForActivation())
347 return string.Empty;
348
267 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 349 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
268 { 350 {
269 m_log.WarnFormat( 351 m_log.WarnFormat(
@@ -273,11 +355,22 @@ namespace OpenSim.Region.ClientStack.Linden
273 return string.Empty; 355 return string.Empty;
274 } 356 }
275 357
276 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true); 358 OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request);
359 List<string> validCaps = new List<string>();
360
361 foreach (OSD c in capsRequested)
362 validCaps.Add(c.AsString());
363
364 Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps);
277 365
278 // Add the external too 366 // Add the external too
279 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers) 367 foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
368 {
369 if (!validCaps.Contains(kvp.Key))
370 continue;
371
280 caps[kvp.Key] = kvp.Value; 372 caps[kvp.Key] = kvp.Value;
373 }
281 374
282 string result = LLSDHelpers.SerialiseLLSDReply(caps); 375 string result = LLSDHelpers.SerialiseLLSDReply(caps);
283 376
@@ -393,62 +486,176 @@ namespace OpenSim.Region.ClientStack.Linden
393 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 486 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
394 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 487 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
395 488
489 // start by getting the client
490 IClientAPI client = null;
491 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
492
493 // check current state so we only have one service at a time
494 lock (m_ModelCost)
495 {
496 switch (m_FileAgentInventoryState)
497 {
498 case FileAgentInventoryState.processRequest:
499 case FileAgentInventoryState.processUpload:
500 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
501 resperror.message = "Uploader busy processing previus request";
502 resperror.identifier = UUID.Zero;
503
504 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
505 errorResponse.uploader = "";
506 errorResponse.state = "error";
507 errorResponse.error = resperror;
508 return errorResponse;
509 break;
510 case FileAgentInventoryState.waitUpload:
511 // todo stop current uploader server
512 break;
513 case FileAgentInventoryState.idle:
514 default:
515 break;
516 }
517
518 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
519 }
520
521 int cost = 0;
522 int nreqtextures = 0;
523 int nreqmeshs= 0;
524 int nreqinstances = 0;
525 bool IsAtestUpload = false;
526
527 string assetName = llsdRequest.name;
528
529 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
530
396 if (llsdRequest.asset_type == "texture" || 531 if (llsdRequest.asset_type == "texture" ||
397 llsdRequest.asset_type == "animation" || 532 llsdRequest.asset_type == "animation" ||
533 llsdRequest.asset_type == "mesh" ||
398 llsdRequest.asset_type == "sound") 534 llsdRequest.asset_type == "sound")
399 { 535 {
400 ScenePresence avatar = null; 536 ScenePresence avatar = null;
401 IClientAPI client = null;
402 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 537 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
403 538
404 // check user level 539 // check user level
405 if (avatar != null) 540 if (avatar != null)
406 { 541 {
407 client = avatar.ControllingClient;
408
409 if (avatar.UserLevel < m_levelUpload) 542 if (avatar.UserLevel < m_levelUpload)
410 { 543 {
411 if (client != null) 544 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
412 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 545 resperror.message = "Insufficient permissions to upload";
546 resperror.identifier = UUID.Zero;
413 547
414 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 548 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
415 errorResponse.uploader = ""; 549 errorResponse.uploader = "";
416 errorResponse.state = "error"; 550 errorResponse.state = "error";
551 errorResponse.error = resperror;
552 lock (m_ModelCost)
553 m_FileAgentInventoryState = FileAgentInventoryState.idle;
417 return errorResponse; 554 return errorResponse;
418 } 555 }
419 } 556 }
420 557
421 // check funds 558 // check test upload and funds
422 if (client != null) 559 if (client != null)
423 { 560 {
424 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 561 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
425 562
563 int baseCost = 0;
426 if (mm != null) 564 if (mm != null)
565 baseCost = mm.UploadCharge;
566
567 string warning = String.Empty;
568
569 if (llsdRequest.asset_type == "mesh")
427 { 570 {
428 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 571 string error;
572 int modelcost;
573
574 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
575 meshcostdata, out error, ref warning))
429 { 576 {
430 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 577 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
578 resperror.message = error;
579 resperror.identifier = UUID.Zero;
431 580
432 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 581 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
433 errorResponse.uploader = ""; 582 errorResponse.uploader = "";
434 errorResponse.state = "error"; 583 errorResponse.state = "error";
584 errorResponse.error = resperror;
585
586 lock (m_ModelCost)
587 m_FileAgentInventoryState = FileAgentInventoryState.idle;
435 return errorResponse; 588 return errorResponse;
436 } 589 }
590 cost = modelcost;
591 }
592 else
593 {
594 cost = baseCost;
595 }
596
597 if (cost > 0 && mm != null)
598 {
599 // check for test upload
600
601 if (m_ForceFreeTestUpload) // all are test
602 {
603 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
604 assetName = "TEST-" + assetName;
605
606 IsAtestUpload = true;
607 }
608
609 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
610 {
611
612 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
613 }
614
615
616 if(IsAtestUpload) // let user know, still showing cost estimation
617 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";
618
619 // check funds
620 else
621 {
622 if (!mm.UploadCovered(client.AgentId, (int)cost))
623 {
624 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
625 resperror.message = "Insuficient funds";
626 resperror.identifier = UUID.Zero;
627
628 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
629 errorResponse.uploader = "";
630 errorResponse.state = "error";
631 errorResponse.error = resperror;
632 lock (m_ModelCost)
633 m_FileAgentInventoryState = FileAgentInventoryState.idle;
634 return errorResponse;
635 }
636 }
437 } 637 }
638
639 if (client != null && warning != String.Empty)
640 client.SendAgentAlertMessage(warning, true);
438 } 641 }
439 } 642 }
440 643
441 string assetName = llsdRequest.name;
442 string assetDes = llsdRequest.description; 644 string assetDes = llsdRequest.description;
443 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 645 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
444 UUID newAsset = UUID.Random(); 646 UUID newAsset = UUID.Random();
445 UUID newInvItem = UUID.Random(); 647 UUID newInvItem = UUID.Random();
446 UUID parentFolder = llsdRequest.folder_id; 648 UUID parentFolder = llsdRequest.folder_id;
447 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 649 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
650 UUID texturesFolder = UUID.Zero;
651
652 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
653 texturesFolder = llsdRequest.texture_folder_id;
448 654
449 AssetUploader uploader = 655 AssetUploader uploader =
450 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 656 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
451 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 657 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
658 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
452 659
453 m_HostCapsObj.HttpListener.AddStreamHandler( 660 m_HostCapsObj.HttpListener.AddStreamHandler(
454 new BinaryStreamHandler( 661 new BinaryStreamHandler(
@@ -466,10 +673,22 @@ namespace OpenSim.Region.ClientStack.Linden
466 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 673 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
467 uploaderPath; 674 uploaderPath;
468 675
676
469 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 677 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
470 uploadResponse.uploader = uploaderURL; 678 uploadResponse.uploader = uploaderURL;
471 uploadResponse.state = "upload"; 679 uploadResponse.state = "upload";
680 uploadResponse.upload_price = (int)cost;
681
682 if (llsdRequest.asset_type == "mesh")
683 {
684 uploadResponse.data = meshcostdata;
685 }
686
472 uploader.OnUpLoad += UploadCompleteHandler; 687 uploader.OnUpLoad += UploadCompleteHandler;
688
689 lock (m_ModelCost)
690 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
691
473 return uploadResponse; 692 return uploadResponse;
474 } 693 }
475 694
@@ -481,8 +700,14 @@ namespace OpenSim.Region.ClientStack.Linden
481 /// <param name="data"></param> 700 /// <param name="data"></param>
482 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 701 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
483 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 702 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
484 string assetType) 703 string assetType, int cost,
704 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
705 bool IsAtestUpload, ref string error)
485 { 706 {
707
708 lock (m_ModelCost)
709 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
710
486 m_log.DebugFormat( 711 m_log.DebugFormat(
487 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 712 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
488 assetID, inventoryItem, inventoryType, assetType); 713 assetID, inventoryItem, inventoryType, assetType);
@@ -490,117 +715,247 @@ namespace OpenSim.Region.ClientStack.Linden
490 sbyte assType = 0; 715 sbyte assType = 0;
491 sbyte inType = 0; 716 sbyte inType = 0;
492 717
718 IClientAPI client = null;
719
720 UUID owner_id = m_HostCapsObj.AgentID;
721 UUID creatorID;
722
723 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
724
725 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
726
727 if (istest && m_testAssetsCreatorID != UUID.Zero)
728 creatorID = m_testAssetsCreatorID;
729 else
730 creatorID = owner_id;
731
732 string creatorIDstr = creatorID.ToString();
733
734 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
735 if (mm != null)
736 {
737 // make sure client still has enougth credit
738 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
739 {
740 error = "Insufficient funds.";
741 return;
742 }
743 }
744
745 // strings to types
493 if (inventoryType == "sound") 746 if (inventoryType == "sound")
494 { 747 {
495 inType = 1; 748 inType = (sbyte)InventoryType.Sound;
496 assType = 1; 749 assType = (sbyte)AssetType.Sound;
497 } 750 }
498 else if (inventoryType == "animation") 751 else if (inventoryType == "animation")
499 { 752 {
500 inType = 19; 753 inType = (sbyte)InventoryType.Animation;
501 assType = 20; 754 assType = (sbyte)AssetType.Animation;
502 } 755 }
503 else if (inventoryType == "wearable") 756 else if (inventoryType == "wearable")
504 { 757 {
505 inType = 18; 758 inType = (sbyte)InventoryType.Wearable;
506 switch (assetType) 759 switch (assetType)
507 { 760 {
508 case "bodypart": 761 case "bodypart":
509 assType = 13; 762 assType = (sbyte)AssetType.Bodypart;
510 break; 763 break;
511 case "clothing": 764 case "clothing":
512 assType = 5; 765 assType = (sbyte)AssetType.Clothing;
513 break; 766 break;
514 } 767 }
515 } 768 }
516 else if (inventoryType == "object") 769 else if (inventoryType == "object")
517 { 770 {
518 inType = (sbyte)InventoryType.Object; 771 if (assetType == "mesh") // this code for now is for mesh models uploads only
519 assType = (sbyte)AssetType.Object;
520
521 List<Vector3> positions = new List<Vector3>();
522 List<Quaternion> rotations = new List<Quaternion>();
523 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
524 OSDArray instance_list = (OSDArray)request["instance_list"];
525 OSDArray mesh_list = (OSDArray)request["mesh_list"];
526 OSDArray texture_list = (OSDArray)request["texture_list"];
527 SceneObjectGroup grp = null;
528
529 List<UUID> textures = new List<UUID>();
530 for (int i = 0; i < texture_list.Count; i++)
531 { 772 {
532 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 773 inType = (sbyte)InventoryType.Object;
533 textureAsset.Data = texture_list[i].AsBinary(); 774 assType = (sbyte)AssetType.Object;
534 m_assetService.Store(textureAsset);
535 textures.Add(textureAsset.FullID);
536 }
537 775
538 for (int i = 0; i < mesh_list.Count; i++) 776 List<Vector3> positions = new List<Vector3>();
539 { 777 List<Quaternion> rotations = new List<Quaternion>();
540 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 778 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
541 779
542 Primitive.TextureEntry textureEntry 780 // compare and get updated information
543 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
544 OSDMap inner_instance_list = (OSDMap)instance_list[i];
545 781
546 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 782 bool mismatchError = true;
547 for (uint face = 0; face < face_list.Count; face++) 783
784 while (mismatchError)
548 { 785 {
549 OSDMap faceMap = (OSDMap)face_list[(int)face]; 786 mismatchError = false;
550 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 787 }
551 if(faceMap.ContainsKey("fullbright"))
552 f.Fullbright = faceMap["fullbright"].AsBoolean();
553 if (faceMap.ContainsKey ("diffuse_color"))
554 f.RGBA = faceMap["diffuse_color"].AsColor4();
555 788
556 int textureNum = faceMap["image"].AsInteger(); 789 if (mismatchError)
557 float imagerot = faceMap["imagerot"].AsInteger(); 790 {
558 float offsets = (float)faceMap["offsets"].AsReal(); 791 error = "Upload and fee estimation information don't match";
559 float offsett = (float)faceMap["offsett"].AsReal(); 792 lock (m_ModelCost)
560 float scales = (float)faceMap["scales"].AsReal(); 793 m_FileAgentInventoryState = FileAgentInventoryState.idle;
561 float scalet = (float)faceMap["scalet"].AsReal(); 794
795 return;
796 }
562 797
563 if(imagerot != 0) 798 OSDArray instance_list = (OSDArray)request["instance_list"];
564 f.Rotation = imagerot; 799 OSDArray mesh_list = (OSDArray)request["mesh_list"];
800 OSDArray texture_list = (OSDArray)request["texture_list"];
801 SceneObjectGroup grp = null;
565 802
566 if(offsets != 0) 803 // create and store texture assets
567 f.OffsetU = offsets; 804 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
805 texturesFolder != UUID.Zero);
568 806
569 if (offsett != 0)
570 f.OffsetV = offsett;
571 807
572 if (scales != 0) 808 List<UUID> textures = new List<UUID>();
573 f.RepeatU = scales;
574 809
575 if (scalet != 0) 810
576 f.RepeatV = scalet; 811 if (doTextInv)
812 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
577 813
578 if (textures.Count > textureNum) 814 if(client == null) // don't put textures in inventory if there is no client
579 f.TextureID = textures[textureNum]; 815 doTextInv = false;
580 else 816
581 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; 817 for (int i = 0; i < texture_list.Count; i++)
818 {
819 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
820 textureAsset.Data = texture_list[i].AsBinary();
821 if (istest)
822 textureAsset.Local = true;
823 m_assetService.Store(textureAsset);
824 textures.Add(textureAsset.FullID);
825
826 if (doTextInv)
827 {
828 string name = assetName;
829 if (name.Length > 25)
830 name = name.Substring(0, 24);
831 name += "_Texture#" + i.ToString();
832 InventoryItemBase texitem = new InventoryItemBase();
833 texitem.Owner = m_HostCapsObj.AgentID;
834 texitem.CreatorId = creatorIDstr;
835 texitem.CreatorData = String.Empty;
836 texitem.ID = UUID.Random();
837 texitem.AssetID = textureAsset.FullID;
838 texitem.Description = "mesh model texture";
839 texitem.Name = name;
840 texitem.AssetType = (int)AssetType.Texture;
841 texitem.InvType = (int)InventoryType.Texture;
842 texitem.Folder = texturesFolder;
843
844 texitem.CurrentPermissions
845 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
846
847 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
848 texitem.EveryOnePermissions = 0;
849 texitem.NextPermissions = (uint)PermissionMask.All;
850 texitem.CreationDate = Util.UnixTimeSinceEpoch();
851
852 m_Scene.AddInventoryItem(client, texitem);
853 texitem = null;
854 }
855 }
582 856
583 textureEntry.FaceTextures[face] = f; 857 // create and store meshs assets
858 List<UUID> meshAssets = new List<UUID>();
859 for (int i = 0; i < mesh_list.Count; i++)
860 {
861 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
862 meshAsset.Data = mesh_list[i].AsBinary();
863 if (istest)
864 meshAsset.Local = true;
865 m_assetService.Store(meshAsset);
866 meshAssets.Add(meshAsset.FullID);
584 } 867 }
585 868
586 pbs.TextureEntry = textureEntry.GetBytes(); 869 int skipedMeshs = 0;
870 // build prims from instances
871 for (int i = 0; i < instance_list.Count; i++)
872 {
873 OSDMap inner_instance_list = (OSDMap)instance_list[i];
874
875 // skip prims that are 2 small
876 Vector3 scale = inner_instance_list["scale"].AsVector3();
877
878 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
879 {
880 skipedMeshs++;
881 continue;
882 }
883
884 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
587 885
588 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 886 Primitive.TextureEntry textureEntry
589 meshAsset.Data = mesh_list[i].AsBinary(); 887 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
590 m_assetService.Store(meshAsset);
591 888
592 pbs.SculptEntry = true;
593 pbs.SculptTexture = meshAsset.FullID;
594 pbs.SculptType = (byte)SculptType.Mesh;
595 pbs.SculptData = meshAsset.Data;
596 889
597 Vector3 position = inner_instance_list["position"].AsVector3(); 890 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
598 Vector3 scale = inner_instance_list["scale"].AsVector3(); 891 for (uint face = 0; face < face_list.Count; face++)
599 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 892 {
893 OSDMap faceMap = (OSDMap)face_list[(int)face];
894 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
895 if (faceMap.ContainsKey("fullbright"))
896 f.Fullbright = faceMap["fullbright"].AsBoolean();
897 if (faceMap.ContainsKey("diffuse_color"))
898 f.RGBA = faceMap["diffuse_color"].AsColor4();
899
900 int textureNum = faceMap["image"].AsInteger();
901 float imagerot = faceMap["imagerot"].AsInteger();
902 float offsets = (float)faceMap["offsets"].AsReal();
903 float offsett = (float)faceMap["offsett"].AsReal();
904 float scales = (float)faceMap["scales"].AsReal();
905 float scalet = (float)faceMap["scalet"].AsReal();
906
907 if (imagerot != 0)
908 f.Rotation = imagerot;
909
910 if (offsets != 0)
911 f.OffsetU = offsets;
912
913 if (offsett != 0)
914 f.OffsetV = offsett;
915
916 if (scales != 0)
917 f.RepeatU = scales;
918
919 if (scalet != 0)
920 f.RepeatV = scalet;
921
922 if (textures.Count > textureNum)
923 f.TextureID = textures[textureNum];
924 else
925 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
926
927 textureEntry.FaceTextures[face] = f;
928 }
929
930 pbs.TextureEntry = textureEntry.GetBytes();
931
932 bool hasmesh = false;
933 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
934 {
935 int meshindx = inner_instance_list["mesh"].AsInteger();
936 if (meshAssets.Count > meshindx)
937 {
938 pbs.SculptEntry = true;
939 pbs.SculptType = (byte)SculptType.Mesh;
940 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
941 // data will be requested from asset on rez (i hope)
942 hasmesh = true;
943 }
944 }
945
946 Vector3 position = inner_instance_list["position"].AsVector3();
947 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
948
949 // for now viwers do send fixed defaults
950 // but this may change
951// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
952 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
953 if(hasmesh)
954 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
955// int material = inner_instance_list["material"].AsInteger();
956 byte material = (byte)Material.Wood;
600 957
601// no longer used - begin ------------------------ 958// no longer used - begin ------------------------
602// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
603// int material = inner_instance_list["material"].AsInteger();
604// int mesh = inner_instance_list["mesh"].AsInteger(); 959// int mesh = inner_instance_list["mesh"].AsInteger();
605 960
606// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 961// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -615,24 +970,49 @@ namespace OpenSim.Region.ClientStack.Linden
615// UUID owner_id = permissions["owner_id"].AsUUID(); 970// UUID owner_id = permissions["owner_id"].AsUUID();
616// int owner_mask = permissions["owner_mask"].AsInteger(); 971// int owner_mask = permissions["owner_mask"].AsInteger();
617// no longer used - end ------------------------ 972// no longer used - end ------------------------
973
974
975 SceneObjectPart prim
976 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
977
978 prim.Scale = scale;
979 rotations.Add(rotation);
980 positions.Add(position);
981 prim.UUID = UUID.Random();
982 prim.CreatorID = creatorID;
983 prim.OwnerID = owner_id;
984 prim.GroupID = UUID.Zero;
985 prim.LastOwnerID = creatorID;
986 prim.CreationDate = Util.UnixTimeSinceEpoch();
987
988 if (grp == null)
989 prim.Name = assetName;
990 else
991 prim.Name = assetName + "#" + i.ToString();
618 992
619 UUID owner_id = m_HostCapsObj.AgentID; 993 prim.EveryoneMask = 0;
994 prim.GroupMask = 0;
995
996 if (restrictPerms)
997 {
998 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
999 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1000 prim.NextOwnerMask = 0;
1001 }
1002 else
1003 {
1004 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1005 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1006 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1007 }
620 1008
621 SceneObjectPart prim 1009 if(istest)
622 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 1010 prim.Description = "For testing only. Other uses are prohibited";
1011 else
1012 prim.Description = "";
623 1013
624 prim.Scale = scale; 1014 prim.Material = material;
625 //prim.OffsetPosition = position; 1015 prim.PhysicsShapeType = physicsShapeType;
626 rotations.Add(rotation);
627 positions.Add(position);
628 prim.UUID = UUID.Random();
629 prim.CreatorID = owner_id;
630 prim.OwnerID = owner_id;
631 prim.GroupID = UUID.Zero;
632 prim.LastOwnerID = prim.OwnerID;
633 prim.CreationDate = Util.UnixTimeSinceEpoch();
634 prim.Name = assetName;
635 prim.Description = "";
636 1016
637// prim.BaseMask = (uint)base_mask; 1017// prim.BaseMask = (uint)base_mask;
638// prim.EveryoneMask = (uint)everyone_mask; 1018// prim.EveryoneMask = (uint)everyone_mask;
@@ -640,52 +1020,64 @@ namespace OpenSim.Region.ClientStack.Linden
640// prim.NextOwnerMask = (uint)next_owner_mask; 1020// prim.NextOwnerMask = (uint)next_owner_mask;
641// prim.OwnerMask = (uint)owner_mask; 1021// prim.OwnerMask = (uint)owner_mask;
642 1022
643 if (grp == null) 1023 if (grp == null)
644 grp = new SceneObjectGroup(prim); 1024 {
645 else 1025 grp = new SceneObjectGroup(prim);
646 grp.AddPart(prim); 1026 grp.LastOwnerID = creatorID;
647 } 1027 }
1028 else
1029 grp.AddPart(prim);
1030 }
648 1031
649 Vector3 rootPos = positions[0]; 1032 Vector3 rootPos = positions[0];
650 1033
651 if (grp.Parts.Length > 1) 1034 if (grp.Parts.Length > 1)
652 { 1035 {
653 // Fix first link number 1036 // Fix first link number
654 grp.RootPart.LinkNum++; 1037 grp.RootPart.LinkNum++;
655 1038
656 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1039 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
657 Quaternion tmprot; 1040 Quaternion tmprot;
658 Vector3 offset; 1041 Vector3 offset;
659 1042
660 // fix children rotations and positions 1043 // fix children rotations and positions
661 for (int i = 1; i < rotations.Count; i++) 1044 for (int i = 1; i < rotations.Count; i++)
662 { 1045 {
663 tmprot = rotations[i]; 1046 tmprot = rotations[i];
664 tmprot = rootRotConj * tmprot; 1047 tmprot = rootRotConj * tmprot;
1048
1049 grp.Parts[i].RotationOffset = tmprot;
665 1050
666 grp.Parts[i].RotationOffset = tmprot; 1051 offset = positions[i] - rootPos;
667 1052
668 offset = positions[i] - rootPos; 1053 offset *= rootRotConj;
1054 grp.Parts[i].OffsetPosition = offset;
1055 }
669 1056
670 offset *= rootRotConj; 1057 grp.AbsolutePosition = rootPos;
671 grp.Parts[i].OffsetPosition = offset; 1058 grp.UpdateGroupRotationR(rotations[0]);
1059 }
1060 else
1061 {
1062 grp.AbsolutePosition = rootPos;
1063 grp.UpdateGroupRotationR(rotations[0]);
672 } 1064 }
673 1065
674 grp.AbsolutePosition = rootPos; 1066 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
675 grp.UpdateGroupRotationR(rotations[0]);
676 } 1067 }
677 else 1068
1069 else // not a mesh model
678 { 1070 {
679 grp.AbsolutePosition = rootPos; 1071 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
680 grp.UpdateGroupRotationR(rotations[0]); 1072 return;
681 } 1073 }
682
683 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
684 } 1074 }
685 1075
686 AssetBase asset; 1076 AssetBase asset;
687 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1077 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
688 asset.Data = data; 1078 asset.Data = data;
1079 if (istest)
1080 asset.Local = true;
689 if (AddNewAsset != null) 1081 if (AddNewAsset != null)
690 AddNewAsset(asset); 1082 AddNewAsset(asset);
691 else if (m_assetService != null) 1083 else if (m_assetService != null)
@@ -693,11 +1085,17 @@ namespace OpenSim.Region.ClientStack.Linden
693 1085
694 InventoryItemBase item = new InventoryItemBase(); 1086 InventoryItemBase item = new InventoryItemBase();
695 item.Owner = m_HostCapsObj.AgentID; 1087 item.Owner = m_HostCapsObj.AgentID;
696 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1088 item.CreatorId = creatorIDstr;
697 item.CreatorData = String.Empty; 1089 item.CreatorData = String.Empty;
698 item.ID = inventoryItem; 1090 item.ID = inventoryItem;
699 item.AssetID = asset.FullID; 1091 item.AssetID = asset.FullID;
700 item.Description = assetDescription; 1092 if (istest)
1093 {
1094 item.Description = "For testing only. Other uses are prohibited";
1095 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1096 }
1097 else
1098 item.Description = assetDescription;
701 item.Name = assetName; 1099 item.Name = assetName;
702 item.AssetType = assType; 1100 item.AssetType = assType;
703 item.InvType = inType; 1101 item.InvType = inType;
@@ -705,18 +1103,56 @@ namespace OpenSim.Region.ClientStack.Linden
705 1103
706 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1104 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
707 // (owner) permissions. This becomes a problem if next permissions are changed. 1105 // (owner) permissions. This becomes a problem if next permissions are changed.
708 item.CurrentPermissions
709 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
710 1106
711 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1107 if (restrictPerms)
712 item.EveryOnePermissions = 0; 1108 {
713 item.NextPermissions = (uint)PermissionMask.All; 1109 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1110 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1111 item.EveryOnePermissions = 0;
1112 item.NextPermissions = 0;
1113 }
1114 else
1115 {
1116 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1117 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1118 item.EveryOnePermissions = 0;
1119 item.NextPermissions = (uint)PermissionMask.Transfer;
1120 }
1121
714 item.CreationDate = Util.UnixTimeSinceEpoch(); 1122 item.CreationDate = Util.UnixTimeSinceEpoch();
715 1123
1124 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1125
716 if (AddNewInventoryItem != null) 1126 if (AddNewInventoryItem != null)
717 { 1127 {
718 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1128 if (istest)
1129 {
1130 m_Scene.AddInventoryItem(client, item);
1131/*
1132 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1133 if (client != null)
1134 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);
1135 */
1136 }
1137 else
1138 {
1139 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1140// if (client != null)
1141// {
1142// // let users see anything.. i don't so far
1143// string str;
1144// if (cost > 0)
1145// // dont remember where is money unit name to put here
1146// str = "Upload complete. charged " + cost.ToString() + "$";
1147// else
1148// str = "Upload complete";
1149// client.SendAgentAlertMessage(str, true);
1150// }
1151 }
719 } 1152 }
1153
1154 lock (m_ModelCost)
1155 m_FileAgentInventoryState = FileAgentInventoryState.idle;
720 } 1156 }
721 1157
722 /// <summary> 1158 /// <summary>
@@ -909,6 +1345,120 @@ namespace OpenSim.Region.ClientStack.Linden
909 return response; 1345 return response;
910 } 1346 }
911 1347
1348 public string GetObjectCost(string request, string path,
1349 string param, IOSHttpRequest httpRequest,
1350 IOSHttpResponse httpResponse)
1351 {
1352 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1353 OSDMap resp = new OSDMap();
1354
1355 OSDArray object_ids = (OSDArray)req["object_ids"];
1356
1357 for (int i = 0; i < object_ids.Count; i++)
1358 {
1359 UUID uuid = object_ids[i].AsUUID();
1360
1361 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1362
1363 if (part != null)
1364 {
1365 SceneObjectGroup grp = part.ParentGroup;
1366 if (grp != null)
1367 {
1368 float linksetCost;
1369 float linksetPhysCost;
1370 float partCost;
1371 float partPhysCost;
1372
1373 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1374
1375 OSDMap object_data = new OSDMap();
1376 object_data["linked_set_resource_cost"] = linksetCost;
1377 object_data["resource_cost"] = partCost;
1378 object_data["physics_cost"] = partPhysCost;
1379 object_data["linked_set_physics_cost"] = linksetPhysCost;
1380
1381 resp[uuid.ToString()] = object_data;
1382 }
1383 }
1384 }
1385
1386 string response = OSDParser.SerializeLLSDXmlString(resp);
1387 return response;
1388 }
1389
1390 public string ResourceCostSelected(string request, string path,
1391 string param, IOSHttpRequest httpRequest,
1392 IOSHttpResponse httpResponse)
1393 {
1394 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1395 OSDMap resp = new OSDMap();
1396
1397
1398 float phys=0;
1399 float stream=0;
1400 float simul=0;
1401
1402 if (req.ContainsKey("selected_roots"))
1403 {
1404 OSDArray object_ids = (OSDArray)req["selected_roots"];
1405
1406 // should go by SOG suming costs for all parts
1407 // ll v3 works ok with several objects select we get the list and adds ok
1408 // FS calls per object so results are wrong guess fs bug
1409 for (int i = 0; i < object_ids.Count; i++)
1410 {
1411 UUID uuid = object_ids[i].AsUUID();
1412 float Physc;
1413 float simulc;
1414 float streamc;
1415
1416 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1417 if (grp != null)
1418 {
1419 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1420 phys += Physc;
1421 stream += streamc;
1422 simul += simulc;
1423 }
1424 }
1425 }
1426 else if (req.ContainsKey("selected_prims"))
1427 {
1428 OSDArray object_ids = (OSDArray)req["selected_prims"];
1429
1430 // don't see in use in any of the 2 viewers
1431 // guess it should be for edit linked but... nothing
1432 // should go to SOP per part
1433 for (int i = 0; i < object_ids.Count; i++)
1434 {
1435 UUID uuid = object_ids[i].AsUUID();
1436
1437 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1438 if (part != null)
1439 {
1440 phys += part.PhysicsCost;
1441 stream += part.StreamingCost;
1442 simul += part.SimulationCost;
1443 }
1444 }
1445 }
1446
1447 if (simul != 0)
1448 {
1449 OSDMap object_data = new OSDMap();
1450
1451 object_data["physics"] = phys;
1452 object_data["streaming"] = stream;
1453 object_data["simulation"] = simul;
1454
1455 resp["selected"] = object_data;
1456 }
1457
1458 string response = OSDParser.SerializeLLSDXmlString(resp);
1459 return response;
1460 }
1461
912 public string UpdateAgentInformation(string request, string path, 1462 public string UpdateAgentInformation(string request, string path,
913 string param, IOSHttpRequest httpRequest, 1463 string param, IOSHttpRequest httpRequest,
914 IOSHttpResponse httpResponse) 1464 IOSHttpResponse httpResponse)
@@ -928,6 +1478,10 @@ namespace OpenSim.Region.ClientStack.Linden
928 1478
929 public class AssetUploader 1479 public class AssetUploader
930 { 1480 {
1481 private static readonly ILog m_log =
1482 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1483
1484
931 public event UpLoadedAsset OnUpLoad; 1485 public event UpLoadedAsset OnUpLoad;
932 private UpLoadedAsset handlerUpLoad = null; 1486 private UpLoadedAsset handlerUpLoad = null;
933 1487
@@ -942,10 +1496,21 @@ namespace OpenSim.Region.ClientStack.Linden
942 1496
943 private string m_invType = String.Empty; 1497 private string m_invType = String.Empty;
944 private string m_assetType = String.Empty; 1498 private string m_assetType = String.Empty;
1499 private int m_cost;
1500 private string m_error = String.Empty;
1501
1502 private Timer m_timeoutTimer = new Timer();
1503 private UUID m_texturesFolder;
1504 private int m_nreqtextures;
1505 private int m_nreqmeshs;
1506 private int m_nreqinstances;
1507 private bool m_IsAtestUpload;
945 1508
946 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1509 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
947 UUID parentFolderID, string invType, string assetType, string path, 1510 UUID parentFolderID, string invType, string assetType, string path,
948 IHttpServer httpServer, bool dumpAssetsToFile) 1511 IHttpServer httpServer, bool dumpAssetsToFile,
1512 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1513 bool IsAtestUpload)
949 { 1514 {
950 m_assetName = assetName; 1515 m_assetName = assetName;
951 m_assetDes = description; 1516 m_assetDes = description;
@@ -957,6 +1522,18 @@ namespace OpenSim.Region.ClientStack.Linden
957 m_assetType = assetType; 1522 m_assetType = assetType;
958 m_invType = invType; 1523 m_invType = invType;
959 m_dumpAssetsToFile = dumpAssetsToFile; 1524 m_dumpAssetsToFile = dumpAssetsToFile;
1525 m_cost = totalCost;
1526
1527 m_texturesFolder = texturesFolder;
1528 m_nreqtextures = nreqtextures;
1529 m_nreqmeshs = nreqmeshs;
1530 m_nreqinstances = nreqinstances;
1531 m_IsAtestUpload = IsAtestUpload;
1532
1533 m_timeoutTimer.Elapsed += TimedOut;
1534 m_timeoutTimer.Interval = 120000;
1535 m_timeoutTimer.AutoReset = false;
1536 m_timeoutTimer.Start();
960 } 1537 }
961 1538
962 /// <summary> 1539 /// <summary>
@@ -971,12 +1548,14 @@ namespace OpenSim.Region.ClientStack.Linden
971 UUID inv = inventoryItemID; 1548 UUID inv = inventoryItemID;
972 string res = String.Empty; 1549 string res = String.Empty;
973 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1550 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1551/*
974 uploadComplete.new_asset = newAssetID.ToString(); 1552 uploadComplete.new_asset = newAssetID.ToString();
975 uploadComplete.new_inventory_item = inv; 1553 uploadComplete.new_inventory_item = inv;
976 uploadComplete.state = "complete"; 1554 uploadComplete.state = "complete";
977 1555
978 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1556 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
979 1557*/
1558 m_timeoutTimer.Stop();
980 httpListener.RemoveStreamHandler("POST", uploaderPath); 1559 httpListener.RemoveStreamHandler("POST", uploaderPath);
981 1560
982 // TODO: probably make this a better set of extensions here 1561 // TODO: probably make this a better set of extensions here
@@ -993,12 +1572,49 @@ namespace OpenSim.Region.ClientStack.Linden
993 handlerUpLoad = OnUpLoad; 1572 handlerUpLoad = OnUpLoad;
994 if (handlerUpLoad != null) 1573 if (handlerUpLoad != null)
995 { 1574 {
996 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1575 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1576 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
997 } 1577 }
1578 if (m_IsAtestUpload)
1579 {
1580 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1581 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1582 resperror.identifier = inv;
998 1583
1584 uploadComplete.error = resperror;
1585 uploadComplete.state = "Upload4Testing";
1586 }
1587 else
1588 {
1589 if (m_error == String.Empty)
1590 {
1591 uploadComplete.new_asset = newAssetID.ToString();
1592 uploadComplete.new_inventory_item = inv;
1593 // if (m_texturesFolder != UUID.Zero)
1594 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1595 uploadComplete.state = "complete";
1596 }
1597 else
1598 {
1599 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1600 resperror.message = m_error;
1601 resperror.identifier = inv;
1602
1603 uploadComplete.error = resperror;
1604 uploadComplete.state = "failed";
1605 }
1606 }
1607
1608 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
999 return res; 1609 return res;
1000 } 1610 }
1001 1611
1612 private void TimedOut(object sender, ElapsedEventArgs args)
1613 {
1614 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1615 httpListener.RemoveStreamHandler("POST", uploaderPath);
1616 }
1617
1002 ///Left this in and commented in case there are unforseen issues 1618 ///Left this in and commented in case there are unforseen issues
1003 //private void SaveAssetToFile(string filename, byte[] data) 1619 //private void SaveAssetToFile(string filename, byte[] data)
1004 //{ 1620 //{
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..4a3fae6
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs
@@ -0,0 +1,671 @@
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 public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost,
100 LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning)
101 {
102 totalcost = 0;
103 error = string.Empty;
104
105 if (resources == null ||
106 resources.instance_list == null ||
107 resources.instance_list.Array.Count == 0)
108 {
109 error = "missing model information.";
110 return false;
111 }
112
113 int numberInstances = resources.instance_list.Array.Count;
114
115 if( numberInstances > ObjectLinkedPartsMax )
116 {
117 error = "Model whould have more than " + ObjectLinkedPartsMax.ToString() + " linked prims";
118 return false;
119 }
120
121 meshcostdata.model_streaming_cost = 0.0;
122 meshcostdata.simulation_cost = 0.0;
123 meshcostdata.physics_cost = 0.0;
124 meshcostdata.resource_cost = 0.0;
125
126 meshcostdata.upload_price_breakdown.mesh_instance = 0;
127 meshcostdata.upload_price_breakdown.mesh_physics = 0;
128 meshcostdata.upload_price_breakdown.mesh_streaming = 0;
129 meshcostdata.upload_price_breakdown.model = 0;
130
131 int itmp;
132
133 // textures cost
134 if (resources.texture_list != null && resources.texture_list.Array.Count > 0)
135 {
136 float textures_cost = (float)(resources.texture_list.Array.Count * basicCost);
137 textures_cost *= ModelTextureCostFactor;
138
139 itmp = (int)(textures_cost + 0.5f); // round
140 meshcostdata.upload_price_breakdown.texture = itmp;
141 totalcost += itmp;
142 }
143
144 // meshs assets cost
145 float meshsfee = 0;
146 int numberMeshs = 0;
147 bool haveMeshs = false;
148 List<ameshCostParam> meshsCosts = new List<ameshCostParam>();
149
150 if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0)
151 {
152 numberMeshs = resources.mesh_list.Array.Count;
153
154 for (int i = 0; i < numberMeshs; i++)
155 {
156 ameshCostParam curCost = new ameshCostParam();
157 byte[] data = (byte[])resources.mesh_list.Array[i];
158
159 if (!MeshCost(data, curCost, out error))
160 {
161 return false;
162 }
163 meshsCosts.Add(curCost);
164 meshsfee += curCost.costFee;
165 }
166 haveMeshs = true;
167 }
168
169 // instances (prims) cost
170
171
172 int mesh;
173 int skipedSmall = 0;
174 for (int i = 0; i < numberInstances; i++)
175 {
176 Hashtable inst = (Hashtable)resources.instance_list.Array[i];
177
178 ArrayList ascale = (ArrayList)inst["scale"];
179 Vector3 scale;
180 double tmp;
181 tmp = (double)ascale[0];
182 scale.X = (float)tmp;
183 tmp = (double)ascale[1];
184 scale.Y = (float)tmp;
185 tmp = (double)ascale[2];
186 scale.Z = (float)tmp;
187
188 if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin)
189 {
190 skipedSmall++;
191 continue;
192 }
193
194 if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax)
195 {
196 error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale";
197 return false;
198 }
199
200 if (haveMeshs && inst.ContainsKey("mesh"))
201 {
202 mesh = (int)inst["mesh"];
203
204 if (mesh >= numberMeshs)
205 {
206 error = "Incoerent model information.";
207 return false;
208 }
209
210 // streamming cost
211
212 float sqdiam = scale.LengthSquared();
213
214 ameshCostParam curCost = meshsCosts[mesh];
215 float mesh_streaming = streamingCost(curCost, sqdiam);
216
217 meshcostdata.model_streaming_cost += mesh_streaming;
218 meshcostdata.physics_cost += curCost.physicsCost;
219 }
220 else // instance as no mesh ??
221 {
222 // to do later if needed
223 meshcostdata.model_streaming_cost += 0.5f;
224 meshcostdata.physics_cost += 1.0f;
225 }
226
227 // assume unscripted and static prim server cost
228 meshcostdata.simulation_cost += 0.5f;
229 // charge for prims creation
230 meshsfee += primCreationCost;
231 }
232
233 if (skipedSmall > 0)
234 {
235 if (skipedSmall > numberInstances / 2)
236 {
237 error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() +
238 "m minimum allowed size. Please check scalling";
239 return false;
240 }
241 else
242 warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() +
243 " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() +
244 "m minimum allowed size. Please check scalling ";
245 }
246
247 if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost)
248 meshcostdata.resource_cost = meshcostdata.model_streaming_cost;
249 else
250 meshcostdata.resource_cost = meshcostdata.physics_cost;
251
252 if (meshcostdata.resource_cost < meshcostdata.simulation_cost)
253 meshcostdata.resource_cost = meshcostdata.simulation_cost;
254
255 // scale cost
256 // at this point a cost of 1.0 whould mean basic cost
257 meshsfee *= ModelMeshCostFactor;
258
259 if (meshsfee < ModelMinCostFactor)
260 meshsfee = ModelMinCostFactor;
261
262 // actually scale it to basic cost
263 meshsfee *= (float)basicCost;
264
265 meshsfee += 0.5f; // rounding
266
267 totalcost += (int)meshsfee;
268
269 // breakdown prices
270 // don't seem to be in use so removed code for now
271
272 return true;
273 }
274
275 // single mesh asset cost
276 private bool MeshCost(byte[] data, ameshCostParam cost, out string error)
277 {
278 cost.highLODSize = 0;
279 cost.medLODSize = 0;
280 cost.lowLODSize = 0;
281 cost.lowestLODSize = 0;
282 cost.physicsCost = 0.0f;
283 cost.costFee = 0.0f;
284
285 error = string.Empty;
286
287 if (data == null || data.Length == 0)
288 {
289 error = "Missing model information.";
290 return false;
291 }
292
293 OSD meshOsd = null;
294 int start = 0;
295
296 error = "Invalid model data";
297
298 using (MemoryStream ms = new MemoryStream(data))
299 {
300 try
301 {
302 OSD osd = OSDParser.DeserializeLLSDBinary(ms);
303 if (osd is OSDMap)
304 meshOsd = (OSDMap)osd;
305 else
306 return false;
307 }
308 catch (Exception e)
309 {
310 return false;
311 }
312 start = (int)ms.Position;
313 }
314
315 OSDMap map = (OSDMap)meshOsd;
316 OSDMap tmpmap;
317
318 int highlod_size = 0;
319 int medlod_size = 0;
320 int lowlod_size = 0;
321 int lowestlod_size = 0;
322 int skin_size = 0;
323
324 int hulls_size = 0;
325 int phys_nhulls;
326 int phys_hullsvertices = 0;
327
328 int physmesh_size = 0;
329 int phys_ntriangles = 0;
330
331 int submesh_offset = -1;
332
333 if (map.ContainsKey("physics_convex"))
334 {
335 tmpmap = (OSDMap)map["physics_convex"];
336 if (tmpmap.ContainsKey("offset"))
337 submesh_offset = tmpmap["offset"].AsInteger() + start;
338 if (tmpmap.ContainsKey("size"))
339 hulls_size = tmpmap["size"].AsInteger();
340 }
341
342 if (submesh_offset < 0 || hulls_size == 0)
343 {
344 error = "Missing physics_convex block";
345 return false;
346 }
347
348 if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls))
349 {
350 error = "Bad physics_convex block";
351 return false;
352 }
353
354 submesh_offset = -1;
355
356 // only look for LOD meshs sizes
357
358 if (map.ContainsKey("high_lod"))
359 {
360 tmpmap = (OSDMap)map["high_lod"];
361 // see at least if there is a offset for this one
362 if (tmpmap.ContainsKey("offset"))
363 submesh_offset = tmpmap["offset"].AsInteger() + start;
364 if (tmpmap.ContainsKey("size"))
365 highlod_size = tmpmap["size"].AsInteger();
366 }
367
368 if (submesh_offset < 0 || highlod_size <= 0)
369 {
370 error = "Missing high_lod block";
371 return false;
372 }
373
374 bool haveprev = true;
375
376 if (map.ContainsKey("medium_lod"))
377 {
378 tmpmap = (OSDMap)map["medium_lod"];
379 if (tmpmap.ContainsKey("size"))
380 medlod_size = tmpmap["size"].AsInteger();
381 else
382 haveprev = false;
383 }
384
385 if (haveprev && map.ContainsKey("low_lod"))
386 {
387 tmpmap = (OSDMap)map["low_lod"];
388 if (tmpmap.ContainsKey("size"))
389 lowlod_size = tmpmap["size"].AsInteger();
390 else
391 haveprev = false;
392 }
393
394 if (haveprev && map.ContainsKey("lowest_lod"))
395 {
396 tmpmap = (OSDMap)map["lowest_lod"];
397 if (tmpmap.ContainsKey("size"))
398 lowestlod_size = tmpmap["size"].AsInteger();
399 }
400
401 if (map.ContainsKey("skin"))
402 {
403 tmpmap = (OSDMap)map["skin"];
404 if (tmpmap.ContainsKey("size"))
405 skin_size = tmpmap["size"].AsInteger();
406 }
407
408 cost.highLODSize = highlod_size;
409 cost.medLODSize = medlod_size;
410 cost.lowLODSize = lowlod_size;
411 cost.lowestLODSize = lowestlod_size;
412
413 submesh_offset = -1;
414
415 tmpmap = null;
416 if(map.ContainsKey("physics_mesh"))
417 tmpmap = (OSDMap)map["physics_mesh"];
418 else if (map.ContainsKey("physics_shape")) // old naming
419 tmpmap = (OSDMap)map["physics_shape"];
420
421 if(tmpmap != null)
422 {
423 if (tmpmap.ContainsKey("offset"))
424 submesh_offset = tmpmap["offset"].AsInteger() + start;
425 if (tmpmap.ContainsKey("size"))
426 physmesh_size = tmpmap["size"].AsInteger();
427
428 if (submesh_offset >= 0 || physmesh_size > 0)
429 {
430
431 if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles))
432 {
433 error = "Model data parsing error";
434 return false;
435 }
436 }
437 }
438
439 // upload is done in convex shape type so only one hull
440 phys_hullsvertices++;
441 cost.physicsCost = 0.04f * phys_hullsvertices;
442
443 float sfee;
444
445 sfee = data.Length; // start with total compressed data size
446
447 // penalize lod meshs that should be more builder optimized
448 sfee += medSizeWth * medlod_size;
449 sfee += lowSizeWth * lowlod_size;
450 sfee += lowestSizeWth * lowlod_size;
451
452 // physics
453 // favor potencial optimized meshs versus automatic decomposition
454 if (physmesh_size != 0)
455 sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull
456 else
457 sfee += physHullSizeWth * hulls_size;
458
459 // bytes to money
460 sfee *= bytecost;
461
462 cost.costFee = sfee;
463 return true;
464 }
465
466 // parses a LOD or physics mesh component
467 private bool submesh(byte[] data, int offset, int size, out int ntriangles)
468 {
469 ntriangles = 0;
470
471 OSD decodedMeshOsd = new OSD();
472 byte[] meshBytes = new byte[size];
473 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
474 try
475 {
476 using (MemoryStream inMs = new MemoryStream(meshBytes))
477 {
478 using (MemoryStream outMs = new MemoryStream())
479 {
480 using (ZOutputStream zOut = new ZOutputStream(outMs))
481 {
482 byte[] readBuffer = new byte[4096];
483 int readLen = 0;
484 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
485 {
486 zOut.Write(readBuffer, 0, readLen);
487 }
488 zOut.Flush();
489 outMs.Seek(0, SeekOrigin.Begin);
490
491 byte[] decompressedBuf = outMs.GetBuffer();
492 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
493 }
494 }
495 }
496 }
497 catch (Exception e)
498 {
499 return false;
500 }
501
502 OSDArray decodedMeshOsdArray = null;
503 if ((!decodedMeshOsd is OSDArray))
504 return false;
505
506 byte[] dummy;
507
508 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
509 foreach (OSD subMeshOsd in decodedMeshOsdArray)
510 {
511 if (subMeshOsd is OSDMap)
512 {
513 OSDMap subtmpmap = (OSDMap)subMeshOsd;
514 if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"]))
515 continue;
516
517 if (!subtmpmap.ContainsKey("Position"))
518 return false;
519
520 if (subtmpmap.ContainsKey("TriangleList"))
521 {
522 dummy = subtmpmap["TriangleList"].AsBinary();
523 ntriangles += dummy.Length / bytesPerCoord;
524 }
525 else
526 return false;
527 }
528 }
529
530 return true;
531 }
532
533 // parses convex hulls component
534 private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls)
535 {
536 nvertices = 0;
537 nhulls = 1;
538
539 OSD decodedMeshOsd = new OSD();
540 byte[] meshBytes = new byte[size];
541 System.Buffer.BlockCopy(data, offset, meshBytes, 0, size);
542 try
543 {
544 using (MemoryStream inMs = new MemoryStream(meshBytes))
545 {
546 using (MemoryStream outMs = new MemoryStream())
547 {
548 using (ZOutputStream zOut = new ZOutputStream(outMs))
549 {
550 byte[] readBuffer = new byte[4096];
551 int readLen = 0;
552 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
553 {
554 zOut.Write(readBuffer, 0, readLen);
555 }
556 zOut.Flush();
557 outMs.Seek(0, SeekOrigin.Begin);
558
559 byte[] decompressedBuf = outMs.GetBuffer();
560 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
561 }
562 }
563 }
564 }
565 catch (Exception e)
566 {
567 return false;
568 }
569
570 OSDMap cmap = (OSDMap)decodedMeshOsd;
571 if (cmap == null)
572 return false;
573
574 byte[] dummy;
575
576 // must have one of this
577 if (cmap.ContainsKey("BoundingVerts"))
578 {
579 dummy = cmap["BoundingVerts"].AsBinary();
580 nvertices = dummy.Length / bytesPerCoord;
581 }
582 else
583 return false;
584
585/* upload is done with convex shape type
586 if (cmap.ContainsKey("HullList"))
587 {
588 dummy = cmap["HullList"].AsBinary();
589 nhulls += dummy.Length;
590 }
591
592
593 if (cmap.ContainsKey("Positions"))
594 {
595 dummy = cmap["Positions"].AsBinary();
596 nvertices = dummy.Length / bytesPerCoord;
597 }
598 */
599
600 return true;
601 }
602
603 // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length
604 private float streamingCost(ameshCostParam curCost, float sqdiam)
605 {
606 // compute efective areas
607 float ma = 262144f;
608
609 float mh = sqdiam * highLodFactor;
610 if (mh > ma)
611 mh = ma;
612 float mm = sqdiam * midLodFactor;
613 if (mm > ma)
614 mm = ma;
615
616 float ml = sqdiam * lowLodFactor;
617 if (ml > ma)
618 ml = ma;
619
620 float mlst = ma;
621
622 mlst -= ml;
623 ml -= mm;
624 mm -= mh;
625
626 if (mlst < 1.0f)
627 mlst = 1.0f;
628 if (ml < 1.0f)
629 ml = 1.0f;
630 if (mm < 1.0f)
631 mm = 1.0f;
632 if (mh < 1.0f)
633 mh = 1.0f;
634
635 ma = mlst + ml + mm + mh;
636
637 // get LODs compressed sizes
638 // giving 384 bytes bonus
639 int lst = curCost.lowestLODSize - 384;
640 int l = curCost.lowLODSize - 384;
641 int m = curCost.medLODSize - 384;
642 int h = curCost.highLODSize - 384;
643
644 // use previus higher LOD size on missing ones
645 if (m <= 0)
646 m = h;
647 if (l <= 0)
648 l = m;
649 if (lst <= 0)
650 lst = l;
651
652 // force minumum sizes
653 if (lst < 16)
654 lst = 16;
655 if (l < 16)
656 l = 16;
657 if (m < 16)
658 m = 16;
659 if (h < 16)
660 h = 16;
661
662 // compute cost weighted by relative effective areas
663 float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh;
664 cost /= ma;
665
666 cost *= 0.004f; // overall tunning parameter
667
668 return cost;
669 }
670 }
671}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index c7d4283..eb40eb1 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -376,7 +376,7 @@ namespace OpenSim.Region.ClientStack.Linden
376 // TODO: Add EventQueueGet name/description for diagnostics 376 // TODO: Add EventQueueGet name/description for diagnostics
377 MainServer.Instance.AddPollServiceHTTPHandler( 377 MainServer.Instance.AddPollServiceHTTPHandler(
378 eventQueueGetPath, 378 eventQueueGetPath,
379 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID)); 379 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000));
380 380
381// m_log.DebugFormat( 381// m_log.DebugFormat(
382// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", 382// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}",
@@ -418,7 +418,7 @@ namespace OpenSim.Region.ClientStack.Linden
418 } 418 }
419 } 419 }
420 420
421 public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request) 421 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
422 { 422 {
423 if (DebugLevel >= 2) 423 if (DebugLevel >= 2)
424 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); 424 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName);
@@ -490,8 +490,8 @@ namespace OpenSim.Region.ClientStack.Linden
490 responsedata["content_type"] = "text/plain"; 490 responsedata["content_type"] = "text/plain";
491 responsedata["keepalive"] = false; 491 responsedata["keepalive"] = false;
492 responsedata["reusecontext"] = false; 492 responsedata["reusecontext"] = false;
493 responsedata["str_response_string"] = "Upstream error: "; 493 responsedata["str_response_string"] = "<llsd></llsd>";
494 responsedata["error_status_text"] = "Upstream error:"; 494 responsedata["error_status_text"] = "<llsd></llsd>";
495 responsedata["http_protocol_version"] = "HTTP/1.0"; 495 responsedata["http_protocol_version"] = "HTTP/1.0";
496 return responsedata; 496 return responsedata;
497 } 497 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index dab727f..7dcf137 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -151,6 +151,12 @@ namespace OpenSim.Region.ClientStack.Linden
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 152 uint locationID, uint flags, string capsURL, UUID agentID)
153 { 153 {
154 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
156 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
157 else
158 flags = (uint)TeleportFlags.ViaLocation;
159
154 OSDMap info = new OSDMap(); 160 OSDMap info = new OSDMap();
155 info.Add("AgentID", OSD.FromUUID(agentID)); 161 info.Add("AgentID", OSD.FromUUID(agentID));
156 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? 162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
@@ -159,7 +165,8 @@ namespace OpenSim.Region.ClientStack.Linden
159 info.Add("SimAccess", OSD.FromInteger(simAccess)); 165 info.Add("SimAccess", OSD.FromInteger(simAccess));
160 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); 166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
161 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
162 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags));
163 170
164 OSDArray infoArr = new OSDArray(); 171 OSDArray infoArr = new OSDArray();
165 infoArr.Add(info); 172 infoArr.Add(info);
@@ -398,7 +405,7 @@ namespace OpenSim.Region.ClientStack.Linden
398 public static OSD partPhysicsProperties(uint localID, byte physhapetype, 405 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
399 float density, float friction, float bounce, float gravmod) 406 float density, float friction, float bounce, float gravmod)
400 { 407 {
401 408
402 OSDMap physinfo = new OSDMap(6); 409 OSDMap physinfo = new OSDMap(6);
403 physinfo["LocalID"] = localID; 410 physinfo["LocalID"] = localID;
404 physinfo["Density"] = density; 411 physinfo["Density"] = density;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 8e1f63a..6ec1115 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,9 +60,45 @@ 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
64 struct aPollRequest
65 {
66 public PollServiceMeshEventArgs thepoll;
67 public UUID reqID;
68 public Hashtable request;
69 }
70
71 public class aPollResponse
72 {
73 public Hashtable response;
74 public int bytes;
75 public int lod;
76 }
77
78
79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80
81 private static GetMeshHandler m_getMeshHandler;
82
83 private IAssetService m_assetService = null;
84
85 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
86 private static Thread[] m_workerThreads = null;
87
88 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
89 new OpenMetaverse.BlockingQueue<aPollRequest>();
90
91 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
60 92
61 #region Region Module interfaceBase Members 93 #region Region Module interfaceBase Members
62 94
95 ~GetMeshModule()
96 {
97 foreach (Thread t in m_workerThreads)
98 Watchdog.AbortThread(t.ManagedThreadId);
99
100 }
101
63 public Type ReplaceableInterface 102 public Type ReplaceableInterface
64 { 103 {
65 get { return null; } 104 get { return null; }
@@ -75,6 +114,7 @@ namespace OpenSim.Region.ClientStack.Linden
75 // Cap doesn't exist 114 // Cap doesn't exist
76 if (m_URL != string.Empty) 115 if (m_URL != string.Empty)
77 m_Enabled = true; 116 m_Enabled = true;
117
78 } 118 }
79 119
80 public void AddRegion(Scene pScene) 120 public void AddRegion(Scene pScene)
@@ -83,6 +123,8 @@ namespace OpenSim.Region.ClientStack.Linden
83 return; 123 return;
84 124
85 m_scene = pScene; 125 m_scene = pScene;
126
127 m_assetService = pScene.AssetService;
86 } 128 }
87 129
88 public void RemoveRegion(Scene scene) 130 public void RemoveRegion(Scene scene)
@@ -91,6 +133,9 @@ namespace OpenSim.Region.ClientStack.Linden
91 return; 133 return;
92 134
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
136 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
137 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
138
94 m_scene = null; 139 m_scene = null;
95 } 140 }
96 141
@@ -101,6 +146,27 @@ namespace OpenSim.Region.ClientStack.Linden
101 146
102 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 147 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 148 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
149 // We'll reuse the same handler for all requests.
150 m_getMeshHandler = new GetMeshHandler(m_assetService);
151 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
152 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
153
154 if (m_workerThreads == null)
155 {
156 m_workerThreads = new Thread[2];
157
158 for (uint i = 0; i < 2; i++)
159 {
160 m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
161 String.Format("MeshWorkerThread{0}", i),
162 ThreadPriority.Normal,
163 false,
164 false,
165 null,
166 int.MaxValue);
167 }
168 }
169
104 } 170 }
105 171
106 172
@@ -110,25 +176,212 @@ namespace OpenSim.Region.ClientStack.Linden
110 176
111 #endregion 177 #endregion
112 178
179 private void DoMeshRequests()
180 {
181 while (true)
182 {
183 aPollRequest poolreq = m_queue.Dequeue();
184
185 poolreq.thepoll.Process(poolreq);
186 }
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 = ExtractTaskThrottle(throttles);
195 PollServiceMeshEventArgs args;
196 if (m_pollservices.TryGetValue(user, out args))
197 {
198 args.UpdateThrottle(imagethrottle, p);
199 }
200 }
201
202 private int ExtractTaskThrottle(byte[] pthrottles)
203 {
204
205 byte[] adjData;
206 int pos = 0;
207
208 if (!BitConverter.IsLittleEndian)
209 {
210 byte[] newData = new byte[7 * 4];
211 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
212
213 for (int i = 0; i < 7; i++)
214 Array.Reverse(newData, i * 4, 4);
215
216 adjData = newData;
217 }
218 else
219 {
220 adjData = pthrottles;
221 }
222
223 // 0.125f converts from bits to bytes
224 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
225 //pos += 4;
226 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
227 //pos += 4;
228 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
229 // pos += 4;
230 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
231 // pos += 4;
232 pos += 16;
233 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 // pos += 4;
235 //int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
236 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
237 return task;
238 }
239
240 private class PollServiceMeshEventArgs : PollServiceEventArgs
241 {
242 private List<Hashtable> requests =
243 new List<Hashtable>();
244 private Dictionary<UUID, aPollResponse> responses =
245 new Dictionary<UUID, aPollResponse>();
246
247 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue)
251 {
252 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
254 // x is request id, y is userid
255 HasEvents = (x, y) =>
256 {
257 lock (responses)
258 {
259 bool ret = m_throttler.hasEvents(x, responses);
260 m_throttler.ProcessTime();
261 return ret;
262
263 }
264 };
265 GetEvents = (x, y) =>
266 {
267 lock (responses)
268 {
269 try
270 {
271 return responses[x].response;
272 }
273 finally
274 {
275 m_throttler.ProcessTime();
276 responses.Remove(x);
277 }
278 }
279 };
280 // x is request id, y is request data hashtable
281 Request = (x, y) =>
282 {
283 aPollRequest reqinfo = new aPollRequest();
284 reqinfo.thepoll = this;
285 reqinfo.reqID = x;
286 reqinfo.request = y;
287
288 m_queue.Enqueue(reqinfo);
289 };
290
291 // this should never happen except possible on shutdown
292 NoEvents = (x, y) =>
293 {
294 /*
295 lock (requests)
296 {
297 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
298 requests.Remove(request);
299 }
300 */
301 Hashtable response = new Hashtable();
302
303 response["int_response_code"] = 500;
304 response["str_response_string"] = "Script timeout";
305 response["content_type"] = "text/plain";
306 response["keepalive"] = false;
307 response["reusecontext"] = false;
308
309 return response;
310 };
311 }
312
313 public void Process(aPollRequest requestinfo)
314 {
315 Hashtable response;
316
317 UUID requestID = requestinfo.reqID;
318
319 // If the avatar is gone, don't bother to get the texture
320 if (m_scene.GetScenePresence(Id) == null)
321 {
322 response = new Hashtable();
323
324 response["int_response_code"] = 500;
325 response["str_response_string"] = "Script timeout";
326 response["content_type"] = "text/plain";
327 response["keepalive"] = false;
328 response["reusecontext"] = false;
329
330 lock (responses)
331 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
332
333 return;
334 }
335
336 response = m_getMeshHandler.Handle(requestinfo.request);
337 lock (responses)
338 {
339 responses[requestID] = new aPollResponse()
340 {
341 bytes = (int)response["int_bytes"],
342 lod = (int)response["int_lod"],
343 response = response
344 };
345
346 }
347 m_throttler.ProcessTime();
348 }
349
350 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
351 {
352 m_throttler.UpdateThrottle(pimagethrottle, p);
353 }
354 }
113 355
114 public void RegisterCaps(UUID agentID, Caps caps) 356 public void RegisterCaps(UUID agentID, Caps caps)
115 { 357 {
116// UUID capID = UUID.Random(); 358// UUID capID = UUID.Random();
117
118 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
119 if (m_URL == "localhost") 359 if (m_URL == "localhost")
120 { 360 {
121// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 361 string capUrl = "/CAPS/" + UUID.Random() + "/";
122 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); 362
123 IRequestHandler reqHandler 363 // Register this as a poll service
124 = new RestHTTPHandler( 364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
125 "GET", 365
126 "/CAPS/" + UUID.Random(), 366 args.Type = PollServiceEventArgs.EventType.Mesh;
127 httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), 367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
128 "GetMesh", 368
129 agentID.ToString()); 369 string hostName = m_scene.RegionInfo.ExternalHostName;
370 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
371 string protocol = "http";
130 372
131 caps.RegisterHandler("GetMesh", reqHandler); 373 if (MainServer.Instance.UseSSL)
374 {
375 hostName = MainServer.Instance.SSLCommonName;
376 port = MainServer.Instance.SSLPort;
377 protocol = "https";
378 }
379 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
380 m_pollservices[agentID] = args;
381 m_capsDict[agentID] = capUrl;
382
383
384
132 } 385 }
133 else 386 else
134 { 387 {
@@ -136,6 +389,177 @@ namespace OpenSim.Region.ClientStack.Linden
136 caps.RegisterHandler("GetMesh", m_URL); 389 caps.RegisterHandler("GetMesh", m_URL);
137 } 390 }
138 } 391 }
392 private void DeregisterCaps(UUID agentID, Caps caps)
393 {
394 string capUrl;
395 PollServiceMeshEventArgs args;
396 if (m_capsDict.TryGetValue(agentID, out capUrl))
397 {
398 MainServer.Instance.RemoveHTTPHandler("", capUrl);
399 m_capsDict.Remove(agentID);
400 }
401 if (m_pollservices.TryGetValue(agentID, out args))
402 {
403 m_pollservices.Remove(agentID);
404 }
405 }
406
407 internal sealed class MeshCapsDataThrottler
408 {
409
410 private volatile int currenttime = 0;
411 private volatile int lastTimeElapsed = 0;
412 private volatile int BytesSent = 0;
413 private int Lod3 = 0;
414 private int Lod2 = 0;
415 private int Lod1 = 0;
416 private int UserSetThrottle = 0;
417 private int UDPSetThrottle = 0;
418 private int CapSetThrottle = 0;
419 private float CapThrottleDistributon = 0.30f;
420 private readonly Scene m_scene;
421 private ThrottleOutPacketType Throttle;
422 private readonly UUID User;
423
424 public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene, UUID puser)
425 {
426 ThrottleBytes = pBytes;
427 lastTimeElapsed = Util.EnvironmentTickCount();
428 Throttle = ThrottleOutPacketType.Task;
429 m_scene = pScene;
430 User = puser;
431 }
432
433
434 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
435 {
436 const float ThirtyPercent = 0.30f;
437 const float FivePercent = 0.05f;
438 PassTime();
439 // Note, this is called IN LOCK
440 bool haskey = responses.ContainsKey(key);
441
442 if (responses.Count > 2)
443 {
444 SplitThrottle(ThirtyPercent);
445 }
446 else
447 {
448 SplitThrottle(FivePercent);
449 }
450
451 if (!haskey)
452 {
453 return false;
454 }
455 aPollResponse response;
456 if (responses.TryGetValue(key, out response))
457 {
458 float LOD3Over = (((ThrottleBytes*CapThrottleDistributon)%50000) + 1);
459 float LOD2Over = (((ThrottleBytes*CapThrottleDistributon)%10000) + 1);
460 // Normal
461 if (BytesSent + response.bytes <= ThrottleBytes)
462 {
463 BytesSent += response.bytes;
464
465 return true;
466 }
467 // Lod3 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
468 else if (response.bytes > ThrottleBytes && Lod3 <= ((LOD3Over < 1)? 1: LOD3Over) )
469 {
470 Interlocked.Increment(ref Lod3);
471 BytesSent += response.bytes;
472
473 return true;
474 }
475 // Lod2 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
476 else if (response.bytes > ThrottleBytes && Lod2 <= ((LOD2Over < 1) ? 1 : LOD2Over))
477 {
478 Interlocked.Increment(ref Lod2);
479 BytesSent += response.bytes;
480
481 return true;
482 }
483 else
484 {
485 return false;
486 }
487 }
488
489 return haskey;
490 }
491 public void SubtractBytes(int bytes,int lod)
492 {
493 BytesSent -= bytes;
494 }
495 private void SplitThrottle(float percentMultiplier)
496 {
497
498 if (CapThrottleDistributon != percentMultiplier) // don't switch it if it's already set at the % multipler
499 {
500 CapThrottleDistributon = percentMultiplier;
501 ScenePresence p;
502 if (m_scene.TryGetScenePresence(User, out p)) // If we don't get a user they're not here anymore.
503 {
504// AlterThrottle(UserSetThrottle, p);
505 UpdateThrottle(UserSetThrottle, p);
506 }
507 }
508 }
509
510 public void ProcessTime()
511 {
512 PassTime();
513 }
514
515
516 private void PassTime()
517 {
518 currenttime = Util.EnvironmentTickCount();
519 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
520 //processTimeBasedActions(responses);
521 if (currenttime - timeElapsed >= 1000)
522 {
523 lastTimeElapsed = Util.EnvironmentTickCount();
524 BytesSent -= ThrottleBytes;
525 if (BytesSent < 0) BytesSent = 0;
526 if (BytesSent < ThrottleBytes)
527 {
528 Lod3 = 0;
529 Lod2 = 0;
530 Lod1 = 0;
531 }
532 }
533 }
534 private void AlterThrottle(int setting, ScenePresence p)
535 {
536 p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
537 }
538
539 public int ThrottleBytes
540 {
541 get { return CapSetThrottle; }
542 set { CapSetThrottle = value; }
543 }
544
545 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
546 {
547 // Client set throttle !
548 UserSetThrottle = pimagethrottle;
549 CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
550// UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
551
552 float udp = 1.0f - CapThrottleDistributon;
553 if(udp < 0.5f)
554 udp = 0.5f;
555 UDPSetThrottle = (int) ((float)pimagethrottle * udp);
556 if (CapSetThrottle < 4068)
557 CapSetThrottle = 4068; // at least two discovery mesh
558 p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
559 ProcessTime();
560
561 }
562 }
139 563
140 } 564 }
141} 565}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 13415f8..0570144 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,57 +50,137 @@ 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";
64 81
65 // TODO: Change this to a config option 82 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
66 const string REDIRECT_URL = null; 83 new OpenMetaverse.BlockingQueue<aPollRequest>();
67 84
68 private string m_URL; 85 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
69 86
70 #region ISharedRegionModule Members 87 #region ISharedRegionModule Members
71 88
72 public void Initialise(IConfigSource source) 89 public void Initialise(IConfigSource source)
73 { 90 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"]; 91 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null) 92 if (config != null)
76 return; 93 m_Url = config.GetString("Cap_GetTexture", "localhost");
77
78 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist
80 if (m_URL != string.Empty)
81 m_Enabled = true;
82 } 94 }
83 95
84 public void AddRegion(Scene s) 96 public void AddRegion(Scene s)
85 { 97 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 98 m_scene = s;
99 m_assetService = s.AssetService;
90 } 100 }
91 101
92 public void RemoveRegion(Scene s) 102 public void RemoveRegion(Scene s)
93 { 103 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 104 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
105 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
106 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 107 m_scene = null;
99 } 108 }
100 109
101 public void RegionLoaded(Scene s) 110 public void RegionLoaded(Scene s)
102 { 111 {
103 if (!m_Enabled) 112 // We'll reuse the same handler for all requests.
104 return; 113 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 114
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 115 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
116 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
117 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
118
119 if (m_workerThreads == null)
120 {
121 m_workerThreads = new Thread[2];
122
123 for (uint i = 0; i < 2; i++)
124 {
125 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
126 String.Format("TextureWorkerThread{0}", i),
127 ThreadPriority.Normal,
128 false,
129 false,
130 null,
131 int.MaxValue);
132 }
133 }
134 }
135 private int ExtractImageThrottle(byte[] pthrottles)
136 {
137
138 byte[] adjData;
139 int pos = 0;
140
141 if (!BitConverter.IsLittleEndian)
142 {
143 byte[] newData = new byte[7 * 4];
144 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
145
146 for (int i = 0; i < 7; i++)
147 Array.Reverse(newData, i * 4, 4);
148
149 adjData = newData;
150 }
151 else
152 {
153 adjData = pthrottles;
154 }
155
156 // 0.125f converts from bits to bytes
157 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
158 //pos += 4;
159 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
160 //pos += 4;
161 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
162 // pos += 4;
163 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
164 // pos += 4;
165 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
166 // pos += 4;
167 pos = pos + 20;
168 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
169 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
170 return texture;
171 }
172
173 // 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.
174 public void ThrottleUpdate(ScenePresence p)
175 {
176 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
177 UUID user = p.UUID;
178 int imagethrottle = ExtractImageThrottle(throttles);
179 PollServiceTextureEventArgs args;
180 if (m_pollservices.TryGetValue(user,out args))
181 {
182 args.UpdateThrottle(imagethrottle);
183 }
108 } 184 }
109 185
110 public void PostInitialise() 186 public void PostInitialise()
@@ -122,24 +198,288 @@ namespace OpenSim.Region.ClientStack.Linden
122 198
123 #endregion 199 #endregion
124 200
125 public void RegisterCaps(UUID agentID, Caps caps) 201 ~GetTextureModule()
126 { 202 {
127 UUID capID = UUID.Random(); 203 foreach (Thread t in m_workerThreads)
204 Watchdog.AbortThread(t.ManagedThreadId);
205
206 }
207
208 private class PollServiceTextureEventArgs : PollServiceEventArgs
209 {
210 private List<Hashtable> requests =
211 new List<Hashtable>();
212 private Dictionary<UUID, aPollResponse> responses =
213 new Dictionary<UUID, aPollResponse>();
214
215 private Scene m_scene;
216 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
217 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
218 base(null, null, null, null, pId, int.MaxValue)
219 {
220 m_scene = scene;
221 // x is request id, y is userid
222 HasEvents = (x, y) =>
223 {
224 lock (responses)
225 {
226 bool ret = m_throttler.hasEvents(x, responses);
227 m_throttler.ProcessTime();
228 return ret;
229
230 }
231 };
232 GetEvents = (x, y) =>
233 {
234 lock (responses)
235 {
236 try
237 {
238 return responses[x].response;
239 }
240 finally
241 {
242 responses.Remove(x);
243 }
244 }
245 };
246 // x is request id, y is request data hashtable
247 Request = (x, y) =>
248 {
249 aPollRequest reqinfo = new aPollRequest();
250 reqinfo.thepoll = this;
251 reqinfo.reqID = x;
252 reqinfo.request = y;
253 reqinfo.send503 = false;
254
255 lock (responses)
256 {
257 if (responses.Count > 0)
258 {
259 if (m_queue.Count >= 4)
260 {
261 // Never allow more than 4 fetches to wait
262 reqinfo.send503 = true;
263 }
264 }
265 }
266 m_queue.Enqueue(reqinfo);
267 };
268
269 // this should never happen except possible on shutdown
270 NoEvents = (x, y) =>
271 {
272/*
273 lock (requests)
274 {
275 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
276 requests.Remove(request);
277 }
278*/
279 Hashtable response = new Hashtable();
280
281 response["int_response_code"] = 500;
282 response["str_response_string"] = "Script timeout";
283 response["content_type"] = "text/plain";
284 response["keepalive"] = false;
285 response["reusecontext"] = false;
286
287 return response;
288 };
289 }
290
291 public void Process(aPollRequest requestinfo)
292 {
293 Hashtable response;
294
295 UUID requestID = requestinfo.reqID;
296
297 if (requestinfo.send503)
298 {
299 response = new Hashtable();
300
301 response["int_response_code"] = 503;
302 response["str_response_string"] = "Throttled";
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};
128 309
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 310 return;
130 if (m_URL == "localhost") 311 }
312
313 // If the avatar is gone, don't bother to get the texture
314 if (m_scene.GetScenePresence(Id) == null)
315 {
316 response = new Hashtable();
317
318 response["int_response_code"] = 500;
319 response["str_response_string"] = "Script timeout";
320 response["content_type"] = "text/plain";
321 response["keepalive"] = false;
322 response["reusecontext"] = false;
323
324 lock (responses)
325 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
326
327 return;
328 }
329
330 response = m_getTextureHandler.Handle(requestinfo.request);
331 lock (responses)
332 {
333 responses[requestID] = new aPollResponse()
334 {
335 bytes = (int) response["int_bytes"],
336 response = response
337 };
338
339 }
340 m_throttler.ProcessTime();
341 }
342
343 internal void UpdateThrottle(int pimagethrottle)
131 { 344 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 345 m_throttler.ThrottleBytes = pimagethrottle;
133 caps.RegisterHandler( 346 }
134 "GetTexture", 347 }
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 348
349 private void RegisterCaps(UUID agentID, Caps caps)
350 {
351 if (m_Url == "localhost")
352 {
353 string capUrl = "/CAPS/" + UUID.Random() + "/";
354
355 // Register this as a poll service
356 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
357
358 args.Type = PollServiceEventArgs.EventType.Texture;
359 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
360
361 string hostName = m_scene.RegionInfo.ExternalHostName;
362 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
363 string protocol = "http";
364
365 if (MainServer.Instance.UseSSL)
366 {
367 hostName = MainServer.Instance.SSLCommonName;
368 port = MainServer.Instance.SSLPort;
369 protocol = "https";
370 }
371 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
372 m_pollservices[agentID] = args;
373 m_capsDict[agentID] = capUrl;
136 } 374 }
137 else 375 else
138 { 376 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 377 caps.RegisterHandler("GetTexture", m_Url);
140 caps.RegisterHandler("GetTexture", m_URL); 378 }
379 }
380
381 private void DeregisterCaps(UUID agentID, Caps caps)
382 {
383 string capUrl;
384 PollServiceTextureEventArgs args;
385 if (m_capsDict.TryGetValue(agentID, out capUrl))
386 {
387 MainServer.Instance.RemoveHTTPHandler("", capUrl);
388 m_capsDict.Remove(agentID);
389 }
390 if (m_pollservices.TryGetValue(agentID, out args))
391 {
392 m_pollservices.Remove(agentID);
393 }
394 }
395
396 private void DoTextureRequests()
397 {
398 while (true)
399 {
400 aPollRequest poolreq = m_queue.Dequeue();
401
402 poolreq.thepoll.Process(poolreq);
141 } 403 }
142 } 404 }
405 internal sealed class CapsDataThrottler
406 {
143 407
408 private volatile int currenttime = 0;
409 private volatile int lastTimeElapsed = 0;
410 private volatile int BytesSent = 0;
411 private int oversizedImages = 0;
412 public CapsDataThrottler(int pBytes, int max, int min)
413 {
414 ThrottleBytes = pBytes;
415 lastTimeElapsed = Util.EnvironmentTickCount();
416 }
417 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
418 {
419 PassTime();
420 // Note, this is called IN LOCK
421 bool haskey = responses.ContainsKey(key);
422 if (!haskey)
423 {
424 return false;
425 }
426 GetTextureModule.aPollResponse response;
427 if (responses.TryGetValue(key, out response))
428 {
429 // This is any error response
430 if (response.bytes == 0)
431 return true;
432
433 // Normal
434 if (BytesSent + response.bytes <= ThrottleBytes)
435 {
436 BytesSent += response.bytes;
437 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
438 //m_actions.Add(timeBasedAction);
439 return true;
440 }
441 // Big textures
442 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
443 {
444 Interlocked.Increment(ref oversizedImages);
445 BytesSent += response.bytes;
446 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
447 //m_actions.Add(timeBasedAction);
448 return true;
449 }
450 else
451 {
452 return false;
453 }
454 }
455
456 return haskey;
457 }
458
459 public void ProcessTime()
460 {
461 PassTime();
462 }
463
464 private void PassTime()
465 {
466 currenttime = Util.EnvironmentTickCount();
467 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
468 //processTimeBasedActions(responses);
469 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
470 {
471 lastTimeElapsed = Util.EnvironmentTickCount();
472 BytesSent -= ThrottleBytes;
473 if (BytesSent < 0) BytesSent = 0;
474 if (BytesSent < ThrottleBytes)
475 {
476 oversizedImages = 0;
477 }
478 }
479 }
480 public int ThrottleBytes;
481 }
144 } 482 }
483
484
145} 485}
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 69dd76f..79d56c4 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/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 3b0ccd7..eca576d 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -27,6 +27,7 @@
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.Drawing; 32using System.Drawing;
32using System.Drawing.Imaging; 33using System.Drawing.Imaging;
@@ -53,8 +54,8 @@ namespace OpenSim.Region.ClientStack.Linden
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")] 54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")]
54 public class UploadBakedTextureModule : INonSharedRegionModule 55 public class UploadBakedTextureModule : INonSharedRegionModule
55 { 56 {
56// private static readonly ILog m_log = 57 private static readonly ILog m_log =
57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 59
59 /// <summary> 60 /// <summary>
60 /// For historical reasons this is fixed, but there 61 /// For historical reasons this is fixed, but there
@@ -64,31 +65,210 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Scene m_scene; 65 private Scene m_scene;
65 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
66 67
68 private IBakedTextureModule m_BakedTextureModule;
69
67 public void Initialise(IConfigSource source) 70 public void Initialise(IConfigSource source)
68 { 71 {
69 IConfig appearanceConfig = source.Configs["Appearance"]; 72 IConfig appearanceConfig = source.Configs["Appearance"];
70 if (appearanceConfig != null) 73 if (appearanceConfig != null)
71 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
75
76
72 } 77 }
73 78
74 public void AddRegion(Scene s) 79 public void AddRegion(Scene s)
75 { 80 {
76 m_scene = s; 81 m_scene = s;
82
77 } 83 }
78 84
79 public void RemoveRegion(Scene s) 85 public void RemoveRegion(Scene s)
80 { 86 {
87 s.EventManager.OnRegisterCaps -= RegisterCaps;
88 s.EventManager.OnNewPresence -= RegisterNewPresence;
89 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null;
91 m_scene = null;
81 } 92 }
82 93
94
95
83 public void RegionLoaded(Scene s) 96 public void RegionLoaded(Scene s)
84 { 97 {
85 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
99 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
100 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
101
102 }
103
104 private void DeRegisterPresence(UUID agentId)
105 {
106 ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence))
108 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 }
111
112 }
113
114 private void RegisterNewPresence(ScenePresence presence)
115 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 }
119
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
121 {
122 int maxCacheitemsLoop = cacheItems.Length;
123 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
124 {
125 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
126 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
127 }
128
129 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
130 if (cacheItems.Length > 0)
131 {
132 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
133 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
134 {
135 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
136 cacheItems[iter].TextureID);
137 }
138
139 ScenePresence p = null;
140 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
141 {
142
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
144 if (existingitems == null)
145 {
146 if (m_BakedTextureModule != null)
147 {
148 WearableCacheItem[] savedcache = null;
149 try
150 {
151 if (p.Appearance.WearableCacheItemsDirty)
152 {
153 savedcache = m_BakedTextureModule.Get(p.UUID);
154 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false;
156 }
157
158 }
159 /*
160 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
161 * it jumps to the General Packet Exception Handler if you don't catch Exception!
162 *
163 catch (System.Net.Sockets.SocketException)
164 {
165 cacheItems = null;
166 }
167 catch (WebException)
168 {
169 cacheItems = null;
170 }
171 catch (InvalidOperationException)
172 {
173 cacheItems = null;
174 } */
175 catch (Exception)
176 {
177 // The service logs a sufficient error message.
178 }
179
180
181 if (savedcache != null)
182 existingitems = savedcache;
183 }
184 }
185 // Existing items null means it's a fully new appearance
186 if (existingitems == null)
187 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++)
190 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
192 {
193 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
194 if (face == null)
195 {
196 textureEntry.CreateFace(cacheItems[i].TextureIndex);
197 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue;
200 }
201 cacheItems[i].TextureID =face.TextureID;
202 if (m_scene.AssetService != null)
203 cacheItems[i].TextureAsset =
204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
205 }
206 else
207 {
208 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
209 }
210
211
212 }
213 }
214 else
215
216
217 {
218 // for each uploaded baked texture
219 for (int i = 0; i < maxCacheitemsLoop; i++)
220 {
221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
222 {
223 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
224 if (face == null)
225 {
226 textureEntry.CreateFace(cacheItems[i].TextureIndex);
227 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
228 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
229 continue;
230 }
231 cacheItems[i].TextureID =
232 face.TextureID;
233 }
234 else
235 {
236 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
237 }
238 }
239
240 for (int i = 0; i < maxCacheitemsLoop; i++)
241 {
242 if (cacheItems[i].TextureAsset == null)
243 {
244 cacheItems[i].TextureAsset =
245 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
246 }
247 }
248 }
249
250
251
252 p.Appearance.WearableCacheItems = cacheItems;
253
254
255
256 if (m_BakedTextureModule != null)
257 {
258 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
259 p.Appearance.WearableCacheItemsDirty = true;
260
261 }
262 }
263 }
86 } 264 }
87 265
88 public void PostInitialise() 266 public void PostInitialise()
89 { 267 {
90 } 268 }
91 269
270
271
92 public void Close() { } 272 public void Close() { }
93 273
94 public string Name { get { return "UploadBakedTextureModule"; } } 274 public string Name { get { return "UploadBakedTextureModule"; } }
@@ -100,15 +280,23 @@ namespace OpenSim.Region.ClientStack.Linden
100 280
101 public void RegisterCaps(UUID agentID, Caps caps) 281 public void RegisterCaps(UUID agentID, Caps caps)
102 { 282 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
284 caps, m_scene.AssetService, m_persistBakedTextures);
285
286
287
103 caps.RegisterHandler( 288 caps.RegisterHandler(
104 "UploadBakedTexture", 289 "UploadBakedTexture",
105 new RestStreamHandler( 290 new RestStreamHandler(
106 "POST", 291 "POST",
107 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, 292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
108 new UploadBakedTextureHandler( 293 avatarhandler.UploadBakedTexture,
109 caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
110 "UploadBakedTexture", 294 "UploadBakedTexture",
111 agentID.ToString())); 295 agentID.ToString()));
296
297
298
299
112 } 300 }
113 } 301 }
114} \ No newline at end of file 302} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 6890f4a..707cc93 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -27,18 +27,25 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
32using System.Threading;
31using log4net; 33using log4net;
32using Nini.Config; 34using Nini.Config;
33using Mono.Addins; 35using Mono.Addins;
34using OpenMetaverse; 36using OpenMetaverse;
35using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Servers;
36using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Framework.Capabilities;
39using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
40using Caps = OpenSim.Framework.Capabilities.Caps; 44using Caps = OpenSim.Framework.Capabilities.Caps;
41using OpenSim.Capabilities.Handlers; 45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47using OpenMetaverse;
48using OpenMetaverse.StructuredData;
42 49
43namespace OpenSim.Region.ClientStack.Linden 50namespace OpenSim.Region.ClientStack.Linden
44{ 51{
@@ -48,67 +55,74 @@ namespace OpenSim.Region.ClientStack.Linden
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")]
49 public class WebFetchInvDescModule : INonSharedRegionModule 56 public class WebFetchInvDescModule : INonSharedRegionModule
50 { 57 {
51// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 class aPollRequest
59 {
60 public PollServiceInventoryEventArgs thepoll;
61 public UUID reqID;
62 public Hashtable request;
63 public ScenePresence presence;
64 public List<UUID> folders;
65 }
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 68
53 private Scene m_scene; 69 private Scene m_scene;
54 70
55 private IInventoryService m_InventoryService; 71 private IInventoryService m_InventoryService;
56 private ILibraryService m_LibraryService; 72 private ILibraryService m_LibraryService;
57 73
58 private bool m_Enabled; 74 private static WebFetchInvDescHandler m_webFetchHandler;
59 75
60 private string m_fetchInventoryDescendents2Url; 76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
61 private string m_webFetchInventoryDescendentsUrl; 77 private static Thread[] m_workerThreads = null;
62 78
63 private WebFetchInvDescHandler m_webFetchHandler; 79 private static DoubleQueue<aPollRequest> m_queue =
80 new DoubleQueue<aPollRequest>();
64 81
65 #region ISharedRegionModule Members 82 #region ISharedRegionModule Members
66 83
67 public void Initialise(IConfigSource source) 84 public void Initialise(IConfigSource source)
68 { 85 {
69 IConfig config = source.Configs["ClientStack.LindenCaps"];
70 if (config == null)
71 return;
72
73 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
74 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
75
76 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
77 {
78 m_Enabled = true;
79 }
80 } 86 }
81 87
82 public void AddRegion(Scene s) 88 public void AddRegion(Scene s)
83 { 89 {
84 if (!m_Enabled)
85 return;
86
87 m_scene = s; 90 m_scene = s;
88 } 91 }
89 92
90 public void RemoveRegion(Scene s) 93 public void RemoveRegion(Scene s)
91 { 94 {
92 if (!m_Enabled)
93 return;
94
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
96 m_scene = null; 97 m_scene = null;
97 } 98 }
98 99
99 public void RegionLoaded(Scene s) 100 public void RegionLoaded(Scene s)
100 { 101 {
101 if (!m_Enabled)
102 return;
103
104 m_InventoryService = m_scene.InventoryService; 102 m_InventoryService = m_scene.InventoryService;
105 m_LibraryService = m_scene.LibraryService; 103 m_LibraryService = m_scene.LibraryService;
106 104
107 // We'll reuse the same handler for all requests. 105 // We'll reuse the same handler for all requests.
108 if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost") 106 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
109 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
110 107
111 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 108 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
109 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
110
111 if (m_workerThreads == null)
112 {
113 m_workerThreads = new Thread[2];
114
115 for (uint i = 0; i < 2; i++)
116 {
117 m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests,
118 String.Format("InventoryWorkerThread{0}", i),
119 ThreadPriority.Normal,
120 false,
121 true,
122 null,
123 int.MaxValue);
124 }
125 }
112 } 126 }
113 127
114 public void PostInitialise() 128 public void PostInitialise()
@@ -126,43 +140,192 @@ namespace OpenSim.Region.ClientStack.Linden
126 140
127 #endregion 141 #endregion
128 142
129 private void RegisterCaps(UUID agentID, Caps caps) 143 ~WebFetchInvDescModule()
130 { 144 {
131 if (m_webFetchInventoryDescendentsUrl != "") 145 foreach (Thread t in m_workerThreads)
132 RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl); 146 Watchdog.AbortThread(t.ManagedThreadId);
133
134 if (m_fetchInventoryDescendents2Url != "")
135 RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
136 } 147 }
137 148
138 private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) 149 private class PollServiceInventoryEventArgs : PollServiceEventArgs
139 { 150 {
140 string capUrl; 151 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
152
153 private Dictionary<UUID, Hashtable> responses =
154 new Dictionary<UUID, Hashtable>();
155
156 private Scene m_scene;
141 157
142 if (url == "localhost") 158 public PollServiceInventoryEventArgs(Scene scene, UUID pId) :
159 base(null, null, null, null, pId, int.MaxValue)
143 { 160 {
144 capUrl = "/CAPS/" + UUID.Random(); 161 m_scene = scene;
162
163 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
164 GetEvents = (x, y) =>
165 {
166 lock (responses)
167 {
168 try
169 {
170 return responses[x];
171 }
172 finally
173 {
174 responses.Remove(x);
175 }
176 }
177 };
178
179 Request = (x, y) =>
180 {
181 ScenePresence sp = m_scene.GetScenePresence(Id);
182 if (sp == null)
183 {
184 m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id);
185 return;
186 }
187
188 aPollRequest reqinfo = new aPollRequest();
189 reqinfo.thepoll = this;
190 reqinfo.reqID = x;
191 reqinfo.request = y;
192 reqinfo.presence = sp;
193 reqinfo.folders = new List<UUID>();
194
195 // Decode the request here
196 string request = y["body"].ToString();
197
198 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
199
200 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
201 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
202
203 Hashtable hash = new Hashtable();
204 try
205 {
206 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
207 }
208 catch (LLSD.LLSDParseException e)
209 {
210 m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
211 m_log.Error("Request: " + request);
212 return;
213 }
214 catch (System.Xml.XmlException)
215 {
216 m_log.ErrorFormat("[INVENTORY]: XML Format error");
217 }
218
219 ArrayList foldersrequested = (ArrayList)hash["folders"];
220
221 bool highPriority = false;
222
223 for (int i = 0; i < foldersrequested.Count; i++)
224 {
225 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
226 string folder = inventoryhash["folder_id"].ToString();
227 UUID folderID;
228 if (UUID.TryParse(folder, out folderID))
229 {
230 if (!reqinfo.folders.Contains(folderID))
231 {
232 if (sp.COF != UUID.Zero && sp.COF == folderID)
233 highPriority = true;
234 reqinfo.folders.Add(folderID);
235 }
236 }
237 }
238
239 if (highPriority)
240 m_queue.EnqueueHigh(reqinfo);
241 else
242 m_queue.EnqueueLow(reqinfo);
243 };
244
245 NoEvents = (x, y) =>
246 {
247/*
248 lock (requests)
249 {
250 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
251 requests.Remove(request);
252 }
253*/
254 Hashtable response = new Hashtable();
255
256 response["int_response_code"] = 500;
257 response["str_response_string"] = "Script timeout";
258 response["content_type"] = "text/plain";
259 response["keepalive"] = false;
260 response["reusecontext"] = false;
261
262 return response;
263 };
264 }
145 265
146 IRequestHandler reqHandler 266 public void Process(aPollRequest requestinfo)
147 = new RestStreamHandler( 267 {
148 "POST", 268 UUID requestID = requestinfo.reqID;
149 capUrl, 269
150 m_webFetchHandler.FetchInventoryDescendentsRequest, 270 Hashtable response = new Hashtable();
151 "FetchInventoryDescendents2", 271
152 agentID.ToString()); 272 response["int_response_code"] = 200;
273 response["content_type"] = "text/plain";
274 response["keepalive"] = false;
275 response["reusecontext"] = false;
153 276
154 caps.RegisterHandler(capName, reqHandler); 277 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
278 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
279
280 lock (responses)
281 responses[requestID] = response;
155 } 282 }
156 else 283 }
284
285 private void RegisterCaps(UUID agentID, Caps caps)
286 {
287 string capUrl = "/CAPS/" + UUID.Random() + "/";
288
289 // Register this as a poll service
290 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
291
292 args.Type = PollServiceEventArgs.EventType.Inventory;
293 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
294
295 string hostName = m_scene.RegionInfo.ExternalHostName;
296 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
297 string protocol = "http";
298
299 if (MainServer.Instance.UseSSL)
157 { 300 {
158 capUrl = url; 301 hostName = MainServer.Instance.SSLCommonName;
302 port = MainServer.Instance.SSLPort;
303 protocol = "https";
304 }
305 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
306
307 m_capsDict[agentID] = capUrl;
308 }
159 309
160 caps.RegisterHandler(capName, capUrl); 310 private void DeregisterCaps(UUID agentID, Caps caps)
311 {
312 string capUrl;
313
314 if (m_capsDict.TryGetValue(agentID, out capUrl))
315 {
316 MainServer.Instance.RemoveHTTPHandler("", capUrl);
317 m_capsDict.Remove(agentID);
161 } 318 }
319 }
162 320
163// m_log.DebugFormat( 321 private void DoInventoryRequests()
164// "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}", 322 {
165// capName, capUrl, m_scene.RegionInfo.RegionName, agentID); 323 while (true)
324 {
325 aPollRequest poolreq = m_queue.Dequeue();
326
327 poolreq.thepoll.Process(poolreq);
328 }
166 } 329 }
167 } 330 }
168} \ No newline at end of file 331}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index afbe56b..3995620 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 110e50e..7c62f90 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;
@@ -160,6 +162,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
160 public event RequestTaskInventory OnRequestTaskInventory; 162 public event RequestTaskInventory OnRequestTaskInventory;
161 public event UpdateInventoryItem OnUpdateInventoryItem; 163 public event UpdateInventoryItem OnUpdateInventoryItem;
162 public event CopyInventoryItem OnCopyInventoryItem; 164 public event CopyInventoryItem OnCopyInventoryItem;
165 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
163 public event MoveInventoryItem OnMoveInventoryItem; 166 public event MoveInventoryItem OnMoveInventoryItem;
164 public event RemoveInventoryItem OnRemoveInventoryItem; 167 public event RemoveInventoryItem OnRemoveInventoryItem;
165 public event RemoveInventoryFolder OnRemoveInventoryFolder; 168 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -258,7 +261,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
258 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 261 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
259 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 262 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
260 public event ClassifiedDelete OnClassifiedDelete; 263 public event ClassifiedDelete OnClassifiedDelete;
261 public event ClassifiedDelete OnClassifiedGodDelete; 264 public event ClassifiedGodDelete OnClassifiedGodDelete;
262 public event EventNotificationAddRequest OnEventNotificationAddRequest; 265 public event EventNotificationAddRequest OnEventNotificationAddRequest;
263 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 266 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
264 public event EventGodDelete OnEventGodDelete; 267 public event EventGodDelete OnEventGodDelete;
@@ -289,10 +292,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
289 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 292 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
290 public event SimWideDeletesDelegate OnSimWideDeletes; 293 public event SimWideDeletesDelegate OnSimWideDeletes;
291 public event SendPostcard OnSendPostcard; 294 public event SendPostcard OnSendPostcard;
295 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
292 public event MuteListEntryUpdate OnUpdateMuteListEntry; 296 public event MuteListEntryUpdate OnUpdateMuteListEntry;
293 public event MuteListEntryRemove OnRemoveMuteListEntry; 297 public event MuteListEntryRemove OnRemoveMuteListEntry;
294 public event GodlikeMessage onGodlikeMessage; 298 public event GodlikeMessage onGodlikeMessage;
295 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 299 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
300 public event GenericCall2 OnUpdateThrottles;
296 301
297 #endregion Events 302 #endregion Events
298 303
@@ -327,6 +332,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
327 private Prioritizer m_prioritizer; 332 private Prioritizer m_prioritizer;
328 private bool m_disableFacelights = false; 333 private bool m_disableFacelights = false;
329 334
335 private bool m_VelocityInterpolate = false;
336 private const uint MaxTransferBytesPerPacket = 600;
337
338
330 /// <value> 339 /// <value>
331 /// List used in construction of data blocks for an object update packet. This is to stop us having to 340 /// List used in construction of data blocks for an object update packet. This is to stop us having to
332 /// continually recreate it. 341 /// continually recreate it.
@@ -338,14 +347,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
338 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 347 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
339 /// ownerless phantom. 348 /// ownerless phantom.
340 /// 349 ///
341 /// All manipulation of this set has to occur under a lock 350 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
342 /// 351 ///
343 /// </value> 352 /// </value>
344 protected HashSet<uint> m_killRecord; 353// protected HashSet<uint> m_killRecord;
345 354
346// protected HashSet<uint> m_attachmentsSent; 355// protected HashSet<uint> m_attachmentsSent;
347 356
348 private int m_moneyBalance; 357 private bool m_deliverPackets = true;
349 private int m_animationSequenceNumber = 1; 358 private int m_animationSequenceNumber = 1;
350 private bool m_SendLogoutPacketWhenClosing = true; 359 private bool m_SendLogoutPacketWhenClosing = true;
351 360
@@ -392,6 +401,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
392 get { return m_startpos; } 401 get { return m_startpos; }
393 set { m_startpos = value; } 402 set { m_startpos = value; }
394 } 403 }
404 public bool DeliverPackets
405 {
406 get { return m_deliverPackets; }
407 set {
408 m_deliverPackets = value;
409 m_udpClient.m_deliverPackets = value;
410 }
411 }
395 public UUID AgentId { get { return m_agentId; } } 412 public UUID AgentId { get { return m_agentId; } }
396 public ISceneAgent SceneAgent { get; set; } 413 public ISceneAgent SceneAgent { get; set; }
397 public UUID ActiveGroupId { get { return m_activeGroupID; } } 414 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -420,7 +437,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
420 public string Name { get { return FirstName + " " + LastName; } } 437 public string Name { get { return FirstName + " " + LastName; } }
421 438
422 public uint CircuitCode { get { return m_circuitCode; } } 439 public uint CircuitCode { get { return m_circuitCode; } }
423 public int MoneyBalance { get { return m_moneyBalance; } }
424 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 440 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } }
425 441
426 /// <summary> 442 /// <summary>
@@ -443,6 +459,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
443 } 459 }
444 460
445 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 461 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
462
446 463
447 #endregion Properties 464 #endregion Properties
448 465
@@ -469,7 +486,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
469 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 486 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
470 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 487 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
471 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 488 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
472 m_killRecord = new HashSet<uint>(); 489// m_killRecord = new HashSet<uint>();
473// m_attachmentsSent = new HashSet<uint>(); 490// m_attachmentsSent = new HashSet<uint>();
474 491
475 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 492 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -483,7 +500,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
483 m_firstName = sessionInfo.LoginInfo.First; 500 m_firstName = sessionInfo.LoginInfo.First;
484 m_lastName = sessionInfo.LoginInfo.Last; 501 m_lastName = sessionInfo.LoginInfo.Last;
485 m_startpos = sessionInfo.LoginInfo.StartPos; 502 m_startpos = sessionInfo.LoginInfo.StartPos;
486 m_moneyBalance = 1000;
487 503
488 m_udpServer = udpServer; 504 m_udpServer = udpServer;
489 m_udpClient = udpClient; 505 m_udpClient = udpClient;
@@ -499,12 +515,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
499 515
500 #region Client Methods 516 #region Client Methods
501 517
518
519 /// <summary>
520 /// Close down the client view
521 /// </summary>
502 public void Close() 522 public void Close()
503 { 523 {
504 Close(false); 524 Close(true, false);
505 } 525 }
506 526
507 public void Close(bool force) 527 public void Close(bool sendStop, bool force)
508 { 528 {
509 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 529 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
510 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 530 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -516,7 +536,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
516 return; 536 return;
517 537
518 IsActive = false; 538 IsActive = false;
519 CloseWithoutChecks(); 539 CloseWithoutChecks(sendStop);
520 } 540 }
521 } 541 }
522 542
@@ -529,12 +549,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
529 /// 549 ///
530 /// Callers must lock ClosingSyncLock before calling. 550 /// Callers must lock ClosingSyncLock before calling.
531 /// </remarks> 551 /// </remarks>
532 public void CloseWithoutChecks() 552 public void CloseWithoutChecks(bool sendStop)
533 { 553 {
534 m_log.DebugFormat( 554 m_log.DebugFormat(
535 "[CLIENT]: Close has been called for {0} attached to scene {1}", 555 "[CLIENT]: Close has been called for {0} attached to scene {1}",
536 Name, m_scene.RegionInfo.RegionName); 556 Name, m_scene.RegionInfo.RegionName);
537 557
558 if (sendStop)
559 {
560 // Send the STOP packet
561 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
562 OutPacket(disable, ThrottleOutPacketType.Unknown);
563 }
564
538 // Shutdown the image manager 565 // Shutdown the image manager
539 ImageManager.Close(); 566 ImageManager.Close();
540 567
@@ -557,6 +584,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
557 // Disable UDP handling for this client 584 // Disable UDP handling for this client
558 m_udpClient.Shutdown(); 585 m_udpClient.Shutdown();
559 586
587
560 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 588 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
561 //GC.Collect(); 589 //GC.Collect();
562 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 590 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -791,9 +819,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
791 handshake.RegionInfo3.ColoName = Utils.EmptyBytes; 819 handshake.RegionInfo3.ColoName = Utils.EmptyBytes;
792 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 820 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
793 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 821 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
822
794 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 823 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0];
795 824// OutPacket(handshake, ThrottleOutPacketType.Task);
796 OutPacket(handshake, ThrottleOutPacketType.Task); 825 // use same as MoveAgentIntoRegion (both should be task )
826 OutPacket(handshake, ThrottleOutPacketType.Unknown);
797 } 827 }
798 828
799 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 829 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
@@ -833,7 +863,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
833 reply.ChatData.OwnerID = ownerID; 863 reply.ChatData.OwnerID = ownerID;
834 reply.ChatData.SourceID = fromAgentID; 864 reply.ChatData.SourceID = fromAgentID;
835 865
836 OutPacket(reply, ThrottleOutPacketType.Task); 866 OutPacket(reply, ThrottleOutPacketType.Unknown);
837 } 867 }
838 868
839 /// <summary> 869 /// <summary>
@@ -866,38 +896,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
866 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 896 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
867 msg.MessageBlock.BinaryBucket = im.binaryBucket; 897 msg.MessageBlock.BinaryBucket = im.binaryBucket;
868 898
869 if (im.message.StartsWith("[grouptest]")) 899 OutPacket(msg, ThrottleOutPacketType.Task);
870 { // this block is test code for implementing group IM - delete when group IM is finished
871 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
872 if (eq != null)
873 {
874 im.dialog = 17;
875
876 //eq.ChatterboxInvitation(
877 // new UUID("00000000-68f9-1111-024e-222222111123"),
878 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
879 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
880
881 eq.ChatterboxInvitation(
882 new UUID("00000000-68f9-1111-024e-222222111123"),
883 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
884 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
885
886 eq.ChatterBoxSessionAgentListUpdates(
887 new UUID("00000000-68f9-1111-024e-222222111123"),
888 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
889 }
890
891 Console.WriteLine("SendInstantMessage: " + msg);
892 }
893 else
894 OutPacket(msg, ThrottleOutPacketType.Task);
895 } 900 }
896 } 901 }
897 902
898 public void SendGenericMessage(string method, List<string> message) 903 public void SendGenericMessage(string method, UUID invoice, List<string> message)
899 { 904 {
900 GenericMessagePacket gmp = new GenericMessagePacket(); 905 GenericMessagePacket gmp = new GenericMessagePacket();
906
907 gmp.AgentData.AgentID = AgentId;
908 gmp.AgentData.SessionID = m_sessionId;
909 gmp.AgentData.TransactionID = invoice;
910
901 gmp.MethodData.Method = Util.StringToBytes256(method); 911 gmp.MethodData.Method = Util.StringToBytes256(method);
902 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; 912 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
903 int i = 0; 913 int i = 0;
@@ -910,9 +920,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
910 OutPacket(gmp, ThrottleOutPacketType.Task); 920 OutPacket(gmp, ThrottleOutPacketType.Task);
911 } 921 }
912 922
913 public void SendGenericMessage(string method, List<byte[]> message) 923 public void SendGenericMessage(string method, UUID invoice, List<byte[]> message)
914 { 924 {
915 GenericMessagePacket gmp = new GenericMessagePacket(); 925 GenericMessagePacket gmp = new GenericMessagePacket();
926
927 gmp.AgentData.AgentID = AgentId;
928 gmp.AgentData.SessionID = m_sessionId;
929 gmp.AgentData.TransactionID = invoice;
930
916 gmp.MethodData.Method = Util.StringToBytes256(method); 931 gmp.MethodData.Method = Util.StringToBytes256(method);
917 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; 932 gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count];
918 int i = 0; 933 int i = 0;
@@ -1119,6 +1134,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1119 public virtual void SendLayerData(float[] map) 1134 public virtual void SendLayerData(float[] map)
1120 { 1135 {
1121 Util.FireAndForget(DoSendLayerData, map); 1136 Util.FireAndForget(DoSendLayerData, map);
1137
1138 // Send it sync, and async. It's not that much data
1139 // and it improves user experience just so much!
1140 DoSendLayerData(map);
1122 } 1141 }
1123 1142
1124 /// <summary> 1143 /// <summary>
@@ -1131,16 +1150,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1131 1150
1132 try 1151 try
1133 { 1152 {
1134 //for (int y = 0; y < 16; y++) 1153 for (int y = 0; y < 16; y++)
1135 //{ 1154 {
1136 // for (int x = 0; x < 16; x++) 1155 for (int x = 0; x < 16; x+=4)
1137 // { 1156 {
1138 // SendLayerData(x, y, map); 1157 SendLayerPacket(x, y, map);
1139 // } 1158 }
1140 //} 1159 }
1141
1142 // Send LayerData in a spiral pattern. Fun!
1143 SendLayerTopRight(map, 0, 0, 15, 15);
1144 } 1160 }
1145 catch (Exception e) 1161 catch (Exception e)
1146 { 1162 {
@@ -1148,51 +1164,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1148 } 1164 }
1149 } 1165 }
1150 1166
1151 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1152 {
1153 // Row
1154 for (int i = x1; i <= x2; i++)
1155 SendLayerData(i, y1, map);
1156
1157 // Column
1158 for (int j = y1 + 1; j <= y2; j++)
1159 SendLayerData(x2, j, map);
1160
1161 if (x2 - x1 > 0)
1162 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1163 }
1164
1165 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1166 {
1167 // Row in reverse
1168 for (int i = x2; i >= x1; i--)
1169 SendLayerData(i, y2, map);
1170
1171 // Column in reverse
1172 for (int j = y2 - 1; j >= y1; j--)
1173 SendLayerData(x1, j, map);
1174
1175 if (x2 - x1 > 0)
1176 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1177 }
1178
1179 /// <summary> 1167 /// <summary>
1180 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1168 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1181 /// </summary> 1169 /// </summary>
1182 /// <param name="map">heightmap</param> 1170 /// <param name="map">heightmap</param>
1183 /// <param name="px">X coordinate for patches 0..12</param> 1171 /// <param name="px">X coordinate for patches 0..12</param>
1184 /// <param name="py">Y coordinate for patches 0..15</param> 1172 /// <param name="py">Y coordinate for patches 0..15</param>
1185 // private void SendLayerPacket(float[] map, int y, int x) 1173 private void SendLayerPacket(int x, int y, float[] map)
1186 // { 1174 {
1187 // int[] patches = new int[4]; 1175 int[] patches = new int[4];
1188 // patches[0] = x + 0 + y * 16; 1176 patches[0] = x + 0 + y * 16;
1189 // patches[1] = x + 1 + y * 16; 1177 patches[1] = x + 1 + y * 16;
1190 // patches[2] = x + 2 + y * 16; 1178 patches[2] = x + 2 + y * 16;
1191 // patches[3] = x + 3 + y * 16; 1179 patches[3] = x + 3 + y * 16;
1192 1180
1193 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1181 float[] heightmap = (map.Length == 65536) ?
1194 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1182 map :
1195 // } 1183 LLHeightFieldMoronize(map);
1184
1185 try
1186 {
1187 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1188 OutPacket(layerpack, ThrottleOutPacketType.Land);
1189 }
1190 catch
1191 {
1192 for (int px = x ; px < x + 4 ; px++)
1193 SendLayerData(px, y, map);
1194 }
1195 }
1196 1196
1197 /// <summary> 1197 /// <summary>
1198 /// Sends a specified patch to a client 1198 /// Sends a specified patch to a client
@@ -1212,7 +1212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1212 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1212 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1213 layerpack.Header.Reliable = true; 1213 layerpack.Header.Reliable = true;
1214 1214
1215 OutPacket(layerpack, ThrottleOutPacketType.Land); 1215 OutPacket(layerpack, ThrottleOutPacketType.Task);
1216 } 1216 }
1217 catch (Exception e) 1217 catch (Exception e)
1218 { 1218 {
@@ -1523,7 +1523,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1523 OutPacket(tpProgress, ThrottleOutPacketType.Unknown); 1523 OutPacket(tpProgress, ThrottleOutPacketType.Unknown);
1524 } 1524 }
1525 1525
1526 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) 1526 public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item)
1527 { 1527 {
1528 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply); 1528 MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply);
1529 money.MoneyData.AgentID = AgentId; 1529 money.MoneyData.AgentID = AgentId;
@@ -1531,7 +1531,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1531 money.MoneyData.TransactionSuccess = success; 1531 money.MoneyData.TransactionSuccess = success;
1532 money.MoneyData.Description = description; 1532 money.MoneyData.Description = description;
1533 money.MoneyData.MoneyBalance = balance; 1533 money.MoneyData.MoneyBalance = balance;
1534 money.TransactionInfo.ItemDescription = Util.StringToBytes256("NONE"); 1534 money.TransactionInfo.TransactionType = transactionType;
1535 money.TransactionInfo.SourceID = sourceID;
1536 money.TransactionInfo.IsSourceGroup = sourceIsGroup;
1537 money.TransactionInfo.DestID = destID;
1538 money.TransactionInfo.IsDestGroup = destIsGroup;
1539 money.TransactionInfo.Amount = amount;
1540 money.TransactionInfo.ItemDescription = Util.StringToBytes256(item);
1541
1535 OutPacket(money, ThrottleOutPacketType.Task); 1542 OutPacket(money, ThrottleOutPacketType.Task);
1536 } 1543 }
1537 1544
@@ -1575,7 +1582,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1575 1582
1576 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1583 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1577 { 1584 {
1578// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1585// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1579 1587
1580 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1588 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1581 // TODO: don't create new blocks if recycling an old packet 1589 // TODO: don't create new blocks if recycling an old packet
@@ -1597,17 +1605,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1597 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1605 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1598 // condition where a kill can be processed before an out-of-date update for the same object. 1606 // condition where a kill can be processed before an out-of-date update for the same object.
1599 // ProcessEntityUpdates() also takes the m_killRecord lock. 1607 // ProcessEntityUpdates() also takes the m_killRecord lock.
1600 lock (m_killRecord) 1608// lock (m_killRecord)
1601 { 1609// {
1602 foreach (uint localID in localIDs) 1610// foreach (uint localID in localIDs)
1603 m_killRecord.Add(localID); 1611// m_killRecord.Add(localID);
1604 1612
1605 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1613 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1606 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1614 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1607 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1615 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1608 // scene objects in a viewer until that viewer is relogged in. 1616 // scene objects in a viewer until that viewer is relogged in.
1609 OutPacket(kill, ThrottleOutPacketType.Task); 1617 OutPacket(kill, ThrottleOutPacketType.Task);
1610 } 1618// }
1611 } 1619 }
1612 } 1620 }
1613 1621
@@ -1729,7 +1737,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1729 newBlock.CreationDate = item.CreationDate; 1737 newBlock.CreationDate = item.CreationDate;
1730 newBlock.SalePrice = item.SalePrice; 1738 newBlock.SalePrice = item.SalePrice;
1731 newBlock.SaleType = item.SaleType; 1739 newBlock.SaleType = item.SaleType;
1732 newBlock.Flags = item.Flags; 1740 newBlock.Flags = item.Flags & 0xff;
1733 1741
1734 newBlock.CRC = 1742 newBlock.CRC =
1735 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, 1743 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
@@ -1983,7 +1991,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1983 itemBlock.GroupID = item.GroupID; 1991 itemBlock.GroupID = item.GroupID;
1984 itemBlock.GroupOwned = item.GroupOwned; 1992 itemBlock.GroupOwned = item.GroupOwned;
1985 itemBlock.GroupMask = item.GroupPermissions; 1993 itemBlock.GroupMask = item.GroupPermissions;
1986 itemBlock.Flags = item.Flags; 1994 itemBlock.Flags = item.Flags & 0xff;
1987 itemBlock.SalePrice = item.SalePrice; 1995 itemBlock.SalePrice = item.SalePrice;
1988 itemBlock.SaleType = item.SaleType; 1996 itemBlock.SaleType = item.SaleType;
1989 itemBlock.CreationDate = item.CreationDate; 1997 itemBlock.CreationDate = item.CreationDate;
@@ -2050,7 +2058,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2050 bulkUpdate.ItemData[0].GroupID = item.GroupID; 2058 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2051 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; 2059 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2052 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; 2060 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2053 bulkUpdate.ItemData[0].Flags = item.Flags; 2061 bulkUpdate.ItemData[0].Flags = item.Flags & 0xff;
2054 bulkUpdate.ItemData[0].SalePrice = item.SalePrice; 2062 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2055 bulkUpdate.ItemData[0].SaleType = item.SaleType; 2063 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2056 2064
@@ -2066,9 +2074,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2066 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2074 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2067 } 2075 }
2068 2076
2069 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2070 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2077 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2071 { 2078 {
2079 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2080 }
2081
2082 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2083 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2084 {
2072 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2085 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2073 2086
2074 UpdateCreateInventoryItemPacket InventoryReply 2087 UpdateCreateInventoryItemPacket InventoryReply
@@ -2078,6 +2091,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2078 // TODO: don't create new blocks if recycling an old packet 2091 // TODO: don't create new blocks if recycling an old packet
2079 InventoryReply.AgentData.AgentID = AgentId; 2092 InventoryReply.AgentData.AgentID = AgentId;
2080 InventoryReply.AgentData.SimApproved = true; 2093 InventoryReply.AgentData.SimApproved = true;
2094 InventoryReply.AgentData.TransactionID = transactionID;
2081 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2095 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2082 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2096 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2083 InventoryReply.InventoryData[0].ItemID = Item.ID; 2097 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2098,7 +2112,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2098 InventoryReply.InventoryData[0].GroupID = Item.GroupID; 2112 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2099 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; 2113 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2100 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; 2114 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2101 InventoryReply.InventoryData[0].Flags = Item.Flags; 2115 InventoryReply.InventoryData[0].Flags = Item.Flags & 0xff;
2102 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; 2116 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2103 InventoryReply.InventoryData[0].SaleType = Item.SaleType; 2117 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2104 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; 2118 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
@@ -2147,16 +2161,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2147 replytask.InventoryData.TaskID = taskID; 2161 replytask.InventoryData.TaskID = taskID;
2148 replytask.InventoryData.Serial = serial; 2162 replytask.InventoryData.Serial = serial;
2149 replytask.InventoryData.Filename = fileName; 2163 replytask.InventoryData.Filename = fileName;
2150 OutPacket(replytask, ThrottleOutPacketType.Asset); 2164 OutPacket(replytask, ThrottleOutPacketType.Task);
2151 } 2165 }
2152 2166
2153 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2167 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2154 { 2168 {
2169 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2170 if (isTaskInventory)
2171 type = ThrottleOutPacketType.Task;
2172
2155 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2173 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2156 sendXfer.XferID.ID = xferID; 2174 sendXfer.XferID.ID = xferID;
2157 sendXfer.XferID.Packet = packet; 2175 sendXfer.XferID.Packet = packet;
2158 sendXfer.DataPacket.Data = data; 2176 sendXfer.DataPacket.Data = data;
2159 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2177 OutPacket(sendXfer, type);
2160 } 2178 }
2161 2179
2162 public void SendAbortXferPacket(ulong xferID) 2180 public void SendAbortXferPacket(ulong xferID)
@@ -2215,9 +2233,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2215 2233
2216 public void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) 2234 public void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle)
2217 { 2235 {
2218 m_activeGroupID = activegroupid; 2236 if (agentid == AgentId)
2219 m_activeGroupName = groupname; 2237 {
2220 m_activeGroupPowers = grouppowers; 2238 m_activeGroupID = activegroupid;
2239 m_activeGroupName = groupname;
2240 m_activeGroupPowers = grouppowers;
2241 }
2221 2242
2222 AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate); 2243 AgentDataUpdatePacket sendAgentDataUpdate = (AgentDataUpdatePacket)PacketPool.Instance.GetPacket(PacketType.AgentDataUpdate);
2223 sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid; 2244 sendAgentDataUpdate.AgentData.ActiveGroupID = activegroupid;
@@ -2264,6 +2285,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2264 /// <returns></returns> 2285 /// <returns></returns>
2265 public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal) 2286 public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal)
2266 { 2287 {
2288 // Prepend a slash to make the message come up in the top right
2289 // again.
2290 // Allow special formats to be sent from aware modules.
2291 if (!modal && !message.StartsWith("ALERT: ") && !message.StartsWith("NOTIFY: ") && message != "Home position set." && message != "You died and have been teleported to your home location")
2292 message = "/" + message;
2267 AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); 2293 AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage);
2268 alertPack.AgentData.AgentID = AgentId; 2294 alertPack.AgentData.AgentID = AgentId;
2269 alertPack.AlertData.Message = Util.StringToBytes256(message); 2295 alertPack.AlertData.Message = Util.StringToBytes256(message);
@@ -2338,6 +2364,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2338 OutPacket(sound, ThrottleOutPacketType.Task); 2364 OutPacket(sound, ThrottleOutPacketType.Task);
2339 } 2365 }
2340 2366
2367 public void SendTransferAbort(TransferRequestPacket transferRequest)
2368 {
2369 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2370 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2371 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2372 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2373 OutPacket(abort, ThrottleOutPacketType.Task);
2374 }
2375
2341 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2376 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2342 { 2377 {
2343 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2378 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2646,6 +2681,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2646 float friction = part.Friction; 2681 float friction = part.Friction;
2647 float bounce = part.Restitution; 2682 float bounce = part.Restitution;
2648 float gravmod = part.GravityModifier; 2683 float gravmod = part.GravityModifier;
2684
2649 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2685 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2650 } 2686 }
2651 } 2687 }
@@ -2716,8 +2752,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2716 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2752 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2717 return; 2753 return;
2718 } 2754 }
2755 int WearableOut = 0;
2756 bool isWearable = false;
2719 2757
2720 //m_log.Debug("sending asset " + req.RequestAssetID); 2758 if (req.AssetInf != null)
2759 isWearable =
2760 ((AssetType) req.AssetInf.Type ==
2761 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2762
2763
2764 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2765
2766
2767 //if (isWearable)
2768 // m_log.Debug((AssetType)req.AssetInf.Type);
2769
2721 TransferInfoPacket Transfer = new TransferInfoPacket(); 2770 TransferInfoPacket Transfer = new TransferInfoPacket();
2722 Transfer.TransferInfo.ChannelType = 2; 2771 Transfer.TransferInfo.ChannelType = 2;
2723 Transfer.TransferInfo.Status = 0; 2772 Transfer.TransferInfo.Status = 0;
@@ -2739,7 +2788,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2739 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2788 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2740 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2789 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2741 Transfer.Header.Zerocoded = true; 2790 Transfer.Header.Zerocoded = true;
2742 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2791 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2743 2792
2744 if (req.NumPackets == 1) 2793 if (req.NumPackets == 1)
2745 { 2794 {
@@ -2750,12 +2799,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2750 TransferPacket.TransferData.Data = req.AssetInf.Data; 2799 TransferPacket.TransferData.Data = req.AssetInf.Data;
2751 TransferPacket.TransferData.Status = 1; 2800 TransferPacket.TransferData.Status = 1;
2752 TransferPacket.Header.Zerocoded = true; 2801 TransferPacket.Header.Zerocoded = true;
2753 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2802 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2754 } 2803 }
2755 else 2804 else
2756 { 2805 {
2757 int processedLength = 0; 2806 int processedLength = 0;
2758 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2807// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2808
2809 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2759 int packetNumber = 0; 2810 int packetNumber = 0;
2760 2811
2761 while (processedLength < req.AssetInf.Data.Length) 2812 while (processedLength < req.AssetInf.Data.Length)
@@ -2781,7 +2832,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2781 TransferPacket.TransferData.Status = 1; 2832 TransferPacket.TransferData.Status = 1;
2782 } 2833 }
2783 TransferPacket.Header.Zerocoded = true; 2834 TransferPacket.Header.Zerocoded = true;
2784 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2835 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2785 2836
2786 processedLength += chunkSize; 2837 processedLength += chunkSize;
2787 packetNumber++; 2838 packetNumber++;
@@ -2826,7 +2877,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2826 reply.Data.ParcelID = parcelID; 2877 reply.Data.ParcelID = parcelID;
2827 reply.Data.OwnerID = land.OwnerID; 2878 reply.Data.OwnerID = land.OwnerID;
2828 reply.Data.Name = Utils.StringToBytes(land.Name); 2879 reply.Data.Name = Utils.StringToBytes(land.Name);
2829 reply.Data.Desc = Utils.StringToBytes(land.Description); 2880 if (land != null && land.Description != null && land.Description != String.Empty)
2881 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2882 else
2883 reply.Data.Desc = new Byte[0];
2830 reply.Data.ActualArea = land.Area; 2884 reply.Data.ActualArea = land.Area;
2831 reply.Data.BillableArea = land.Area; // TODO: what is this? 2885 reply.Data.BillableArea = land.Area; // TODO: what is this?
2832 2886
@@ -3533,24 +3587,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3533 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3587 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3534 AgentWearablesUpdatePacket.WearableDataBlock awb; 3588 AgentWearablesUpdatePacket.WearableDataBlock awb;
3535 int idx = 0; 3589 int idx = 0;
3536 for (int i = 0; i < wearables.Length; i++) 3590
3537 { 3591 for (int i = 0; i < wearables.Length; i++)
3538 for (int j = 0; j < wearables[i].Count; j++) 3592 {
3539 { 3593 for (int j = 0; j < wearables[i].Count; j++)
3540 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3594 {
3541 awb.WearableType = (byte)i; 3595 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3542 awb.AssetID = wearables[i][j].AssetID; 3596 awb.WearableType = (byte) i;
3543 awb.ItemID = wearables[i][j].ItemID; 3597 awb.AssetID = wearables[i][j].AssetID;
3544 aw.WearableData[idx] = awb; 3598 awb.ItemID = wearables[i][j].ItemID;
3545 idx++; 3599 aw.WearableData[idx] = awb;
3546 3600 idx++;
3547// m_log.DebugFormat( 3601
3548// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3602 // m_log.DebugFormat(
3549// awb.ItemID, awb.AssetID, i, Name); 3603 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3550 } 3604 // awb.ItemID, awb.AssetID, i, Name);
3551 } 3605 }
3606 }
3552 3607
3553 OutPacket(aw, ThrottleOutPacketType.Task); 3608 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3554 } 3609 }
3555 3610
3556 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3611 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3561,7 +3616,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3561 3616
3562 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3617 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3563 // TODO: don't create new blocks if recycling an old packet 3618 // TODO: don't create new blocks if recycling an old packet
3564 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3619 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3565 avp.ObjectData.TextureEntry = textureEntry; 3620 avp.ObjectData.TextureEntry = textureEntry;
3566 3621
3567 AvatarAppearancePacket.VisualParamBlock avblock = null; 3622 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3692,7 +3747,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3692 /// </summary> 3747 /// </summary>
3693 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3748 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3694 { 3749 {
3695 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3750 if (entity is SceneObjectPart)
3751 {
3752 SceneObjectPart e = (SceneObjectPart)entity;
3753 SceneObjectGroup g = e.ParentGroup;
3754 if (g.RootPart.Shape.State > 30) // HUD
3755 if (g.OwnerID != AgentId)
3756 return; // Don't send updates for other people's HUDs
3757 }
3758
3696 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3759 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3697 3760
3698 lock (m_entityUpdates.SyncRoot) 3761 lock (m_entityUpdates.SyncRoot)
@@ -3759,27 +3822,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3759 3822
3760 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3823 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3761 // condition where a kill can be processed before an out-of-date update for the same object. 3824 // condition where a kill can be processed before an out-of-date update for the same object.
3762 lock (m_killRecord) 3825 float avgTimeDilation = 1.0f;
3826 IEntityUpdate iupdate;
3827 Int32 timeinqueue; // this is just debugging code & can be dropped later
3828
3829 while (updatesThisCall < maxUpdates)
3763 { 3830 {
3764 float avgTimeDilation = 1.0f; 3831 lock (m_entityUpdates.SyncRoot)
3765 IEntityUpdate iupdate; 3832 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3766 Int32 timeinqueue; // this is just debugging code & can be dropped later 3833 break;
3834
3835 EntityUpdate update = (EntityUpdate)iupdate;
3836
3837 avgTimeDilation += update.TimeDilation;
3838 avgTimeDilation *= 0.5f;
3767 3839
3768 while (updatesThisCall < maxUpdates) 3840 if (update.Entity is SceneObjectPart)
3769 { 3841 {
3770 lock (m_entityUpdates.SyncRoot) 3842 SceneObjectPart part = (SceneObjectPart)update.Entity;
3771 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3772 break;
3773 3843
3774 EntityUpdate update = (EntityUpdate)iupdate; 3844 if (part.ParentGroup.IsDeleted)
3775 3845 continue;
3776 avgTimeDilation += update.TimeDilation;
3777 avgTimeDilation *= 0.5f;
3778 3846
3779 if (update.Entity is SceneObjectPart) 3847 if (part.ParentGroup.IsAttachment)
3848 { // Someone else's HUD, why are we getting these?
3849 if (part.ParentGroup.OwnerID != AgentId &&
3850 part.ParentGroup.RootPart.Shape.State > 30)
3851 continue;
3852 ScenePresence sp;
3853 // Owner is not in the sim, don't update it to
3854 // anyone
3855 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3856 continue;
3857
3858 List<SceneObjectGroup> atts = sp.GetAttachments();
3859 bool found = false;
3860 foreach (SceneObjectGroup att in atts)
3861 {
3862 if (att == part.ParentGroup)
3863 {
3864 found = true;
3865 break;
3866 }
3867 }
3868
3869 // It's an attachment of a valid avatar, but
3870 // doesn't seem to be attached, skip
3871 if (!found)
3872 continue;
3873
3874 // On vehicle crossing, the attachments are received
3875 // while the avatar is still a child. Don't send
3876 // updates here because the LocalId has not yet
3877 // been updated and the viewer will derender the
3878 // attachments until the avatar becomes root.
3879 if (sp.IsChildAgent)
3880 continue;
3881
3882 // If the object is an attachment we don't want it to be in the kill
3883 // record. Else attaching from inworld and subsequently dropping
3884 // it will no longer work.
3885// lock (m_killRecord)
3886// {
3887// m_killRecord.Remove(part.LocalId);
3888// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3889// }
3890 }
3891 else
3780 { 3892 {
3781 SceneObjectPart part = (SceneObjectPart)update.Entity;
3782
3783 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3893 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3784 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3894 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3785 // safety measure. 3895 // safety measure.
@@ -3790,21 +3900,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3790 // 3900 //
3791 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3901 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3792 // after the root prim has been deleted. 3902 // after the root prim has been deleted.
3793 if (m_killRecord.Contains(part.LocalId)) 3903 //
3794 { 3904 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3795 // m_log.WarnFormat( 3905// lock (m_killRecord)
3796 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3906// {
3797 // part.LocalId, Name); 3907// if (m_killRecord.Contains(part.LocalId))
3798 continue; 3908// continue;
3799 } 3909// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3800 3910// continue;
3801 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3911// }
3912 }
3913
3914 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3915 {
3916 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3917 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3802 { 3918 {
3803 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3919 part.Shape.LightEntry = false;
3804 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3805 {
3806 part.Shape.LightEntry = false;
3807 }
3808 } 3920 }
3809 3921
3810 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 3922 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
@@ -3815,224 +3927,178 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3815 part.Shape.ProfileHollow = 27500; 3927 part.Shape.ProfileHollow = 27500;
3816 } 3928 }
3817 } 3929 }
3818 3930
3819 #region UpdateFlags to packet type conversion 3931 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3820
3821 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3822
3823 bool canUseCompressed = true;
3824 bool canUseImproved = true;
3825
3826 // Compressed object updates only make sense for LL primitives
3827 if (!(update.Entity is SceneObjectPart))
3828 { 3932 {
3829 canUseCompressed = false; 3933 // Ensure that mesh has at least 8 valid faces
3934 part.Shape.ProfileBegin = 12500;
3935 part.Shape.ProfileEnd = 0;
3936 part.Shape.ProfileHollow = 27500;
3830 } 3937 }
3831 3938 }
3832 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3939 else if (update.Entity is ScenePresence)
3940 {
3941 ScenePresence presence = (ScenePresence)update.Entity;
3942
3943 // If ParentUUID is not UUID.Zero and ParentID is 0, this
3944 // avatar is in the process of crossing regions while
3945 // sat on an object. In this state, we don't want any
3946 // updates because they will visually orbit the avatar.
3947 // Update will be forced once crossing is completed anyway.
3948 if (presence.ParentUUID != UUID.Zero && presence.ParentID == 0)
3949 continue;
3950 }
3951
3952 ++updatesThisCall;
3953
3954 #region UpdateFlags to packet type conversion
3955
3956 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3957
3958 bool canUseCompressed = true;
3959 bool canUseImproved = true;
3960
3961 // Compressed object updates only make sense for LL primitives
3962 if (!(update.Entity is SceneObjectPart))
3963 {
3964 canUseCompressed = false;
3965 }
3966
3967 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3968 {
3969 canUseCompressed = false;
3970 canUseImproved = false;
3971 }
3972 else
3973 {
3974 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3975 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3976 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3977 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3833 { 3978 {
3834 canUseCompressed = false; 3979 canUseCompressed = false;
3835 canUseImproved = false;
3836 } 3980 }
3837 else 3981
3982 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3983 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3984 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3985 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3986 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3987 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3988 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3989 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3990 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3991 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3992 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3993 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3994 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3995 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3838 { 3996 {
3839 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3997 canUseImproved = false;
3840 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3841 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3842 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3843 {
3844 canUseCompressed = false;
3845 }
3846
3847 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3848 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3849 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3850 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3851 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3852 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3853 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3854 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3855 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3856 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3857 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3858 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3859 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3860 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3861 {
3862 canUseImproved = false;
3863 }
3864 } 3998 }
3999 }
3865 4000
3866 #endregion UpdateFlags to packet type conversion 4001 #endregion UpdateFlags to packet type conversion
3867
3868 #region Block Construction
3869
3870 // TODO: Remove this once we can build compressed updates
3871 canUseCompressed = false;
3872
3873 if (!canUseImproved && !canUseCompressed)
3874 {
3875 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3876 4002
3877 if (update.Entity is ScenePresence) 4003 #region Block Construction
3878 {
3879 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3880 }
3881 else
3882 {
3883 SceneObjectPart part = (SceneObjectPart)update.Entity;
3884 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3885
3886 // If the part has become a private hud since the update was scheduled then we do not
3887 // want to send it to other avatars.
3888 if (part.ParentGroup.IsAttachment
3889 && part.ParentGroup.HasPrivateAttachmentPoint
3890 && part.ParentGroup.AttachedAvatar != AgentId)
3891 continue;
3892
3893 // If the part has since been deleted, then drop the update. In the case of attachments,
3894 // this is to avoid spurious updates to other viewers since post-processing of attachments
3895 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3896 // of the test above).
3897 //
3898 // Actual deletions (kills) happen in another method.
3899 if (part.ParentGroup.IsDeleted)
3900 continue;
3901 }
3902 4004
3903 objectUpdateBlocks.Value.Add(updateBlock); 4005 // TODO: Remove this once we can build compressed updates
3904 objectUpdates.Value.Add(update); 4006 canUseCompressed = false;
3905 }
3906 else if (!canUseImproved)
3907 {
3908 SceneObjectPart part = (SceneObjectPart)update.Entity;
3909 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
3910 = CreateCompressedUpdateBlock(part, updateFlags);
3911
3912 // If the part has since been deleted, then drop the update. In the case of attachments,
3913 // this is to avoid spurious updates to other viewers since post-processing of attachments
3914 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3915 // of the test above).
3916 //
3917 // Actual deletions (kills) happen in another method.
3918 if (part.ParentGroup.IsDeleted)
3919 continue;
3920 4007
3921 compressedUpdateBlocks.Value.Add(compressedBlock); 4008 if (!canUseImproved && !canUseCompressed)
3922 compressedUpdates.Value.Add(update); 4009 {
4010 if (update.Entity is ScenePresence)
4011 {
4012 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3923 } 4013 }
3924 else 4014 else
3925 { 4015 {
3926 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4016 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3927 {
3928 // Self updates go into a special list
3929 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3930 terseAgentUpdates.Value.Add(update);
3931 }
3932 else
3933 {
3934 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
3935 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
3936
3937 // Everything else goes here
3938 if (update.Entity is SceneObjectPart)
3939 {
3940 SceneObjectPart part = (SceneObjectPart)update.Entity;
3941
3942 // If the part has become a private hud since the update was scheduled then we do not
3943 // want to send it to other avatars.
3944 if (part.ParentGroup.IsAttachment
3945 && part.ParentGroup.HasPrivateAttachmentPoint
3946 && part.ParentGroup.AttachedAvatar != AgentId)
3947 continue;
3948
3949 // If the part has since been deleted, then drop the update. In the case of attachments,
3950 // this is to avoid spurious updates to other viewers since post-processing of attachments
3951 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3952 // of the test above).
3953 //
3954 // Actual deletions (kills) happen in another method.
3955 if (part.ParentGroup.IsDeleted)
3956 continue;
3957 }
3958
3959 terseUpdateBlocks.Value.Add(terseUpdateBlock);
3960 terseUpdates.Value.Add(update);
3961 }
3962 } 4017 }
3963
3964 ++updatesThisCall;
3965
3966 #endregion Block Construction
3967 } 4018 }
3968 4019 else if (!canUseImproved)
3969 #region Packet Sending
3970 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3971
3972 if (terseAgentUpdateBlocks.IsValueCreated)
3973 { 4020 {
3974 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4021 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
4022 }
4023 else
4024 {
4025 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
4026 // Self updates go into a special list
4027 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4028 else
4029 // Everything else goes here
4030 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4031 }
3975 4032
3976 ImprovedTerseObjectUpdatePacket packet 4033 #endregion Block Construction
3977 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4034 }
3978 4035
3979 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4036 #region Packet Sending
3980 packet.RegionData.TimeDilation = timeDilation; 4037
3981 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4038 const float TIME_DILATION = 1.0f;
4039 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4040
4041 if (terseAgentUpdateBlocks.IsValueCreated)
4042 {
4043 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3982 4044
3983 for (int i = 0; i < blocks.Count; i++) 4045 ImprovedTerseObjectUpdatePacket packet
3984 packet.ObjectData[i] = blocks[i]; 4046 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3985 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4047 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3986 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4048 packet.RegionData.TimeDilation = timeDilation;
3987 } 4049 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3988 4050
3989 if (objectUpdateBlocks.IsValueCreated) 4051 for (int i = 0; i < blocks.Count; i++)
3990 { 4052 packet.ObjectData[i] = blocks[i];
3991 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3992
3993 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3994 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3995 packet.RegionData.TimeDilation = timeDilation;
3996 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3997
3998 for (int i = 0; i < blocks.Count; i++)
3999 packet.ObjectData[i] = blocks[i];
4000 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4001 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4002 }
4003
4004 if (compressedUpdateBlocks.IsValueCreated)
4005 {
4006 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4007
4008 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4009 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4010 packet.RegionData.TimeDilation = timeDilation;
4011 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4012
4013 for (int i = 0; i < blocks.Count; i++)
4014 packet.ObjectData[i] = blocks[i];
4015 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4016 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4017 }
4018 4053
4019 if (terseUpdateBlocks.IsValueCreated) 4054 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4020 { 4055 }
4021 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4022
4023 ImprovedTerseObjectUpdatePacket packet
4024 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4025 PacketType.ImprovedTerseObjectUpdate);
4026 4056
4027 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4057 if (objectUpdateBlocks.IsValueCreated)
4028 packet.RegionData.TimeDilation = timeDilation; 4058 {
4029 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4059 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4030 4060
4031 for (int i = 0; i < blocks.Count; i++) 4061 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4032 packet.ObjectData[i] = blocks[i]; 4062 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4033 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4063 packet.RegionData.TimeDilation = timeDilation;
4034 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4064 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4035 } 4065
4066 for (int i = 0; i < blocks.Count; i++)
4067 packet.ObjectData[i] = blocks[i];
4068
4069 OutPacket(packet, ThrottleOutPacketType.Task, true);
4070 }
4071
4072 if (compressedUpdateBlocks.IsValueCreated)
4073 {
4074 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4075
4076 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4077 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4078 packet.RegionData.TimeDilation = timeDilation;
4079 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4080
4081 for (int i = 0; i < blocks.Count; i++)
4082 packet.ObjectData[i] = blocks[i];
4083
4084 OutPacket(packet, ThrottleOutPacketType.Task, true);
4085 }
4086
4087 if (terseUpdateBlocks.IsValueCreated)
4088 {
4089 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4090
4091 ImprovedTerseObjectUpdatePacket packet
4092 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4093 PacketType.ImprovedTerseObjectUpdate);
4094 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4095 packet.RegionData.TimeDilation = timeDilation;
4096 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4097
4098 for (int i = 0; i < blocks.Count; i++)
4099 packet.ObjectData[i] = blocks[i];
4100
4101 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4036 } 4102 }
4037 4103
4038 #endregion Packet Sending 4104 #endregion Packet Sending
@@ -4325,11 +4391,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4325 4391
4326 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4392 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4327 // of the object rather than the properties when the packet was created 4393 // of the object rather than the properties when the packet was created
4328 OutPacket(packet, ThrottleOutPacketType.Task, true, 4394 // HACK : Remove intelligent resending until it's fixed in core
4329 delegate(OutgoingPacket oPacket) 4395 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4330 { 4396 // delegate(OutgoingPacket oPacket)
4331 ResendPropertyUpdates(updates, oPacket); 4397 // {
4332 }); 4398 // ResendPropertyUpdates(updates, oPacket);
4399 // });
4400 OutPacket(packet, ThrottleOutPacketType.Task, true);
4333 4401
4334 // pbcnt += blocks.Count; 4402 // pbcnt += blocks.Count;
4335 // ppcnt++; 4403 // ppcnt++;
@@ -4355,11 +4423,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4355 // of the object rather than the properties when the packet was created 4423 // of the object rather than the properties when the packet was created
4356 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4424 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4357 updates.Add(familyUpdates.Value[i]); 4425 updates.Add(familyUpdates.Value[i]);
4358 OutPacket(packet, ThrottleOutPacketType.Task, true, 4426 // HACK : Remove intelligent resending until it's fixed in core
4359 delegate(OutgoingPacket oPacket) 4427 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4360 { 4428 // delegate(OutgoingPacket oPacket)
4361 ResendPropertyUpdates(updates, oPacket); 4429 // {
4362 }); 4430 // ResendPropertyUpdates(updates, oPacket);
4431 // });
4432 OutPacket(packet, ThrottleOutPacketType.Task, true);
4363 4433
4364 // fpcnt++; 4434 // fpcnt++;
4365 // fbcnt++; 4435 // fbcnt++;
@@ -4731,7 +4801,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4731 4801
4732 if (landData.SimwideArea > 0) 4802 if (landData.SimwideArea > 0)
4733 { 4803 {
4734 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4804 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4805 // Never report more than sim total capacity
4806 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4807 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4735 updateMessage.SimWideMaxPrims = simulatorCapacity; 4808 updateMessage.SimWideMaxPrims = simulatorCapacity;
4736 } 4809 }
4737 else 4810 else
@@ -4860,14 +4933,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4860 4933
4861 if (notifyCount > 0) 4934 if (notifyCount > 0)
4862 { 4935 {
4863 if (notifyCount > 32) 4936// if (notifyCount > 32)
4864 { 4937// {
4865 m_log.InfoFormat( 4938// m_log.InfoFormat(
4866 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4939// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4867 + " - a developer might want to investigate whether this is a hard limit", 32); 4940// + " - a developer might want to investigate whether this is a hard limit", 32);
4868 4941//
4869 notifyCount = 32; 4942// notifyCount = 32;
4870 } 4943// }
4871 4944
4872 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4945 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4873 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4946 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4922,9 +4995,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4922 { 4995 {
4923 ScenePresence presence = (ScenePresence)entity; 4996 ScenePresence presence = (ScenePresence)entity;
4924 4997
4998 position = presence.OffsetPosition;
4999 rotation = presence.Rotation;
5000
5001 if (presence.ParentID != 0)
5002 {
5003 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
5004 if (part != null && part != part.ParentGroup.RootPart)
5005 {
5006 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
5007 rotation = part.RotationOffset * presence.Rotation;
5008 }
5009 angularVelocity = Vector3.Zero;
5010 }
5011 else
5012 {
5013 angularVelocity = presence.AngularVelocity;
5014 rotation = presence.Rotation;
5015 }
5016
4925 attachPoint = 0; 5017 attachPoint = 0;
4926 collisionPlane = presence.CollisionPlane; 5018 collisionPlane = presence.CollisionPlane;
4927 position = presence.OffsetPosition;
4928 velocity = presence.Velocity; 5019 velocity = presence.Velocity;
4929 acceleration = Vector3.Zero; 5020 acceleration = Vector3.Zero;
4930 5021
@@ -4933,9 +5024,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4933 // may improve movement smoothness. 5024 // may improve movement smoothness.
4934// acceleration = new Vector3(1, 0, 0); 5025// acceleration = new Vector3(1, 0, 0);
4935 5026
4936 angularVelocity = presence.AngularVelocity;
4937 rotation = presence.Rotation;
4938
4939 if (sendTexture) 5027 if (sendTexture)
4940 textureEntry = presence.Appearance.Texture.GetBytes(); 5028 textureEntry = presence.Appearance.Texture.GetBytes();
4941 else 5029 else
@@ -5041,13 +5129,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5041 5129
5042 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5130 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5043 { 5131 {
5132 Vector3 offsetPosition = data.OffsetPosition;
5133 Quaternion rotation = data.Rotation;
5134 uint parentID = data.ParentID;
5135
5136 if (parentID != 0)
5137 {
5138 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5139 if (part != null && part != part.ParentGroup.RootPart)
5140 {
5141 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5142 rotation = part.RotationOffset * data.Rotation;
5143 parentID = part.ParentGroup.RootPart.LocalId;
5144 }
5145 }
5146
5044 byte[] objectData = new byte[76]; 5147 byte[] objectData = new byte[76];
5045 5148
5046 data.CollisionPlane.ToBytes(objectData, 0); 5149 data.CollisionPlane.ToBytes(objectData, 0);
5047 data.OffsetPosition.ToBytes(objectData, 16); 5150 offsetPosition.ToBytes(objectData, 16);
5151 Vector3 velocity = new Vector3(0, 0, 0);
5152 Vector3 acceleration = new Vector3(0, 0, 0);
5153 velocity.ToBytes(objectData, 28);
5154 acceleration.ToBytes(objectData, 40);
5048// data.Velocity.ToBytes(objectData, 28); 5155// data.Velocity.ToBytes(objectData, 28);
5049// data.Acceleration.ToBytes(objectData, 40); 5156// data.Acceleration.ToBytes(objectData, 40);
5050 data.Rotation.ToBytes(objectData, 52); 5157 rotation.ToBytes(objectData, 52);
5051 //data.AngularVelocity.ToBytes(objectData, 64); 5158 //data.AngularVelocity.ToBytes(objectData, 64);
5052 5159
5053 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5160 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5061,14 +5168,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5061 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5168 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5062 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5169 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5063 update.ObjectData = objectData; 5170 update.ObjectData = objectData;
5064 update.ParentID = data.ParentID; 5171 update.ParentID = parentID;
5065 update.PathCurve = 16; 5172 update.PathCurve = 16;
5066 update.PathScaleX = 100; 5173 update.PathScaleX = 100;
5067 update.PathScaleY = 100; 5174 update.PathScaleY = 100;
5068 update.PCode = (byte)PCode.Avatar; 5175 update.PCode = (byte)PCode.Avatar;
5069 update.ProfileCurve = 1; 5176 update.ProfileCurve = 1;
5070 update.PSBlock = Utils.EmptyBytes; 5177 update.PSBlock = Utils.EmptyBytes;
5071 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5178 update.Scale = data.Appearance.AvatarSize;
5179// update.Scale.Z -= 0.2f;
5180
5072 update.Text = Utils.EmptyBytes; 5181 update.Text = Utils.EmptyBytes;
5073 update.TextColor = new byte[4]; 5182 update.TextColor = new byte[4];
5074 5183
@@ -5079,10 +5188,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5079 update.TextureEntry = Utils.EmptyBytes; 5188 update.TextureEntry = Utils.EmptyBytes;
5080// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5189// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5081 5190
5191/* 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)
5082 update.UpdateFlags = (uint)( 5192 update.UpdateFlags = (uint)(
5083 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5193 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5084 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5194 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5085 PrimFlags.ObjectOwnerModify); 5195 PrimFlags.ObjectOwnerModify);
5196*/
5197 update.UpdateFlags = 0;
5086 5198
5087 return update; 5199 return update;
5088 } 5200 }
@@ -5253,8 +5365,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5253 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5365 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5254 // for each AgentUpdate packet. 5366 // for each AgentUpdate packet.
5255 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5367 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5256 5368
5257 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5369 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5370 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5371 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5258 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5372 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5259 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5373 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5260 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5374 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5406,6 +5520,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5406 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5520 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5407 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5521 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5408 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5522 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5523 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5409 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5524 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5410 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5525 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5411 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5526 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5472,6 +5587,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5472 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5587 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5473 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5588 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5474 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5589 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5590 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5475 5591
5476 AddGenericPacketHandler("autopilot", HandleAutopilot); 5592 AddGenericPacketHandler("autopilot", HandleAutopilot);
5477 } 5593 }
@@ -5510,6 +5626,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5510 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || 5626 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5511 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || 5627 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5512 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || 5628 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5629 (x.ControlFlags != 0) ||
5513 (x.Far != m_lastAgentUpdateArgs.Far) || 5630 (x.Far != m_lastAgentUpdateArgs.Far) ||
5514 (x.Flags != m_lastAgentUpdateArgs.Flags) || 5631 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5515 (x.State != m_lastAgentUpdateArgs.State) || 5632 (x.State != m_lastAgentUpdateArgs.State) ||
@@ -5769,6 +5886,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5769 return true; 5886 return true;
5770 } 5887 }
5771 5888
5889 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
5890 {
5891 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
5892 if (p.AgentData.SessionID != SessionId ||
5893 p.AgentData.AgentID != AgentId)
5894 return true;
5895
5896 m_VelocityInterpolate = false;
5897 return true;
5898 }
5899
5900 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
5901 {
5902 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
5903 if (p.AgentData.SessionID != SessionId ||
5904 p.AgentData.AgentID != AgentId)
5905 return true;
5906
5907 m_VelocityInterpolate = true;
5908 return true;
5909 }
5910
5911
5772 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 5912 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5773 { 5913 {
5774 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 5914 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6189,17 +6329,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6189 // Temporarily protect ourselves from the mantis #951 failure. 6329 // Temporarily protect ourselves from the mantis #951 failure.
6190 // However, we could do this for several other handlers where a failure isn't terminal 6330 // However, we could do this for several other handlers where a failure isn't terminal
6191 // for the client session anyway, in order to protect ourselves against bad code in plugins 6331 // for the client session anyway, in order to protect ourselves against bad code in plugins
6332 Vector3 avSize = appear.AgentData.Size;
6192 try 6333 try
6193 { 6334 {
6194 byte[] visualparams = new byte[appear.VisualParam.Length]; 6335 byte[] visualparams = new byte[appear.VisualParam.Length];
6195 for (int i = 0; i < appear.VisualParam.Length; i++) 6336 for (int i = 0; i < appear.VisualParam.Length; i++)
6196 visualparams[i] = appear.VisualParam[i].ParamValue; 6337 visualparams[i] = appear.VisualParam[i].ParamValue;
6197 6338 //var b = appear.WearableData[0];
6339
6198 Primitive.TextureEntry te = null; 6340 Primitive.TextureEntry te = null;
6199 if (appear.ObjectData.TextureEntry.Length > 1) 6341 if (appear.ObjectData.TextureEntry.Length > 1)
6200 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6342 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6343
6344 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6345 for (int i=0; i<appear.WearableData.Length;i++)
6346 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6347
6348
6201 6349
6202 handlerSetAppearance(sender, te, visualparams); 6350 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6203 } 6351 }
6204 catch (Exception e) 6352 catch (Exception e)
6205 { 6353 {
@@ -6408,6 +6556,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6408 { 6556 {
6409 handlerCompleteMovementToRegion(sender, true); 6557 handlerCompleteMovementToRegion(sender, true);
6410 } 6558 }
6559 else
6560 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6561
6411 handlerCompleteMovementToRegion = null; 6562 handlerCompleteMovementToRegion = null;
6412 6563
6413 return true; 6564 return true;
@@ -6425,7 +6576,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6425 return true; 6576 return true;
6426 } 6577 }
6427 #endregion 6578 #endregion
6428 6579/*
6429 StartAnim handlerStartAnim = null; 6580 StartAnim handlerStartAnim = null;
6430 StopAnim handlerStopAnim = null; 6581 StopAnim handlerStopAnim = null;
6431 6582
@@ -6449,6 +6600,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6449 } 6600 }
6450 } 6601 }
6451 return true; 6602 return true;
6603*/
6604 ChangeAnim handlerChangeAnim = null;
6605
6606 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6607 {
6608 handlerChangeAnim = OnChangeAnim;
6609 if (handlerChangeAnim != null)
6610 {
6611 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6612 }
6613 }
6614
6615 handlerChangeAnim = OnChangeAnim;
6616 if (handlerChangeAnim != null)
6617 {
6618 handlerChangeAnim(UUID.Zero, false, true);
6619 }
6620
6621 return true;
6452 } 6622 }
6453 6623
6454 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6624 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6674,6 +6844,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6674 #endregion 6844 #endregion
6675 6845
6676 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6846 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6847 GenericCall2 handler = OnUpdateThrottles;
6848 if (handler != null)
6849 {
6850 handler();
6851 }
6677 return true; 6852 return true;
6678 } 6853 }
6679 6854
@@ -7098,7 +7273,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7098 physdata.Bounce = phsblock.Restitution; 7273 physdata.Bounce = phsblock.Restitution;
7099 physdata.Density = phsblock.Density; 7274 physdata.Density = phsblock.Density;
7100 physdata.Friction = phsblock.Friction; 7275 physdata.Friction = phsblock.Friction;
7101 physdata.GravitationModifier = phsblock.GravityMultiplier; 7276 physdata.GravitationModifier = phsblock.GravityMultiplier;
7102 } 7277 }
7103 7278
7104 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7279 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7684,6 +7859,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7684 // surrounding scene 7859 // surrounding scene
7685 if ((ImageType)block.Type == ImageType.Baked) 7860 if ((ImageType)block.Type == ImageType.Baked)
7686 args.Priority *= 2.0f; 7861 args.Priority *= 2.0f;
7862 int wearableout = 0;
7687 7863
7688 ImageManager.EnqueueReq(args); 7864 ImageManager.EnqueueReq(args);
7689 } 7865 }
@@ -8702,16 +8878,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8702 8878
8703 #region Parcel related packets 8879 #region Parcel related packets
8704 8880
8881 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
8882 // to be done with minimal resources as possible
8883 // variables temporary here while in test
8884
8885 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
8886 bool RegionHandleRequestsInService = false;
8887
8705 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 8888 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8706 { 8889 {
8707 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 8890 UUID currentUUID;
8708 8891
8709 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 8892 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8710 if (handlerRegionHandleRequest != null) 8893
8894 if (handlerRegionHandleRequest == null)
8895 return true;
8896
8897 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
8898
8899 lock (RegionHandleRequests)
8711 { 8900 {
8712 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 8901 if (RegionHandleRequestsInService)
8902 {
8903 // we are already busy doing a previus request
8904 // so enqueue it
8905 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
8906 return true;
8907 }
8908
8909 // else do it
8910 currentUUID = rhrPack.RequestBlock.RegionID;
8911 RegionHandleRequestsInService = true;
8713 } 8912 }
8714 return true; 8913
8914 while (true)
8915 {
8916 handlerRegionHandleRequest(this, currentUUID);
8917
8918 lock (RegionHandleRequests)
8919 {
8920 // exit condition, nothing to do or closed
8921 // current code seems to assume we may loose the handler at anytime,
8922 // so keep checking it
8923 handlerRegionHandleRequest = OnRegionHandleRequest;
8924
8925 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
8926 {
8927 RegionHandleRequests.Clear();
8928 RegionHandleRequestsInService = false;
8929 return true;
8930 }
8931 currentUUID = RegionHandleRequests.Dequeue();
8932 }
8933 }
8934
8935 return true; // actually unreached
8715 } 8936 }
8716 8937
8717 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 8938 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -9667,7 +9888,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9667 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; 9888 EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest;
9668 if (handlerEconomoyDataRequest != null) 9889 if (handlerEconomoyDataRequest != null)
9669 { 9890 {
9670 handlerEconomoyDataRequest(AgentId); 9891 handlerEconomoyDataRequest(this);
9671 } 9892 }
9672 return true; 9893 return true;
9673 } 9894 }
@@ -9967,7 +10188,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9967 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10188 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9968 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10189 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9969 UpdateMuteListEntry.MuteData.MuteType, 10190 UpdateMuteListEntry.MuteData.MuteType,
9970 UpdateMuteListEntry.AgentData.AgentID); 10191 UpdateMuteListEntry.MuteData.MuteFlags);
9971 return true; 10192 return true;
9972 } 10193 }
9973 return false; 10194 return false;
@@ -9982,8 +10203,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9982 { 10203 {
9983 handlerRemoveMuteListEntry(this, 10204 handlerRemoveMuteListEntry(this,
9984 RemoveMuteListEntry.MuteData.MuteID, 10205 RemoveMuteListEntry.MuteData.MuteID,
9985 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10206 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9986 RemoveMuteListEntry.AgentData.AgentID);
9987 return true; 10207 return true;
9988 } 10208 }
9989 return false; 10209 return false;
@@ -10027,10 +10247,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10027 return false; 10247 return false;
10028 } 10248 }
10029 10249
10250 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10251 {
10252 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10253 (ChangeInventoryItemFlagsPacket)packet;
10254 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10255 if (handlerChangeInventoryItemFlags != null)
10256 {
10257 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10258 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10259 return true;
10260 }
10261 return false;
10262 }
10263
10030 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10264 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10031 { 10265 {
10032 return true; 10266 return true;
10033 } 10267 }
10268
10269 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10270 {
10271 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10272
10273 #region Packet Session and User Check
10274 if (m_checkPackets)
10275 {
10276 if (packet.AgentData.SessionID != SessionId ||
10277 packet.AgentData.AgentID != AgentId)
10278 return true;
10279 }
10280 #endregion
10281 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10282 List<InventoryItemBase> items = new List<InventoryItemBase>();
10283 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10284 {
10285 InventoryItemBase b = new InventoryItemBase();
10286 b.ID = n.OldItemID;
10287 b.Folder = n.OldFolderID;
10288 items.Add(b);
10289 }
10290
10291 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10292 if (handlerMoveItemsAndLeaveCopy != null)
10293 {
10294 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10295 }
10296
10297 return true;
10298 }
10034 10299
10035 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10300 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10036 { 10301 {
@@ -10457,6 +10722,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10457 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10722 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10458 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10723 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10459 10724
10725 Scene scene = (Scene)m_scene;
10726 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10727 {
10728 ScenePresence p;
10729 if (scene.TryGetScenePresence(sender.AgentId, out p))
10730 {
10731 if (p.GodLevel >= 200)
10732 {
10733 groupProfileReply.GroupData.OpenEnrollment = true;
10734 groupProfileReply.GroupData.MembershipFee = 0;
10735 }
10736 }
10737 }
10738
10460 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10739 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10461 } 10740 }
10462 return true; 10741 return true;
@@ -11030,11 +11309,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11030 11309
11031 StartLure handlerStartLure = OnStartLure; 11310 StartLure handlerStartLure = OnStartLure;
11032 if (handlerStartLure != null) 11311 if (handlerStartLure != null)
11033 handlerStartLure(startLureRequest.Info.LureType, 11312 {
11034 Utils.BytesToString( 11313 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11035 startLureRequest.Info.Message), 11314 {
11036 startLureRequest.TargetData[0].TargetID, 11315 handlerStartLure(startLureRequest.Info.LureType,
11037 this); 11316 Utils.BytesToString(
11317 startLureRequest.Info.Message),
11318 startLureRequest.TargetData[i].TargetID,
11319 this);
11320 }
11321 }
11038 return true; 11322 return true;
11039 } 11323 }
11040 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11324 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11148,10 +11432,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11148 } 11432 }
11149 #endregion 11433 #endregion
11150 11434
11151 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11435 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11152 if (handlerClassifiedGodDelete != null) 11436 if (handlerClassifiedGodDelete != null)
11153 handlerClassifiedGodDelete( 11437 handlerClassifiedGodDelete(
11154 classifiedGodDelete.Data.ClassifiedID, 11438 classifiedGodDelete.Data.ClassifiedID,
11439 classifiedGodDelete.Data.QueryID,
11155 this); 11440 this);
11156 return true; 11441 return true;
11157 } 11442 }
@@ -11464,6 +11749,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11464 11749
11465 if (cachedtex.AgentData.SessionID != SessionId) 11750 if (cachedtex.AgentData.SessionID != SessionId)
11466 return false; 11751 return false;
11752
11467 11753
11468 // TODO: don't create new blocks if recycling an old packet 11754 // TODO: don't create new blocks if recycling an old packet
11469 cachedresp.AgentData.AgentID = AgentId; 11755 cachedresp.AgentData.AgentID = AgentId;
@@ -11473,14 +11759,140 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11473 cachedresp.WearableData = 11759 cachedresp.WearableData =
11474 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 11760 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11475 11761
11476 for (int i = 0; i < cachedtex.WearableData.Length; i++) 11762 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11763 // var item = fac.GetBakedTextureFaces(AgentId);
11764 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11765
11766 IAssetService cache = m_scene.AssetService;
11767 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11768 //bakedTextureModule = null;
11769 int maxWearablesLoop = cachedtex.WearableData.Length;
11770 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11771 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11772
11773 if (bakedTextureModule != null && cache != null)
11477 { 11774 {
11478 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 11775 // 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
11479 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 11776
11480 cachedresp.WearableData[i].TextureID = UUID.Zero; 11777 WearableCacheItem[] cacheItems = null;
11481 cachedresp.WearableData[i].HostName = new byte[0]; 11778 ScenePresence p = m_scene.GetScenePresence(AgentId);
11779 if (p.Appearance != null)
11780 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11781 {
11782 try
11783 {
11784 cacheItems = bakedTextureModule.Get(AgentId);
11785 p.Appearance.WearableCacheItems = cacheItems;
11786 p.Appearance.WearableCacheItemsDirty = false;
11787 }
11788
11789 /*
11790 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11791 *
11792 catch (System.Net.Sockets.SocketException)
11793 {
11794 cacheItems = null;
11795 }
11796 catch (WebException)
11797 {
11798 cacheItems = null;
11799 }
11800 catch (InvalidOperationException)
11801 {
11802 cacheItems = null;
11803 } */
11804 catch (Exception)
11805 {
11806 cacheItems = null;
11807 }
11808
11809 }
11810 else if (p.Appearance.WearableCacheItems != null)
11811 {
11812 cacheItems = p.Appearance.WearableCacheItems;
11813 }
11814
11815 if (cache != null && cacheItems != null)
11816 {
11817 foreach (WearableCacheItem item in cacheItems)
11818 {
11819
11820 if (cache.GetCached(item.TextureID.ToString()) == null)
11821 {
11822 item.TextureAsset.Temporary = true;
11823 cache.Store(item.TextureAsset);
11824 }
11825
11826
11827 }
11828 }
11829
11830 if (cacheItems != null)
11831 {
11832
11833 for (int i = 0; i < maxWearablesLoop; i++)
11834 {
11835 WearableCacheItem item =
11836 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11837
11838 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11839 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
11840 cachedresp.WearableData[i].HostName = new byte[0];
11841 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11842 {
11843
11844 cachedresp.WearableData[i].TextureID = item.TextureID;
11845 }
11846 else
11847 {
11848 cachedresp.WearableData[i].TextureID = UUID.Zero;
11849 }
11850 }
11851 }
11852 else
11853 {
11854 for (int i = 0; i < maxWearablesLoop; i++)
11855 {
11856 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11857 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11858 cachedresp.WearableData[i].TextureID = UUID.Zero;
11859 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11860 cachedresp.WearableData[i].HostName = new byte[0];
11861 }
11862 }
11482 } 11863 }
11864 else
11865 {
11866 if (cache == null)
11867 {
11868 for (int i = 0; i < maxWearablesLoop; i++)
11869 {
11870 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11871 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11872 cachedresp.WearableData[i].TextureID = UUID.Zero;
11873 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11874 cachedresp.WearableData[i].HostName = new byte[0];
11875 }
11876 }
11877 else
11878 {
11879 for (int i = 0; i < maxWearablesLoop; i++)
11880 {
11881 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11882 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11883
11483 11884
11885
11886 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11887 cachedresp.WearableData[i].TextureID = UUID.Zero;
11888 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11889 else
11890 cachedresp.WearableData[i].TextureID = UUID.Zero;
11891 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11892 cachedresp.WearableData[i].HostName = new byte[0];
11893 }
11894 }
11895 }
11484 cachedresp.Header.Zerocoded = true; 11896 cachedresp.Header.Zerocoded = true;
11485 OutPacket(cachedresp, ThrottleOutPacketType.Task); 11897 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11486 11898
@@ -11517,209 +11929,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11517 } 11929 }
11518 else 11930 else
11519 { 11931 {
11520// m_log.DebugFormat( 11932 ClientChangeObject updatehandler = onClientChangeObject;
11521// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11522// i, block.Type, part.Name, part.LocalId);
11523 11933
11524// // Do this once since fetch parts creates a new array. 11934 if (updatehandler != null)
11525// SceneObjectPart[] parts = part.ParentGroup.Parts; 11935 {
11526// for (int j = 0; j < parts.Length; j++) 11936 ObjectChangeData udata = new ObjectChangeData();
11527// {
11528// part.StoreUndoState();
11529// parts[j].IgnoreUndoUpdate = true;
11530// }
11531 11937
11532 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 11938 /*ubit from ll JIRA:
11939 * 0x01 position
11940 * 0x02 rotation
11941 * 0x04 scale
11942
11943 * 0x08 LINK_SET
11944 * 0x10 UNIFORM for scale
11945 */
11533 11946
11534 switch (block.Type) 11947 // translate to internal changes
11535 { 11948 // not all cases .. just the ones older code did
11536 case 1:
11537 Vector3 pos1 = new Vector3(block.Data, 0);
11538 11949
11539 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11950 switch (block.Type)
11540 if (handlerUpdatePrimSinglePosition != null) 11951 {
11541 { 11952 case 1: //change position sp
11542 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11953 udata.position = new Vector3(block.Data, 0);
11543 handlerUpdatePrimSinglePosition(localId, pos1, this);
11544 }
11545 break;
11546 11954
11547 case 2: 11955 udata.change = ObjectChangeType.primP;
11548 Quaternion rot1 = new Quaternion(block.Data, 0, true); 11956 updatehandler(localId, udata, this);
11957 break;
11549 11958
11550 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 11959 case 2: // rotation sp
11551 if (handlerUpdatePrimSingleRotation != null) 11960 udata.rotation = new Quaternion(block.Data, 0, true);
11552 {
11553 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11554 handlerUpdatePrimSingleRotation(localId, rot1, this);
11555 }
11556 break;
11557 11961
11558 case 3: 11962 udata.change = ObjectChangeType.primR;
11559 Vector3 rotPos = new Vector3(block.Data, 0); 11963 updatehandler(localId, udata, this);
11560 Quaternion rot2 = new Quaternion(block.Data, 12, true); 11964 break;
11561 11965
11562 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 11966 case 3: // position plus rotation
11563 if (handlerUpdatePrimSingleRotationPosition != null) 11967 udata.position = new Vector3(block.Data, 0);
11564 { 11968 udata.rotation = new Quaternion(block.Data, 12, true);
11565 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11566 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11567 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11568 }
11569 break;
11570 11969
11571 case 4: 11970 udata.change = ObjectChangeType.primPR;
11572 case 20: 11971 updatehandler(localId, udata, this);
11573 Vector3 scale4 = new Vector3(block.Data, 0); 11972 break;
11574 11973
11575 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 11974 case 4: // scale sp
11576 if (handlerUpdatePrimScale != null) 11975 udata.scale = new Vector3(block.Data, 0);
11577 { 11976 udata.change = ObjectChangeType.primS;
11578 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11579 handlerUpdatePrimScale(localId, scale4, this);
11580 }
11581 break;
11582 11977
11583 case 5: 11978 updatehandler(localId, udata, this);
11584 Vector3 scale1 = new Vector3(block.Data, 12); 11979 break;
11585 Vector3 pos11 = new Vector3(block.Data, 0);
11586 11980
11587 handlerUpdatePrimScale = OnUpdatePrimScale; 11981 case 0x14: // uniform scale sp
11588 if (handlerUpdatePrimScale != null) 11982 udata.scale = new Vector3(block.Data, 0);
11589 {
11590 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11591 handlerUpdatePrimScale(localId, scale1, this);
11592 11983
11593 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11984 udata.change = ObjectChangeType.primUS;
11594 if (handlerUpdatePrimSinglePosition != null) 11985 updatehandler(localId, udata, this);
11595 { 11986 break;
11596 handlerUpdatePrimSinglePosition(localId, pos11, this);
11597 }
11598 }
11599 break;
11600 11987
11601 case 9: 11988 case 5: // scale and position sp
11602 Vector3 pos2 = new Vector3(block.Data, 0); 11989 udata.position = new Vector3(block.Data, 0);
11990 udata.scale = new Vector3(block.Data, 12);
11603 11991
11604 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 11992 udata.change = ObjectChangeType.primPS;
11993 updatehandler(localId, udata, this);
11994 break;
11605 11995
11606 if (handlerUpdateVector != null) 11996 case 0x15: //uniform scale and position
11607 { 11997 udata.position = new Vector3(block.Data, 0);
11608 handlerUpdateVector(localId, pos2, this); 11998 udata.scale = new Vector3(block.Data, 12);
11609 }
11610 break;
11611 11999
11612 case 10: 12000 udata.change = ObjectChangeType.primPUS;
11613 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12001 updatehandler(localId, udata, this);
12002 break;
11614 12003
11615 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12004 // now group related (bit 4)
11616 if (handlerUpdatePrimRotation != null) 12005 case 9: //( 8 + 1 )group position
11617 { 12006 udata.position = new Vector3(block.Data, 0);
11618 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11619 handlerUpdatePrimRotation(localId, rot3, this);
11620 }
11621 break;
11622 12007
11623 case 11: 12008 udata.change = ObjectChangeType.groupP;
11624 Vector3 pos3 = new Vector3(block.Data, 0); 12009 updatehandler(localId, udata, this);
11625 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12010 break;
11626 12011
11627 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12012 case 0x0A: // (8 + 2) group rotation
11628 if (handlerUpdatePrimGroupRotation != null) 12013 udata.rotation = new Quaternion(block.Data, 0, true);
11629 {
11630 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11631 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11632 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11633 }
11634 break;
11635 case 12:
11636 case 28:
11637 Vector3 scale7 = new Vector3(block.Data, 0);
11638 12014
11639 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12015 udata.change = ObjectChangeType.groupR;
11640 if (handlerUpdatePrimGroupScale != null) 12016 updatehandler(localId, udata, this);
11641 { 12017 break;
11642 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11643 handlerUpdatePrimGroupScale(localId, scale7, this);
11644 }
11645 break;
11646 12018
11647 case 13: 12019 case 0x0B: //( 8 + 2 + 1) group rotation and position
11648 Vector3 scale2 = new Vector3(block.Data, 12); 12020 udata.position = new Vector3(block.Data, 0);
11649 Vector3 pos4 = new Vector3(block.Data, 0); 12021 udata.rotation = new Quaternion(block.Data, 12, true);
11650 12022
11651 handlerUpdatePrimScale = OnUpdatePrimScale; 12023 udata.change = ObjectChangeType.groupPR;
11652 if (handlerUpdatePrimScale != null) 12024 updatehandler(localId, udata, this);
11653 { 12025 break;
11654 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11655 handlerUpdatePrimScale(localId, scale2, this);
11656 12026
11657 // Change the position based on scale (for bug number 246) 12027 case 0x0C: // (8 + 4) group scale
11658 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12028 // only afects root prim and only sent by viewer editor object tab scaling
11659 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12029 // mouse edition only allows uniform scaling
11660 if (handlerUpdatePrimSinglePosition != null) 12030 // SL MAY CHANGE THIS in viewers
11661 {
11662 handlerUpdatePrimSinglePosition(localId, pos4, this);
11663 }
11664 }
11665 break;
11666 12031
11667 case 29: 12032 udata.scale = new Vector3(block.Data, 0);
11668 Vector3 scale5 = new Vector3(block.Data, 12);
11669 Vector3 pos5 = new Vector3(block.Data, 0);
11670 12033
11671 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12034 udata.change = ObjectChangeType.groupS;
11672 if (handlerUpdatePrimGroupScale != null) 12035 updatehandler(localId, udata, this);
11673 {
11674 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11675 part.StoreUndoState(true);
11676 part.IgnoreUndoUpdate = true;
11677 handlerUpdatePrimGroupScale(localId, scale5, this);
11678 handlerUpdateVector = OnUpdatePrimGroupPosition;
11679 12036
11680 if (handlerUpdateVector != null) 12037 break;
11681 {
11682 handlerUpdateVector(localId, pos5, this);
11683 }
11684 12038
11685 part.IgnoreUndoUpdate = false; 12039 case 0x0D: //(8 + 4 + 1) group scale and position
11686 } 12040 // exception as above
11687 12041
11688 break; 12042 udata.position = new Vector3(block.Data, 0);
12043 udata.scale = new Vector3(block.Data, 12);
11689 12044
11690 case 21: 12045 udata.change = ObjectChangeType.groupPS;
11691 Vector3 scale6 = new Vector3(block.Data, 12); 12046 updatehandler(localId, udata, this);
11692 Vector3 pos6 = new Vector3(block.Data, 0); 12047 break;
11693 12048
11694 handlerUpdatePrimScale = OnUpdatePrimScale; 12049 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11695 if (handlerUpdatePrimScale != null) 12050 udata.scale = new Vector3(block.Data, 0);
11696 {
11697 part.StoreUndoState(false);
11698 part.IgnoreUndoUpdate = true;
11699 12051
11700 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12052 udata.change = ObjectChangeType.groupUS;
11701 handlerUpdatePrimScale(localId, scale6, this); 12053 updatehandler(localId, udata, this);
11702 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12054 break;
11703 if (handlerUpdatePrimSinglePosition != null)
11704 {
11705 handlerUpdatePrimSinglePosition(localId, pos6, this);
11706 }
11707 12055
11708 part.IgnoreUndoUpdate = false; 12056 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11709 } 12057 udata.position = new Vector3(block.Data, 0);
11710 break; 12058 udata.scale = new Vector3(block.Data, 12);
11711 12059
11712 default: 12060 udata.change = ObjectChangeType.groupPUS;
11713 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12061 updatehandler(localId, udata, this);
11714 break; 12062 break;
12063
12064 default:
12065 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12066 break;
12067 }
11715 } 12068 }
11716 12069
11717// for (int j = 0; j < parts.Length; j++)
11718// parts[j].IgnoreUndoUpdate = false;
11719 } 12070 }
11720 } 12071 }
11721 } 12072 }
11722
11723 return true; 12073 return true;
11724 } 12074 }
11725 12075
@@ -11780,9 +12130,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11780 public void SetChildAgentThrottle(byte[] throttles) 12130 public void SetChildAgentThrottle(byte[] throttles)
11781 { 12131 {
11782 m_udpClient.SetThrottles(throttles); 12132 m_udpClient.SetThrottles(throttles);
12133 GenericCall2 handler = OnUpdateThrottles;
12134 if (handler != null)
12135 {
12136 handler();
12137 }
11783 } 12138 }
11784 12139
11785 /// <summary> 12140 /// <summary>
12141 /// Sets the throttles from values supplied by the client
12142 /// </summary>
12143 /// <param name="throttles"></param>
12144 public void SetAgentThrottleSilent(int throttle, int setting)
12145 {
12146 m_udpClient.ForceThrottleSetting(throttle,setting);
12147 //m_udpClient.SetThrottles(throttles);
12148
12149 }
12150
12151
12152 /// <summary>
11786 /// Get the current throttles for this client as a packed byte array 12153 /// Get the current throttles for this client as a packed byte array
11787 /// </summary> 12154 /// </summary>
11788 /// <param name="multiplier">Unused</param> 12155 /// <param name="multiplier">Unused</param>
@@ -11874,17 +12241,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11874 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); 12241 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11875 } 12242 }
11876 12243
11877 public bool AddMoney(int debit)
11878 {
11879 if (m_moneyBalance + debit >= 0)
11880 {
11881 m_moneyBalance += debit;
11882 SendMoneyBalance(UUID.Zero, true, Util.StringToBytes256("Poof Poof!"), m_moneyBalance);
11883 return true;
11884 }
11885 return false;
11886 }
11887
11888 protected void HandleAutopilot(Object sender, string method, List<String> args) 12244 protected void HandleAutopilot(Object sender, string method, List<String> args)
11889 { 12245 {
11890 float locx = 0; 12246 float locx = 0;
@@ -12174,7 +12530,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12174// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12530// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12175// requestID, taskID, (SourceType)sourceType, Name); 12531// requestID, taskID, (SourceType)sourceType, Name);
12176 12532
12533
12534 //Note, the bool returned from the below function is useless since it is always false.
12177 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12535 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12536
12178 } 12537 }
12179 12538
12180 /// <summary> 12539 /// <summary>
@@ -12240,7 +12599,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12240 /// <returns></returns> 12599 /// <returns></returns>
12241 private static int CalculateNumPackets(byte[] data) 12600 private static int CalculateNumPackets(byte[] data)
12242 { 12601 {
12243 const uint m_maxPacketSize = 600; 12602// const uint m_maxPacketSize = 600;
12603 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12244 int numPackets = 1; 12604 int numPackets = 1;
12245 12605
12246 if (data == null) 12606 if (data == null)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 621e0fd..e52ac37 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -92,7 +92,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
92 /// <summary>Packets we have sent that need to be ACKed by the client</summary> 92 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
93 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 93 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
94 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 94 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
95 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); 95 public readonly DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>();
96 96
97 /// <summary>Current packet sequence number</summary> 97 /// <summary>Current packet sequence number</summary>
98 public int CurrentSequence; 98 public int CurrentSequence;
@@ -146,7 +146,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
146 /// <summary>Throttle buckets for each packet category</summary> 146 /// <summary>Throttle buckets for each packet category</summary>
147 private readonly TokenBucket[] m_throttleCategories; 147 private readonly TokenBucket[] m_throttleCategories;
148 /// <summary>Outgoing queues for throttled packets</summary> 148 /// <summary>Outgoing queues for throttled packets</summary>
149 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 149 private readonly DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
150 /// <summary>A container that can hold one packet for each outbox, used to store 150 /// <summary>A container that can hold one packet for each outbox, used to store
151 /// dequeued packets that are being held for throttling</summary> 151 /// dequeued packets that are being held for throttling</summary>
152 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 152 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
@@ -158,6 +158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
158 158
159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
160 private int m_maxRTO = 60000; 160 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true;
161 162
162 /// <summary> 163 /// <summary>
163 /// Default constructor 164 /// Default constructor
@@ -201,7 +202,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
201 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 202 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
202 203
203 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 204 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
204 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 205 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
205 // Initialize the token buckets that control the throttling for each category 206 // Initialize the token buckets that control the throttling for each category
206 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); 207 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
207 } 208 }
@@ -429,11 +430,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
429 /// </returns> 430 /// </returns>
430 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) 431 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
431 { 432 {
433 return EnqueueOutgoing(packet, forceQueue, false);
434 }
435
436 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
437 {
432 int category = (int)packet.Category; 438 int category = (int)packet.Category;
433 439
434 if (category >= 0 && category < m_packetOutboxes.Length) 440 if (category >= 0 && category < m_packetOutboxes.Length)
435 { 441 {
436 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 442 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
443
444 if (m_deliverPackets == false)
445 {
446 queue.Enqueue(packet, highPriority);
447 return true;
448 }
449
437 TokenBucket bucket = m_throttleCategories[category]; 450 TokenBucket bucket = m_throttleCategories[category];
438 451
439 // Don't send this packet if there is already a packet waiting in the queue 452 // Don't send this packet if there is already a packet waiting in the queue
@@ -441,7 +454,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
441 // queued packets 454 // queued packets
442 if (queue.Count > 0) 455 if (queue.Count > 0)
443 { 456 {
444 queue.Enqueue(packet); 457 queue.Enqueue(packet, highPriority);
445 return true; 458 return true;
446 } 459 }
447 460
@@ -454,7 +467,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
454 else 467 else
455 { 468 {
456 // Force queue specified or not enough tokens in the bucket, queue this packet 469 // Force queue specified or not enough tokens in the bucket, queue this packet
457 queue.Enqueue(packet); 470 queue.Enqueue(packet, highPriority);
458 return true; 471 return true;
459 } 472 }
460 } 473 }
@@ -483,8 +496,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
483 /// <returns>True if any packets were sent, otherwise false</returns> 496 /// <returns>True if any packets were sent, otherwise false</returns>
484 public bool DequeueOutgoing() 497 public bool DequeueOutgoing()
485 { 498 {
486 OutgoingPacket packet; 499 if (m_deliverPackets == false) return false;
487 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 500
501 OutgoingPacket packet = null;
502 DoubleLocklessQueue<OutgoingPacket> queue;
488 TokenBucket bucket; 503 TokenBucket bucket;
489 bool packetSent = false; 504 bool packetSent = false;
490 ThrottleOutPacketTypeFlags emptyCategories = 0; 505 ThrottleOutPacketTypeFlags emptyCategories = 0;
@@ -515,32 +530,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
515 // No dequeued packet waiting to be sent, try to pull one off 530 // No dequeued packet waiting to be sent, try to pull one off
516 // this queue 531 // this queue
517 queue = m_packetOutboxes[i]; 532 queue = m_packetOutboxes[i];
518 if (queue.Dequeue(out packet)) 533 if (queue != null)
519 { 534 {
520 // A packet was pulled off the queue. See if we have 535 bool success = false;
521 // enough tokens in the bucket to send it out 536 try
522 if (bucket.RemoveTokens(packet.Buffer.DataLength))
523 { 537 {
524 // Send the packet 538 success = queue.Dequeue(out packet);
525 m_udpServer.SendPacketFinal(packet);
526 packetSent = true;
527 } 539 }
528 else 540 catch
529 { 541 {
530 // Save the dequeued packet for the next iteration 542 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
531 m_nextPackets[i] = packet;
532 } 543 }
533 544 if (success)
534 // If the queue is empty after this dequeue, fire the queue 545 {
535 // empty callback now so it has a chance to fill before we 546 // A packet was pulled off the queue. See if we have
536 // get back here 547 // enough tokens in the bucket to send it out
537 if (queue.Count == 0) 548 if (bucket.RemoveTokens(packet.Buffer.DataLength))
549 {
550 // Send the packet
551 m_udpServer.SendPacketFinal(packet);
552 packetSent = true;
553 }
554 else
555 {
556 // Save the dequeued packet for the next iteration
557 m_nextPackets[i] = packet;
558 }
559
560 // If the queue is empty after this dequeue, fire the queue
561 // empty callback now so it has a chance to fill before we
562 // get back here
563 if (queue.Count == 0)
564 emptyCategories |= CategoryToFlag(i);
565 }
566 else
567 {
568 // No packets in this queue. Fire the queue empty callback
569 // if it has not been called recently
538 emptyCategories |= CategoryToFlag(i); 570 emptyCategories |= CategoryToFlag(i);
571 }
539 } 572 }
540 else 573 else
541 { 574 {
542 // No packets in this queue. Fire the queue empty callback 575 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
543 // if it has not been called recently
544 emptyCategories |= CategoryToFlag(i); 576 emptyCategories |= CategoryToFlag(i);
545 } 577 }
546 } 578 }
@@ -649,6 +681,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
649 if (m_nextOnQueueEmpty == 0) 681 if (m_nextOnQueueEmpty == 0)
650 m_nextOnQueueEmpty = 1; 682 m_nextOnQueueEmpty = 1;
651 } 683 }
684 internal void ForceThrottleSetting(int throttle, int setting)
685 {
686 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ;
687 }
652 688
653 /// <summary> 689 /// <summary>
654 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a 690 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
@@ -693,4 +729,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
693 } 729 }
694 } 730 }
695 } 731 }
732
733 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
734 {
735 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
736
737 public override int Count
738 {
739 get
740 {
741 return base.Count + highQueue.Count;
742 }
743 }
744
745 public override bool Dequeue(out T item)
746 {
747 if (highQueue.Dequeue(out item))
748 return true;
749
750 return base.Dequeue(out item);
751 }
752
753 public void Enqueue(T item, bool highPriority)
754 {
755 if (highPriority)
756 highQueue.Enqueue(item);
757 else
758 Enqueue(item);
759 }
760 }
696} 761}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 72516cd..4154ef2 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -126,7 +126,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 /// <summary>Handlers for incoming packets</summary> 126 /// <summary>Handlers for incoming packets</summary>
127 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 127 //PacketEventDictionary packetEvents = new PacketEventDictionary();
128 /// <summary>Incoming packets that are awaiting handling</summary> 128 /// <summary>Incoming packets that are awaiting handling</summary>
129 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 129 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
130
131 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
130 132
131 /// <summary></summary> 133 /// <summary></summary>
132 //private UDPClientCollection m_clients = new UDPClientCollection(); 134 //private UDPClientCollection m_clients = new UDPClientCollection();
@@ -181,6 +183,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 /// <summary>Flag to signal when clients should send pings</summary> 183 /// <summary>Flag to signal when clients should send pings</summary>
182 protected bool m_sendPing; 184 protected bool m_sendPing;
183 185
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
184 private Pool<IncomingPacket> m_incomingPacketPool; 187 private Pool<IncomingPacket> m_incomingPacketPool;
185 188
186 /// <summary> 189 /// <summary>
@@ -787,6 +790,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
787 790
788 #region Queue or Send 791 #region Queue or Send
789 792
793 bool highPriority = false;
794
795 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
796 {
797 category = (ThrottleOutPacketType)((int)category & 127);
798 highPriority = true;
799 }
800
790 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 801 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
791 // If we were not provided a method for handling unacked, use the UDPServer default method 802 // If we were not provided a method for handling unacked, use the UDPServer default method
792 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 803 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
@@ -795,7 +806,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
795 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 806 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
796 // packet so that it isn't sent before a queued update packet. 807 // packet so that it isn't sent before a queued update packet.
797 bool requestQueue = type == PacketType.KillObject; 808 bool requestQueue = type == PacketType.KillObject;
798 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 809 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
799 SendPacketFinal(outgoingPacket); 810 SendPacketFinal(outgoingPacket);
800 811
801 #endregion Queue or Send 812 #endregion Queue or Send
@@ -1080,21 +1091,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1080 1091
1081 #region Packet to Client Mapping 1092 #region Packet to Client Mapping
1082 1093
1083 // UseCircuitCode handling 1094 // If there is already a client for this endpoint, don't process UseCircuitCode
1084 if (packet.Type == PacketType.UseCircuitCode) 1095 IClientAPI client = null;
1096 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1085 { 1097 {
1086 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1098 // UseCircuitCode handling
1087 // buffer. 1099 if (packet.Type == PacketType.UseCircuitCode)
1088 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1100 {
1101 // And if there is a UseCircuitCode pending, also drop it
1102 lock (m_pendingCache)
1103 {
1104 if (m_pendingCache.Contains(endPoint))
1105 return;
1089 1106
1090 Util.FireAndForget(HandleUseCircuitCode, array); 1107 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1108 }
1091 1109
1092 return; 1110 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1111 // buffer.
1112 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1113
1114 Util.FireAndForget(HandleUseCircuitCode, array);
1115
1116 return;
1117 }
1118 }
1119
1120 // If this is a pending connection, enqueue, don't process yet
1121 lock (m_pendingCache)
1122 {
1123 Queue<UDPPacketBuffer> queue;
1124 if (m_pendingCache.TryGetValue(endPoint, out queue))
1125 {
1126 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1127 queue.Enqueue(buffer);
1128 return;
1129 }
1093 } 1130 }
1094 1131
1095 // Determine which agent this packet came from 1132 // Determine which agent this packet came from
1096 IClientAPI client; 1133 if (client == null || !(client is LLClientView))
1097 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1098 { 1134 {
1099 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1100 return; 1136 return;
@@ -1103,7 +1139,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1103 udpClient = ((LLClientView)client).UDPClient; 1139 udpClient = ((LLClientView)client).UDPClient;
1104 1140
1105 if (!udpClient.IsConnected) 1141 if (!udpClient.IsConnected)
1142 {
1143 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1106 return; 1144 return;
1145 }
1107 1146
1108 #endregion Packet to Client Mapping 1147 #endregion Packet to Client Mapping
1109 1148
@@ -1233,7 +1272,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1272 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1234 } 1273 }
1235 1274
1236 packetInbox.Enqueue(incomingPacket); 1275 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1276 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1277 packetInbox.EnqueueHigh(incomingPacket);
1278 else
1279 packetInbox.EnqueueLow(incomingPacket);
1237 } 1280 }
1238 1281
1239 #region BinaryStats 1282 #region BinaryStats
@@ -1379,6 +1422,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1379 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1422 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1380 if (client != null) 1423 if (client != null)
1381 client.SceneAgent.SendInitialDataToMe(); 1424 client.SceneAgent.SendInitialDataToMe();
1425
1426 // Now we know we can handle more data
1427 Thread.Sleep(200);
1428
1429 // Obtain the queue and remove it from the cache
1430 Queue<UDPPacketBuffer> queue = null;
1431
1432 lock (m_pendingCache)
1433 {
1434 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1435 {
1436 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1437 return;
1438 }
1439 m_pendingCache.Remove(endPoint);
1440 }
1441
1442 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1443
1444 // Reinject queued packets
1445 while(queue.Count > 0)
1446 {
1447 UDPPacketBuffer buf = queue.Dequeue();
1448 PacketReceived(buf);
1449 }
1450 queue = null;
1382 } 1451 }
1383 else 1452 else
1384 { 1453 {
@@ -1386,6 +1455,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1386 m_log.WarnFormat( 1455 m_log.WarnFormat(
1387 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1456 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1388 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1457 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1458 lock (m_pendingCache)
1459 m_pendingCache.Remove(endPoint);
1389 } 1460 }
1390 1461
1391 // m_log.DebugFormat( 1462 // m_log.DebugFormat(
@@ -1504,7 +1575,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1504 if (!client.SceneAgent.IsChildAgent) 1575 if (!client.SceneAgent.IsChildAgent)
1505 client.Kick("Simulator logged you out due to connection timeout"); 1576 client.Kick("Simulator logged you out due to connection timeout");
1506 1577
1507 client.CloseWithoutChecks(); 1578 client.CloseWithoutChecks(true);
1508 } 1579 }
1509 } 1580 }
1510 1581
@@ -1516,6 +1587,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1516 1587
1517 while (IsRunningInbound) 1588 while (IsRunningInbound)
1518 { 1589 {
1590 m_scene.ThreadAlive(1);
1519 try 1591 try
1520 { 1592 {
1521 IncomingPacket incomingPacket = null; 1593 IncomingPacket incomingPacket = null;
@@ -1563,6 +1635,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1563 1635
1564 while (base.IsRunningOutbound) 1636 while (base.IsRunningOutbound)
1565 { 1637 {
1638 m_scene.ThreadAlive(2);
1566 try 1639 try
1567 { 1640 {
1568 m_packetSent = false; 1641 m_packetSent = false;
@@ -1793,8 +1866,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1793 Packet packet = incomingPacket.Packet; 1866 Packet packet = incomingPacket.Packet;
1794 LLClientView client = incomingPacket.Client; 1867 LLClientView client = incomingPacket.Client;
1795 1868
1796 if (client.IsActive) 1869// if (client.IsActive)
1797 { 1870// {
1798 m_currentIncomingClient = client; 1871 m_currentIncomingClient = client;
1799 1872
1800 try 1873 try
@@ -1821,13 +1894,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1821 { 1894 {
1822 m_currentIncomingClient = null; 1895 m_currentIncomingClient = null;
1823 } 1896 }
1824 } 1897// }
1825 else 1898// else
1826 { 1899// {
1827 m_log.DebugFormat( 1900// m_log.DebugFormat(
1828 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1901// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1829 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1902// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1830 } 1903// }
1831 1904
1832 IncomingPacketsProcessed++; 1905 IncomingPacketsProcessed++;
1833 } 1906 }
@@ -1839,8 +1912,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1839 if (!client.IsLoggingOut) 1912 if (!client.IsLoggingOut)
1840 { 1913 {
1841 client.IsLoggingOut = true; 1914 client.IsLoggingOut = true;
1842 client.Close(); 1915 client.Close(false, false);
1843 } 1916 }
1844 } 1917 }
1845 } 1918 }
1846} \ No newline at end of file 1919}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f143c32..7035e38 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -114,10 +114,6 @@ namespace OpenMetaverse
114 const int SIO_UDP_CONNRESET = -1744830452; 114 const int SIO_UDP_CONNRESET = -1744830452;
115 115
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
117
118 m_log.DebugFormat(
119 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
120 ipep.Address, ipep.Port);
121 117
122 m_udpSocket = new Socket( 118 m_udpSocket = new Socket(
123 AddressFamily.InterNetwork, 119 AddressFamily.InterNetwork,