aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs894
-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.cs382
-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.cs1494
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs122
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
16 files changed, 3742 insertions, 1197 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index a46c24a..59b9585 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(
@@ -404,62 +486,176 @@ namespace OpenSim.Region.ClientStack.Linden
404 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 486 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
405 //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);
406 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
407 if (llsdRequest.asset_type == "texture" || 531 if (llsdRequest.asset_type == "texture" ||
408 llsdRequest.asset_type == "animation" || 532 llsdRequest.asset_type == "animation" ||
533 llsdRequest.asset_type == "mesh" ||
409 llsdRequest.asset_type == "sound") 534 llsdRequest.asset_type == "sound")
410 { 535 {
411 ScenePresence avatar = null; 536 ScenePresence avatar = null;
412 IClientAPI client = null;
413 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 537 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
414 538
415 // check user level 539 // check user level
416 if (avatar != null) 540 if (avatar != null)
417 { 541 {
418 client = avatar.ControllingClient;
419
420 if (avatar.UserLevel < m_levelUpload) 542 if (avatar.UserLevel < m_levelUpload)
421 { 543 {
422 if (client != null) 544 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
423 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 545 resperror.message = "Insufficient permissions to upload";
546 resperror.identifier = UUID.Zero;
424 547
425 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 548 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
426 errorResponse.uploader = ""; 549 errorResponse.uploader = "";
427 errorResponse.state = "error"; 550 errorResponse.state = "error";
551 errorResponse.error = resperror;
552 lock (m_ModelCost)
553 m_FileAgentInventoryState = FileAgentInventoryState.idle;
428 return errorResponse; 554 return errorResponse;
429 } 555 }
430 } 556 }
431 557
432 // check funds 558 // check test upload and funds
433 if (client != null) 559 if (client != null)
434 { 560 {
435 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 561 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
436 562
563 int baseCost = 0;
437 if (mm != null) 564 if (mm != null)
565 baseCost = mm.UploadCharge;
566
567 string warning = String.Empty;
568
569 if (llsdRequest.asset_type == "mesh")
438 { 570 {
439 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))
440 { 576 {
441 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 577 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
578 resperror.message = error;
579 resperror.identifier = UUID.Zero;
442 580
443 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 581 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
444 errorResponse.uploader = ""; 582 errorResponse.uploader = "";
445 errorResponse.state = "error"; 583 errorResponse.state = "error";
584 errorResponse.error = resperror;
585
586 lock (m_ModelCost)
587 m_FileAgentInventoryState = FileAgentInventoryState.idle;
446 return errorResponse; 588 return errorResponse;
447 } 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 }
448 } 637 }
638
639 if (client != null && warning != String.Empty)
640 client.SendAgentAlertMessage(warning, true);
449 } 641 }
450 } 642 }
451 643
452 string assetName = llsdRequest.name;
453 string assetDes = llsdRequest.description; 644 string assetDes = llsdRequest.description;
454 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 645 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
455 UUID newAsset = UUID.Random(); 646 UUID newAsset = UUID.Random();
456 UUID newInvItem = UUID.Random(); 647 UUID newInvItem = UUID.Random();
457 UUID parentFolder = llsdRequest.folder_id; 648 UUID parentFolder = llsdRequest.folder_id;
458 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;
459 654
460 AssetUploader uploader = 655 AssetUploader uploader =
461 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 656 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
462 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);
463 659
464 m_HostCapsObj.HttpListener.AddStreamHandler( 660 m_HostCapsObj.HttpListener.AddStreamHandler(
465 new BinaryStreamHandler( 661 new BinaryStreamHandler(
@@ -477,10 +673,22 @@ namespace OpenSim.Region.ClientStack.Linden
477 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 673 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
478 uploaderPath; 674 uploaderPath;
479 675
676
480 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 677 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
481 uploadResponse.uploader = uploaderURL; 678 uploadResponse.uploader = uploaderURL;
482 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
483 uploader.OnUpLoad += UploadCompleteHandler; 687 uploader.OnUpLoad += UploadCompleteHandler;
688
689 lock (m_ModelCost)
690 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
691
484 return uploadResponse; 692 return uploadResponse;
485 } 693 }
486 694
@@ -492,8 +700,14 @@ namespace OpenSim.Region.ClientStack.Linden
492 /// <param name="data"></param> 700 /// <param name="data"></param>
493 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 701 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
494 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 702 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
495 string assetType) 703 string assetType, int cost,
704 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
705 bool IsAtestUpload, ref string error)
496 { 706 {
707
708 lock (m_ModelCost)
709 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
710
497 m_log.DebugFormat( 711 m_log.DebugFormat(
498 "[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}",
499 assetID, inventoryItem, inventoryType, assetType); 713 assetID, inventoryItem, inventoryType, assetType);
@@ -501,117 +715,247 @@ namespace OpenSim.Region.ClientStack.Linden
501 sbyte assType = 0; 715 sbyte assType = 0;
502 sbyte inType = 0; 716 sbyte inType = 0;
503 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
504 if (inventoryType == "sound") 746 if (inventoryType == "sound")
505 { 747 {
506 inType = 1; 748 inType = (sbyte)InventoryType.Sound;
507 assType = 1; 749 assType = (sbyte)AssetType.Sound;
508 } 750 }
509 else if (inventoryType == "animation") 751 else if (inventoryType == "animation")
510 { 752 {
511 inType = 19; 753 inType = (sbyte)InventoryType.Animation;
512 assType = 20; 754 assType = (sbyte)AssetType.Animation;
513 } 755 }
514 else if (inventoryType == "wearable") 756 else if (inventoryType == "wearable")
515 { 757 {
516 inType = 18; 758 inType = (sbyte)InventoryType.Wearable;
517 switch (assetType) 759 switch (assetType)
518 { 760 {
519 case "bodypart": 761 case "bodypart":
520 assType = 13; 762 assType = (sbyte)AssetType.Bodypart;
521 break; 763 break;
522 case "clothing": 764 case "clothing":
523 assType = 5; 765 assType = (sbyte)AssetType.Clothing;
524 break; 766 break;
525 } 767 }
526 } 768 }
527 else if (inventoryType == "object") 769 else if (inventoryType == "object")
528 { 770 {
529 inType = (sbyte)InventoryType.Object; 771 if (assetType == "mesh") // this code for now is for mesh models uploads only
530 assType = (sbyte)AssetType.Object;
531
532 List<Vector3> positions = new List<Vector3>();
533 List<Quaternion> rotations = new List<Quaternion>();
534 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
535 OSDArray instance_list = (OSDArray)request["instance_list"];
536 OSDArray mesh_list = (OSDArray)request["mesh_list"];
537 OSDArray texture_list = (OSDArray)request["texture_list"];
538 SceneObjectGroup grp = null;
539
540 List<UUID> textures = new List<UUID>();
541 for (int i = 0; i < texture_list.Count; i++)
542 { 772 {
543 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 773 inType = (sbyte)InventoryType.Object;
544 textureAsset.Data = texture_list[i].AsBinary(); 774 assType = (sbyte)AssetType.Object;
545 m_assetService.Store(textureAsset);
546 textures.Add(textureAsset.FullID);
547 }
548 775
549 for (int i = 0; i < mesh_list.Count; i++) 776 List<Vector3> positions = new List<Vector3>();
550 { 777 List<Quaternion> rotations = new List<Quaternion>();
551 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 778 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
779
780 // compare and get updated information
552 781
553 Primitive.TextureEntry textureEntry 782 bool mismatchError = true;
554 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
555 OSDMap inner_instance_list = (OSDMap)instance_list[i];
556 783
557 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 784 while (mismatchError)
558 for (uint face = 0; face < face_list.Count; face++)
559 { 785 {
560 OSDMap faceMap = (OSDMap)face_list[(int)face]; 786 mismatchError = false;
561 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 787 }
562 if(faceMap.ContainsKey("fullbright"))
563 f.Fullbright = faceMap["fullbright"].AsBoolean();
564 if (faceMap.ContainsKey ("diffuse_color"))
565 f.RGBA = faceMap["diffuse_color"].AsColor4();
566 788
567 int textureNum = faceMap["image"].AsInteger(); 789 if (mismatchError)
568 float imagerot = faceMap["imagerot"].AsInteger(); 790 {
569 float offsets = (float)faceMap["offsets"].AsReal(); 791 error = "Upload and fee estimation information don't match";
570 float offsett = (float)faceMap["offsett"].AsReal(); 792 lock (m_ModelCost)
571 float scales = (float)faceMap["scales"].AsReal(); 793 m_FileAgentInventoryState = FileAgentInventoryState.idle;
572 float scalet = (float)faceMap["scalet"].AsReal();
573 794
574 if(imagerot != 0) 795 return;
575 f.Rotation = imagerot; 796 }
576 797
577 if(offsets != 0) 798 OSDArray instance_list = (OSDArray)request["instance_list"];
578 f.OffsetU = offsets; 799 OSDArray mesh_list = (OSDArray)request["mesh_list"];
800 OSDArray texture_list = (OSDArray)request["texture_list"];
801 SceneObjectGroup grp = null;
579 802
580 if (offsett != 0) 803 // create and store texture assets
581 f.OffsetV = offsett; 804 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
805 texturesFolder != UUID.Zero);
582 806
583 if (scales != 0)
584 f.RepeatU = scales;
585 807
586 if (scalet != 0) 808 List<UUID> textures = new List<UUID>();
587 f.RepeatV = scalet;
588 809
589 if (textures.Count > textureNum) 810
590 f.TextureID = textures[textureNum]; 811 if (doTextInv)
591 else 812 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
592 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; 813
814 if(client == null) // don't put textures in inventory if there is no client
815 doTextInv = false;
816
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 }
593 856
594 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);
595 } 867 }
596 868
597 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();
885
886 Primitive.TextureEntry textureEntry
887 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
598 888
599 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, "");
600 meshAsset.Data = mesh_list[i].AsBinary();
601 m_assetService.Store(meshAsset);
602 889
603 pbs.SculptEntry = true; 890 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
604 pbs.SculptTexture = meshAsset.FullID; 891 for (uint face = 0; face < face_list.Count; face++)
605 pbs.SculptType = (byte)SculptType.Mesh; 892 {
606 pbs.SculptData = meshAsset.Data; 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();
607 948
608 Vector3 position = inner_instance_list["position"].AsVector3(); 949 // for now viwers do send fixed defaults
609 Vector3 scale = inner_instance_list["scale"].AsVector3(); 950 // but this may change
610 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 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;
611 957
612// no longer used - begin ------------------------ 958// no longer used - begin ------------------------
613// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
614// int material = inner_instance_list["material"].AsInteger();
615// int mesh = inner_instance_list["mesh"].AsInteger(); 959// int mesh = inner_instance_list["mesh"].AsInteger();
616 960
617// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 961// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -626,24 +970,42 @@ namespace OpenSim.Region.ClientStack.Linden
626// UUID owner_id = permissions["owner_id"].AsUUID(); 970// UUID owner_id = permissions["owner_id"].AsUUID();
627// int owner_mask = permissions["owner_mask"].AsInteger(); 971// int owner_mask = permissions["owner_mask"].AsInteger();
628// 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();
629 992
630 UUID owner_id = m_HostCapsObj.AgentID; 993 if (restrictPerms)
994 {
995 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
996 prim.EveryoneMask = 0;
997 prim.GroupMask = 0;
998 prim.NextOwnerMask = 0;
999 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1000 }
631 1001
632 SceneObjectPart prim 1002 if(istest)
633 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 1003 prim.Description = "For testing only. Other uses are prohibited";
1004 else
1005 prim.Description = "";
634 1006
635 prim.Scale = scale; 1007 prim.Material = material;
636 //prim.OffsetPosition = position; 1008 prim.PhysicsShapeType = physicsShapeType;
637 rotations.Add(rotation);
638 positions.Add(position);
639 prim.UUID = UUID.Random();
640 prim.CreatorID = owner_id;
641 prim.OwnerID = owner_id;
642 prim.GroupID = UUID.Zero;
643 prim.LastOwnerID = prim.OwnerID;
644 prim.CreationDate = Util.UnixTimeSinceEpoch();
645 prim.Name = assetName;
646 prim.Description = "";
647 1009
648// prim.BaseMask = (uint)base_mask; 1010// prim.BaseMask = (uint)base_mask;
649// prim.EveryoneMask = (uint)everyone_mask; 1011// prim.EveryoneMask = (uint)everyone_mask;
@@ -651,52 +1013,64 @@ namespace OpenSim.Region.ClientStack.Linden
651// prim.NextOwnerMask = (uint)next_owner_mask; 1013// prim.NextOwnerMask = (uint)next_owner_mask;
652// prim.OwnerMask = (uint)owner_mask; 1014// prim.OwnerMask = (uint)owner_mask;
653 1015
654 if (grp == null) 1016 if (grp == null)
655 grp = new SceneObjectGroup(prim); 1017 {
656 else 1018 grp = new SceneObjectGroup(prim);
657 grp.AddPart(prim); 1019 grp.LastOwnerID = creatorID;
658 } 1020 }
1021 else
1022 grp.AddPart(prim);
1023 }
659 1024
660 Vector3 rootPos = positions[0]; 1025 Vector3 rootPos = positions[0];
661 1026
662 if (grp.Parts.Length > 1) 1027 if (grp.Parts.Length > 1)
663 { 1028 {
664 // Fix first link number 1029 // Fix first link number
665 grp.RootPart.LinkNum++; 1030 grp.RootPart.LinkNum++;
666 1031
667 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1032 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
668 Quaternion tmprot; 1033 Quaternion tmprot;
669 Vector3 offset; 1034 Vector3 offset;
670 1035
671 // fix children rotations and positions 1036 // fix children rotations and positions
672 for (int i = 1; i < rotations.Count; i++) 1037 for (int i = 1; i < rotations.Count; i++)
673 { 1038 {
674 tmprot = rotations[i]; 1039 tmprot = rotations[i];
675 tmprot = rootRotConj * tmprot; 1040 tmprot = rootRotConj * tmprot;
676 1041
677 grp.Parts[i].RotationOffset = tmprot; 1042 grp.Parts[i].RotationOffset = tmprot;
678 1043
679 offset = positions[i] - rootPos; 1044 offset = positions[i] - rootPos;
1045
1046 offset *= rootRotConj;
1047 grp.Parts[i].OffsetPosition = offset;
1048 }
680 1049
681 offset *= rootRotConj; 1050 grp.AbsolutePosition = rootPos;
682 grp.Parts[i].OffsetPosition = offset; 1051 grp.UpdateGroupRotationR(rotations[0]);
1052 }
1053 else
1054 {
1055 grp.AbsolutePosition = rootPos;
1056 grp.UpdateGroupRotationR(rotations[0]);
683 } 1057 }
684 1058
685 grp.AbsolutePosition = rootPos; 1059 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
686 grp.UpdateGroupRotationR(rotations[0]);
687 } 1060 }
688 else 1061
1062 else // not a mesh model
689 { 1063 {
690 grp.AbsolutePosition = rootPos; 1064 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
691 grp.UpdateGroupRotationR(rotations[0]); 1065 return;
692 } 1066 }
693
694 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
695 } 1067 }
696 1068
697 AssetBase asset; 1069 AssetBase asset;
698 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1070 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
699 asset.Data = data; 1071 asset.Data = data;
1072 if (istest)
1073 asset.Local = true;
700 if (AddNewAsset != null) 1074 if (AddNewAsset != null)
701 AddNewAsset(asset); 1075 AddNewAsset(asset);
702 else if (m_assetService != null) 1076 else if (m_assetService != null)
@@ -704,11 +1078,17 @@ namespace OpenSim.Region.ClientStack.Linden
704 1078
705 InventoryItemBase item = new InventoryItemBase(); 1079 InventoryItemBase item = new InventoryItemBase();
706 item.Owner = m_HostCapsObj.AgentID; 1080 item.Owner = m_HostCapsObj.AgentID;
707 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1081 item.CreatorId = creatorIDstr;
708 item.CreatorData = String.Empty; 1082 item.CreatorData = String.Empty;
709 item.ID = inventoryItem; 1083 item.ID = inventoryItem;
710 item.AssetID = asset.FullID; 1084 item.AssetID = asset.FullID;
711 item.Description = assetDescription; 1085 if (istest)
1086 {
1087 item.Description = "For testing only. Other uses are prohibited";
1088 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1089 }
1090 else
1091 item.Description = assetDescription;
712 item.Name = assetName; 1092 item.Name = assetName;
713 item.AssetType = assType; 1093 item.AssetType = assType;
714 item.InvType = inType; 1094 item.InvType = inType;
@@ -716,18 +1096,60 @@ namespace OpenSim.Region.ClientStack.Linden
716 1096
717 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1097 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
718 // (owner) permissions. This becomes a problem if next permissions are changed. 1098 // (owner) permissions. This becomes a problem if next permissions are changed.
719 item.CurrentPermissions
720 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
721 1099
722 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1100 if (restrictPerms)
723 item.EveryOnePermissions = 0; 1101 {
724 item.NextPermissions = (uint)PermissionMask.All; 1102 item.CurrentPermissions
1103 = (uint)(PermissionMask.Move | PermissionMask.Modify);
1104
1105 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1106 item.EveryOnePermissions = 0;
1107 item.NextPermissions = 0;
1108 }
1109 else
1110 {
1111 item.CurrentPermissions
1112 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
1113
1114 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1115 item.EveryOnePermissions = 0;
1116 item.NextPermissions = (uint)PermissionMask.All;
1117 }
1118
725 item.CreationDate = Util.UnixTimeSinceEpoch(); 1119 item.CreationDate = Util.UnixTimeSinceEpoch();
726 1120
1121 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1122
727 if (AddNewInventoryItem != null) 1123 if (AddNewInventoryItem != null)
728 { 1124 {
729 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1125 if (istest)
1126 {
1127 m_Scene.AddInventoryItem(client, item);
1128/*
1129 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1130 if (client != null)
1131 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);
1132 */
1133 }
1134 else
1135 {
1136 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1137// if (client != null)
1138// {
1139// // let users see anything.. i don't so far
1140// string str;
1141// if (cost > 0)
1142// // dont remember where is money unit name to put here
1143// str = "Upload complete. charged " + cost.ToString() + "$";
1144// else
1145// str = "Upload complete";
1146// client.SendAgentAlertMessage(str, true);
1147// }
1148 }
730 } 1149 }
1150
1151 lock (m_ModelCost)
1152 m_FileAgentInventoryState = FileAgentInventoryState.idle;
731 } 1153 }
732 1154
733 /// <summary> 1155 /// <summary>
@@ -920,6 +1342,120 @@ namespace OpenSim.Region.ClientStack.Linden
920 return response; 1342 return response;
921 } 1343 }
922 1344
1345 public string GetObjectCost(string request, string path,
1346 string param, IOSHttpRequest httpRequest,
1347 IOSHttpResponse httpResponse)
1348 {
1349 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1350 OSDMap resp = new OSDMap();
1351
1352 OSDArray object_ids = (OSDArray)req["object_ids"];
1353
1354 for (int i = 0; i < object_ids.Count; i++)
1355 {
1356 UUID uuid = object_ids[i].AsUUID();
1357
1358 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1359
1360 if (part != null)
1361 {
1362 SceneObjectGroup grp = part.ParentGroup;
1363 if (grp != null)
1364 {
1365 float linksetCost;
1366 float linksetPhysCost;
1367 float partCost;
1368 float partPhysCost;
1369
1370 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1371
1372 OSDMap object_data = new OSDMap();
1373 object_data["linked_set_resource_cost"] = linksetCost;
1374 object_data["resource_cost"] = partCost;
1375 object_data["physics_cost"] = partPhysCost;
1376 object_data["linked_set_physics_cost"] = linksetPhysCost;
1377
1378 resp[uuid.ToString()] = object_data;
1379 }
1380 }
1381 }
1382
1383 string response = OSDParser.SerializeLLSDXmlString(resp);
1384 return response;
1385 }
1386
1387 public string ResourceCostSelected(string request, string path,
1388 string param, IOSHttpRequest httpRequest,
1389 IOSHttpResponse httpResponse)
1390 {
1391 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1392 OSDMap resp = new OSDMap();
1393
1394
1395 float phys=0;
1396 float stream=0;
1397 float simul=0;
1398
1399 if (req.ContainsKey("selected_roots"))
1400 {
1401 OSDArray object_ids = (OSDArray)req["selected_roots"];
1402
1403 // should go by SOG suming costs for all parts
1404 // ll v3 works ok with several objects select we get the list and adds ok
1405 // FS calls per object so results are wrong guess fs bug
1406 for (int i = 0; i < object_ids.Count; i++)
1407 {
1408 UUID uuid = object_ids[i].AsUUID();
1409 float Physc;
1410 float simulc;
1411 float streamc;
1412
1413 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1414 if (grp != null)
1415 {
1416 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1417 phys += Physc;
1418 stream += streamc;
1419 simul += simulc;
1420 }
1421 }
1422 }
1423 else if (req.ContainsKey("selected_prims"))
1424 {
1425 OSDArray object_ids = (OSDArray)req["selected_prims"];
1426
1427 // don't see in use in any of the 2 viewers
1428 // guess it should be for edit linked but... nothing
1429 // should go to SOP per part
1430 for (int i = 0; i < object_ids.Count; i++)
1431 {
1432 UUID uuid = object_ids[i].AsUUID();
1433
1434 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1435 if (part != null)
1436 {
1437 phys += part.PhysicsCost;
1438 stream += part.StreamingCost;
1439 simul += part.SimulationCost;
1440 }
1441 }
1442 }
1443
1444 if (simul != 0)
1445 {
1446 OSDMap object_data = new OSDMap();
1447
1448 object_data["physics"] = phys;
1449 object_data["streaming"] = stream;
1450 object_data["simulation"] = simul;
1451
1452 resp["selected"] = object_data;
1453 }
1454
1455 string response = OSDParser.SerializeLLSDXmlString(resp);
1456 return response;
1457 }
1458
923 public string UpdateAgentInformation(string request, string path, 1459 public string UpdateAgentInformation(string request, string path,
924 string param, IOSHttpRequest httpRequest, 1460 string param, IOSHttpRequest httpRequest,
925 IOSHttpResponse httpResponse) 1461 IOSHttpResponse httpResponse)
@@ -939,6 +1475,10 @@ namespace OpenSim.Region.ClientStack.Linden
939 1475
940 public class AssetUploader 1476 public class AssetUploader
941 { 1477 {
1478 private static readonly ILog m_log =
1479 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1480
1481
942 public event UpLoadedAsset OnUpLoad; 1482 public event UpLoadedAsset OnUpLoad;
943 private UpLoadedAsset handlerUpLoad = null; 1483 private UpLoadedAsset handlerUpLoad = null;
944 1484
@@ -953,10 +1493,21 @@ namespace OpenSim.Region.ClientStack.Linden
953 1493
954 private string m_invType = String.Empty; 1494 private string m_invType = String.Empty;
955 private string m_assetType = String.Empty; 1495 private string m_assetType = String.Empty;
1496 private int m_cost;
1497 private string m_error = String.Empty;
1498
1499 private Timer m_timeoutTimer = new Timer();
1500 private UUID m_texturesFolder;
1501 private int m_nreqtextures;
1502 private int m_nreqmeshs;
1503 private int m_nreqinstances;
1504 private bool m_IsAtestUpload;
956 1505
957 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1506 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
958 UUID parentFolderID, string invType, string assetType, string path, 1507 UUID parentFolderID, string invType, string assetType, string path,
959 IHttpServer httpServer, bool dumpAssetsToFile) 1508 IHttpServer httpServer, bool dumpAssetsToFile,
1509 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1510 bool IsAtestUpload)
960 { 1511 {
961 m_assetName = assetName; 1512 m_assetName = assetName;
962 m_assetDes = description; 1513 m_assetDes = description;
@@ -968,6 +1519,18 @@ namespace OpenSim.Region.ClientStack.Linden
968 m_assetType = assetType; 1519 m_assetType = assetType;
969 m_invType = invType; 1520 m_invType = invType;
970 m_dumpAssetsToFile = dumpAssetsToFile; 1521 m_dumpAssetsToFile = dumpAssetsToFile;
1522 m_cost = totalCost;
1523
1524 m_texturesFolder = texturesFolder;
1525 m_nreqtextures = nreqtextures;
1526 m_nreqmeshs = nreqmeshs;
1527 m_nreqinstances = nreqinstances;
1528 m_IsAtestUpload = IsAtestUpload;
1529
1530 m_timeoutTimer.Elapsed += TimedOut;
1531 m_timeoutTimer.Interval = 120000;
1532 m_timeoutTimer.AutoReset = false;
1533 m_timeoutTimer.Start();
971 } 1534 }
972 1535
973 /// <summary> 1536 /// <summary>
@@ -982,12 +1545,14 @@ namespace OpenSim.Region.ClientStack.Linden
982 UUID inv = inventoryItemID; 1545 UUID inv = inventoryItemID;
983 string res = String.Empty; 1546 string res = String.Empty;
984 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1547 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1548/*
985 uploadComplete.new_asset = newAssetID.ToString(); 1549 uploadComplete.new_asset = newAssetID.ToString();
986 uploadComplete.new_inventory_item = inv; 1550 uploadComplete.new_inventory_item = inv;
987 uploadComplete.state = "complete"; 1551 uploadComplete.state = "complete";
988 1552
989 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1553 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
990 1554*/
1555 m_timeoutTimer.Stop();
991 httpListener.RemoveStreamHandler("POST", uploaderPath); 1556 httpListener.RemoveStreamHandler("POST", uploaderPath);
992 1557
993 // TODO: probably make this a better set of extensions here 1558 // TODO: probably make this a better set of extensions here
@@ -1004,12 +1569,49 @@ namespace OpenSim.Region.ClientStack.Linden
1004 handlerUpLoad = OnUpLoad; 1569 handlerUpLoad = OnUpLoad;
1005 if (handlerUpLoad != null) 1570 if (handlerUpLoad != null)
1006 { 1571 {
1007 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1572 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1573 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1574 }
1575 if (m_IsAtestUpload)
1576 {
1577 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1578 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1579 resperror.identifier = inv;
1580
1581 uploadComplete.error = resperror;
1582 uploadComplete.state = "Upload4Testing";
1008 } 1583 }
1584 else
1585 {
1586 if (m_error == String.Empty)
1587 {
1588 uploadComplete.new_asset = newAssetID.ToString();
1589 uploadComplete.new_inventory_item = inv;
1590 // if (m_texturesFolder != UUID.Zero)
1591 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1592 uploadComplete.state = "complete";
1593 }
1594 else
1595 {
1596 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1597 resperror.message = m_error;
1598 resperror.identifier = inv;
1009 1599
1600 uploadComplete.error = resperror;
1601 uploadComplete.state = "failed";
1602 }
1603 }
1604
1605 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1010 return res; 1606 return res;
1011 } 1607 }
1012 1608
1609 private void TimedOut(object sender, ElapsedEventArgs args)
1610 {
1611 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1612 httpListener.RemoveStreamHandler("POST", uploaderPath);
1613 }
1614
1013 ///Left this in and commented in case there are unforseen issues 1615 ///Left this in and commented in case there are unforseen issues
1014 //private void SaveAssetToFile(string filename, byte[] data) 1616 //private void SaveAssetToFile(string filename, byte[] data)
1015 //{ 1617 //{
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..37285e3 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, 1000));
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..d4dbfb9 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,131 @@ 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 }
60
61 public class aPollResponse
62 {
63 public Hashtable response;
64 public int bytes;
65 }
66
67
68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69
60 private Scene m_scene; 70 private Scene m_scene;
61 private IAssetService m_assetService;
62 71
63 private bool m_Enabled = false; 72 private static GetTextureHandler m_getTextureHandler;
73
74 private IAssetService m_assetService = null;
75
76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
77 private static Thread[] m_workerThreads = null;
64 78
65 // TODO: Change this to a config option 79 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
66 const string REDIRECT_URL = null; 80 new OpenMetaverse.BlockingQueue<aPollRequest>();
67 81
68 private string m_URL; 82 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
69 83
70 #region ISharedRegionModule Members 84 #region ISharedRegionModule Members
71 85
72 public void Initialise(IConfigSource source) 86 public void Initialise(IConfigSource source)
73 { 87 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null)
76 return;
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 } 88 }
83 89
84 public void AddRegion(Scene s) 90 public void AddRegion(Scene s)
85 { 91 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 92 m_scene = s;
93 m_assetService = s.AssetService;
90 } 94 }
91 95
92 public void RemoveRegion(Scene s) 96 public void RemoveRegion(Scene s)
93 { 97 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
99 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
100 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 101 m_scene = null;
99 } 102 }
100 103
101 public void RegionLoaded(Scene s) 104 public void RegionLoaded(Scene s)
102 { 105 {
103 if (!m_Enabled) 106 // We'll reuse the same handler for all requests.
104 return; 107 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 108
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 109 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
110 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
111 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
112
113 if (m_workerThreads == null)
114 {
115 m_workerThreads = new Thread[2];
116
117 for (uint i = 0; i < 2; i++)
118 {
119 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
120 String.Format("TextureWorkerThread{0}", i),
121 ThreadPriority.Normal,
122 false,
123 false,
124 null,
125 int.MaxValue);
126 }
127 }
128 }
129 private int ExtractImageThrottle(byte[] pthrottles)
130 {
131
132 byte[] adjData;
133 int pos = 0;
134
135 if (!BitConverter.IsLittleEndian)
136 {
137 byte[] newData = new byte[7 * 4];
138 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
139
140 for (int i = 0; i < 7; i++)
141 Array.Reverse(newData, i * 4, 4);
142
143 adjData = newData;
144 }
145 else
146 {
147 adjData = pthrottles;
148 }
149
150 // 0.125f converts from bits to bytes
151 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
152 //pos += 4;
153 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
154 //pos += 4;
155 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
156 // pos += 4;
157 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
158 // pos += 4;
159 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
160 // pos += 4;
161 pos = pos + 20;
162 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
163 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
164 return texture;
165 }
166
167 // 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.
168 public void ThrottleUpdate(ScenePresence p)
169 {
170 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
171 UUID user = p.UUID;
172 int imagethrottle = ExtractImageThrottle(throttles);
173 PollServiceTextureEventArgs args;
174 if (m_pollservices.TryGetValue(user,out args))
175 {
176 args.UpdateThrottle(imagethrottle);
177 }
108 } 178 }
109 179
110 public void PostInitialise() 180 public void PostInitialise()
@@ -122,24 +192,250 @@ namespace OpenSim.Region.ClientStack.Linden
122 192
123 #endregion 193 #endregion
124 194
125 public void RegisterCaps(UUID agentID, Caps caps) 195 ~GetTextureModule()
196 {
197 foreach (Thread t in m_workerThreads)
198 Watchdog.AbortThread(t.ManagedThreadId);
199
200 }
201
202 private class PollServiceTextureEventArgs : PollServiceEventArgs
126 { 203 {
127 UUID capID = UUID.Random(); 204 private List<Hashtable> requests =
205 new List<Hashtable>();
206 private Dictionary<UUID, aPollResponse> responses =
207 new Dictionary<UUID, aPollResponse>();
128 208
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 209 private Scene m_scene;
130 if (m_URL == "localhost") 210 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
211 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
212 base(null, null, null, null, pId, int.MaxValue)
131 { 213 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 214 m_scene = scene;
133 caps.RegisterHandler( 215 // x is request id, y is userid
134 "GetTexture", 216 HasEvents = (x, y) =>
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 217 {
218 lock (responses)
219 {
220 bool ret = m_throttler.hasEvents(x, responses);
221 m_throttler.ProcessTime();
222 return ret;
223
224 }
225 };
226 GetEvents = (x, y) =>
227 {
228 lock (responses)
229 {
230 try
231 {
232 return responses[x].response;
233 }
234 finally
235 {
236 responses.Remove(x);
237 }
238 }
239 };
240 // x is request id, y is request data hashtable
241 Request = (x, y) =>
242 {
243 aPollRequest reqinfo = new aPollRequest();
244 reqinfo.thepoll = this;
245 reqinfo.reqID = x;
246 reqinfo.request = y;
247
248 m_queue.Enqueue(reqinfo);
249 };
250
251 // this should never happen except possible on shutdown
252 NoEvents = (x, y) =>
253 {
254/*
255 lock (requests)
256 {
257 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
258 requests.Remove(request);
259 }
260*/
261 Hashtable response = new Hashtable();
262
263 response["int_response_code"] = 500;
264 response["str_response_string"] = "Script timeout";
265 response["content_type"] = "text/plain";
266 response["keepalive"] = false;
267 response["reusecontext"] = false;
268
269 return response;
270 };
136 } 271 }
137 else 272
273 public void Process(aPollRequest requestinfo)
274 {
275 Hashtable response;
276
277 UUID requestID = requestinfo.reqID;
278
279 // If the avatar is gone, don't bother to get the texture
280 if (m_scene.GetScenePresence(Id) == null)
281 {
282 response = new Hashtable();
283
284 response["int_response_code"] = 500;
285 response["str_response_string"] = "Script timeout";
286 response["content_type"] = "text/plain";
287 response["keepalive"] = false;
288 response["reusecontext"] = false;
289
290 lock (responses)
291 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
292
293 return;
294 }
295
296 response = m_getTextureHandler.Handle(requestinfo.request);
297 lock (responses)
298 {
299 responses[requestID] = new aPollResponse()
300 {
301 bytes = (int) response["int_bytes"],
302 response = response
303 };
304
305 }
306 m_throttler.ProcessTime();
307 }
308
309 internal void UpdateThrottle(int pimagethrottle)
310 {
311 m_throttler.ThrottleBytes = pimagethrottle;
312 }
313 }
314
315 private void RegisterCaps(UUID agentID, Caps caps)
316 {
317 string capUrl = "/CAPS/" + UUID.Random() + "/";
318
319 // Register this as a poll service
320 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
321
322 args.Type = PollServiceEventArgs.EventType.Texture;
323 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
324
325 string hostName = m_scene.RegionInfo.ExternalHostName;
326 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
327 string protocol = "http";
328
329 if (MainServer.Instance.UseSSL)
330 {
331 hostName = MainServer.Instance.SSLCommonName;
332 port = MainServer.Instance.SSLPort;
333 protocol = "https";
334 }
335 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
336 m_pollservices[agentID] = args;
337 m_capsDict[agentID] = capUrl;
338 }
339
340 private void DeregisterCaps(UUID agentID, Caps caps)
341 {
342 string capUrl;
343 PollServiceTextureEventArgs args;
344 if (m_capsDict.TryGetValue(agentID, out capUrl))
345 {
346 MainServer.Instance.RemoveHTTPHandler("", capUrl);
347 m_capsDict.Remove(agentID);
348 }
349 if (m_pollservices.TryGetValue(agentID, out args))
138 { 350 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 351 m_pollservices.Remove(agentID);
140 caps.RegisterHandler("GetTexture", m_URL);
141 } 352 }
142 } 353 }
143 354
355 private void DoTextureRequests()
356 {
357 while (true)
358 {
359 aPollRequest poolreq = m_queue.Dequeue();
360
361 poolreq.thepoll.Process(poolreq);
362 }
363 }
364 internal sealed class CapsDataThrottler
365 {
366
367 private volatile int currenttime = 0;
368 private volatile int lastTimeElapsed = 0;
369 private volatile int BytesSent = 0;
370 private int oversizedImages = 0;
371 public CapsDataThrottler(int pBytes, int max, int min)
372 {
373 ThrottleBytes = pBytes;
374 lastTimeElapsed = Util.EnvironmentTickCount();
375 }
376 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
377 {
378 PassTime();
379 // Note, this is called IN LOCK
380 bool haskey = responses.ContainsKey(key);
381 if (!haskey)
382 {
383 return false;
384 }
385 GetTextureModule.aPollResponse response;
386 if (responses.TryGetValue(key, out response))
387 {
388
389 // Normal
390 if (BytesSent + response.bytes <= ThrottleBytes)
391 {
392 BytesSent += response.bytes;
393 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
394 //m_actions.Add(timeBasedAction);
395 return true;
396 }
397 // Big textures
398 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
399 {
400 Interlocked.Increment(ref oversizedImages);
401 BytesSent += response.bytes;
402 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
403 //m_actions.Add(timeBasedAction);
404 return true;
405 }
406 else
407 {
408 return false;
409 }
410 }
411
412 return haskey;
413 }
414 public void ProcessTime()
415 {
416 PassTime();
417 }
418
419
420 private void PassTime()
421 {
422 currenttime = Util.EnvironmentTickCount();
423 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
424 //processTimeBasedActions(responses);
425 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
426 {
427 lastTimeElapsed = Util.EnvironmentTickCount();
428 BytesSent -= ThrottleBytes;
429 if (BytesSent < 0) BytesSent = 0;
430 if (BytesSent < ThrottleBytes)
431 {
432 oversizedImages = 0;
433 }
434 }
435 }
436 public int ThrottleBytes;
437 }
144 } 438 }
439
440
145} 441}
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 a168bfe..dfc4419 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 e47397d..ef1d803 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -101,6 +101,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
101 public event AvatarPickerRequest OnAvatarPickerRequest; 101 public event AvatarPickerRequest OnAvatarPickerRequest;
102 public event StartAnim OnStartAnim; 102 public event StartAnim OnStartAnim;
103 public event StopAnim OnStopAnim; 103 public event StopAnim OnStopAnim;
104 public event ChangeAnim OnChangeAnim;
104 public event Action<IClientAPI> OnRequestAvatarsData; 105 public event Action<IClientAPI> OnRequestAvatarsData;
105 public event LinkObjects OnLinkObjects; 106 public event LinkObjects OnLinkObjects;
106 public event DelinkObjects OnDelinkObjects; 107 public event DelinkObjects OnDelinkObjects;
@@ -128,6 +129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; 129 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
129 public event UpdatePrimFlags OnUpdatePrimFlags; 130 public event UpdatePrimFlags OnUpdatePrimFlags;
130 public event UpdatePrimTexture OnUpdatePrimTexture; 131 public event UpdatePrimTexture OnUpdatePrimTexture;
132 public event ClientChangeObject onClientChangeObject;
131 public event UpdateVector OnUpdatePrimGroupPosition; 133 public event UpdateVector OnUpdatePrimGroupPosition;
132 public event UpdateVector OnUpdatePrimSinglePosition; 134 public event UpdateVector OnUpdatePrimSinglePosition;
133 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 135 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
@@ -161,6 +163,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 public event RequestTaskInventory OnRequestTaskInventory; 163 public event RequestTaskInventory OnRequestTaskInventory;
162 public event UpdateInventoryItem OnUpdateInventoryItem; 164 public event UpdateInventoryItem OnUpdateInventoryItem;
163 public event CopyInventoryItem OnCopyInventoryItem; 165 public event CopyInventoryItem OnCopyInventoryItem;
166 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
164 public event MoveInventoryItem OnMoveInventoryItem; 167 public event MoveInventoryItem OnMoveInventoryItem;
165 public event RemoveInventoryItem OnRemoveInventoryItem; 168 public event RemoveInventoryItem OnRemoveInventoryItem;
166 public event RemoveInventoryFolder OnRemoveInventoryFolder; 169 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -259,7 +262,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
259 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 262 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
260 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 263 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
261 public event ClassifiedDelete OnClassifiedDelete; 264 public event ClassifiedDelete OnClassifiedDelete;
262 public event ClassifiedDelete OnClassifiedGodDelete; 265 public event ClassifiedGodDelete OnClassifiedGodDelete;
263 public event EventNotificationAddRequest OnEventNotificationAddRequest; 266 public event EventNotificationAddRequest OnEventNotificationAddRequest;
264 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 267 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
265 public event EventGodDelete OnEventGodDelete; 268 public event EventGodDelete OnEventGodDelete;
@@ -290,10 +293,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
290 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 293 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
291 public event SimWideDeletesDelegate OnSimWideDeletes; 294 public event SimWideDeletesDelegate OnSimWideDeletes;
292 public event SendPostcard OnSendPostcard; 295 public event SendPostcard OnSendPostcard;
296 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
293 public event MuteListEntryUpdate OnUpdateMuteListEntry; 297 public event MuteListEntryUpdate OnUpdateMuteListEntry;
294 public event MuteListEntryRemove OnRemoveMuteListEntry; 298 public event MuteListEntryRemove OnRemoveMuteListEntry;
295 public event GodlikeMessage onGodlikeMessage; 299 public event GodlikeMessage onGodlikeMessage;
296 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 300 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
301 public event GenericCall2 OnUpdateThrottles;
297 302
298 #endregion Events 303 #endregion Events
299 304
@@ -322,11 +327,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
322 private readonly byte[] m_channelVersion = Utils.EmptyBytes; 327 private readonly byte[] m_channelVersion = Utils.EmptyBytes;
323 private readonly IGroupsModule m_GroupsModule; 328 private readonly IGroupsModule m_GroupsModule;
324 329
330 private int m_cachedTextureSerial;
325 private PriorityQueue m_entityUpdates; 331 private PriorityQueue m_entityUpdates;
326 private PriorityQueue m_entityProps; 332 private PriorityQueue m_entityProps;
327 private Prioritizer m_prioritizer; 333 private Prioritizer m_prioritizer;
328 private bool m_disableFacelights = false; 334 private bool m_disableFacelights = false;
329 335
336 private bool m_VelocityInterpolate = false;
337 private const uint MaxTransferBytesPerPacket = 600;
338
339
330 /// <value> 340 /// <value>
331 /// List used in construction of data blocks for an object update packet. This is to stop us having to 341 /// List used in construction of data blocks for an object update packet. This is to stop us having to
332 /// continually recreate it. 342 /// continually recreate it.
@@ -338,13 +348,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
338 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 348 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
339 /// ownerless phantom. 349 /// ownerless phantom.
340 /// 350 ///
341 /// All manipulation of this set has to occur under a lock 351 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
342 /// 352 ///
343 /// </value> 353 /// </value>
344 protected HashSet<uint> m_killRecord; 354// protected HashSet<uint> m_killRecord;
345 355
346// protected HashSet<uint> m_attachmentsSent; 356// protected HashSet<uint> m_attachmentsSent;
347 357
358 private bool m_deliverPackets = true;
348 private int m_animationSequenceNumber = 1; 359 private int m_animationSequenceNumber = 1;
349 private bool m_SendLogoutPacketWhenClosing = true; 360 private bool m_SendLogoutPacketWhenClosing = true;
350 361
@@ -391,6 +402,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
391 get { return m_startpos; } 402 get { return m_startpos; }
392 set { m_startpos = value; } 403 set { m_startpos = value; }
393 } 404 }
405 public bool DeliverPackets
406 {
407 get { return m_deliverPackets; }
408 set {
409 m_deliverPackets = value;
410 m_udpClient.m_deliverPackets = value;
411 }
412 }
394 public UUID AgentId { get { return m_agentId; } } 413 public UUID AgentId { get { return m_agentId; } }
395 public ISceneAgent SceneAgent { get; set; } 414 public ISceneAgent SceneAgent { get; set; }
396 public UUID ActiveGroupId { get { return m_activeGroupID; } } 415 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -441,6 +460,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
441 } 460 }
442 461
443 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 462 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
463
444 464
445 #endregion Properties 465 #endregion Properties
446 466
@@ -467,7 +487,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
467 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 487 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
468 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 488 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
469 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 489 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
470 m_killRecord = new HashSet<uint>(); 490// m_killRecord = new HashSet<uint>();
471// m_attachmentsSent = new HashSet<uint>(); 491// m_attachmentsSent = new HashSet<uint>();
472 492
473 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 493 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -496,12 +516,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
496 516
497 #region Client Methods 517 #region Client Methods
498 518
519
520 /// <summary>
521 /// Close down the client view
522 /// </summary>
499 public void Close() 523 public void Close()
500 { 524 {
501 Close(false); 525 Close(true, false);
502 } 526 }
503 527
504 public void Close(bool force) 528 public void Close(bool sendStop, bool force)
505 { 529 {
506 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 530 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
507 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 531 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -513,7 +537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
513 return; 537 return;
514 538
515 IsActive = false; 539 IsActive = false;
516 CloseWithoutChecks(); 540 CloseWithoutChecks(sendStop);
517 } 541 }
518 } 542 }
519 543
@@ -526,12 +550,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
526 /// 550 ///
527 /// Callers must lock ClosingSyncLock before calling. 551 /// Callers must lock ClosingSyncLock before calling.
528 /// </remarks> 552 /// </remarks>
529 public void CloseWithoutChecks() 553 public void CloseWithoutChecks(bool sendStop)
530 { 554 {
531 m_log.DebugFormat( 555 m_log.DebugFormat(
532 "[CLIENT]: Close has been called for {0} attached to scene {1}", 556 "[CLIENT]: Close has been called for {0} attached to scene {1}",
533 Name, m_scene.RegionInfo.RegionName); 557 Name, m_scene.RegionInfo.RegionName);
534 558
559 if (sendStop)
560 {
561 // Send the STOP packet
562 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
563 OutPacket(disable, ThrottleOutPacketType.Unknown);
564 }
565
535 // Shutdown the image manager 566 // Shutdown the image manager
536 ImageManager.Close(); 567 ImageManager.Close();
537 568
@@ -554,6 +585,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
554 // Disable UDP handling for this client 585 // Disable UDP handling for this client
555 m_udpClient.Shutdown(); 586 m_udpClient.Shutdown();
556 587
588
557 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 589 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
558 //GC.Collect(); 590 //GC.Collect();
559 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 591 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -794,7 +826,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
794 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; 826 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
795 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported 827 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
796 828
797 OutPacket(handshake, ThrottleOutPacketType.Task); 829 OutPacket(handshake, ThrottleOutPacketType.Unknown);
798 } 830 }
799 831
800 832
@@ -835,7 +867,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
835 reply.ChatData.OwnerID = ownerID; 867 reply.ChatData.OwnerID = ownerID;
836 reply.ChatData.SourceID = fromAgentID; 868 reply.ChatData.SourceID = fromAgentID;
837 869
838 OutPacket(reply, ThrottleOutPacketType.Task); 870 OutPacket(reply, ThrottleOutPacketType.Unknown);
839 } 871 }
840 872
841 /// <summary> 873 /// <summary>
@@ -868,32 +900,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
868 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 900 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
869 msg.MessageBlock.BinaryBucket = im.binaryBucket; 901 msg.MessageBlock.BinaryBucket = im.binaryBucket;
870 902
871 if (im.message.StartsWith("[grouptest]")) 903 OutPacket(msg, ThrottleOutPacketType.Task);
872 { // this block is test code for implementing group IM - delete when group IM is finished
873 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
874 if (eq != null)
875 {
876 im.dialog = 17;
877
878 //eq.ChatterboxInvitation(
879 // new UUID("00000000-68f9-1111-024e-222222111123"),
880 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
881 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
882
883 eq.ChatterboxInvitation(
884 new UUID("00000000-68f9-1111-024e-222222111123"),
885 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
886 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
887
888 eq.ChatterBoxSessionAgentListUpdates(
889 new UUID("00000000-68f9-1111-024e-222222111123"),
890 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
891 }
892
893 Console.WriteLine("SendInstantMessage: " + msg);
894 }
895 else
896 OutPacket(msg, ThrottleOutPacketType.Task);
897 } 904 }
898 } 905 }
899 906
@@ -1131,6 +1138,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1131 public virtual void SendLayerData(float[] map) 1138 public virtual void SendLayerData(float[] map)
1132 { 1139 {
1133 Util.FireAndForget(DoSendLayerData, map); 1140 Util.FireAndForget(DoSendLayerData, map);
1141
1142 // Send it sync, and async. It's not that much data
1143 // and it improves user experience just so much!
1144 DoSendLayerData(map);
1134 } 1145 }
1135 1146
1136 /// <summary> 1147 /// <summary>
@@ -1143,16 +1154,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1143 1154
1144 try 1155 try
1145 { 1156 {
1146 //for (int y = 0; y < 16; y++) 1157 for (int y = 0; y < 16; y++)
1147 //{ 1158 {
1148 // for (int x = 0; x < 16; x++) 1159 for (int x = 0; x < 16; x+=4)
1149 // { 1160 {
1150 // SendLayerData(x, y, map); 1161 SendLayerPacket(x, y, map);
1151 // } 1162 }
1152 //} 1163 }
1153
1154 // Send LayerData in a spiral pattern. Fun!
1155 SendLayerTopRight(map, 0, 0, 15, 15);
1156 } 1164 }
1157 catch (Exception e) 1165 catch (Exception e)
1158 { 1166 {
@@ -1160,51 +1168,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1160 } 1168 }
1161 } 1169 }
1162 1170
1163 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1164 {
1165 // Row
1166 for (int i = x1; i <= x2; i++)
1167 SendLayerData(i, y1, map);
1168
1169 // Column
1170 for (int j = y1 + 1; j <= y2; j++)
1171 SendLayerData(x2, j, map);
1172
1173 if (x2 - x1 > 0)
1174 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1175 }
1176
1177 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1178 {
1179 // Row in reverse
1180 for (int i = x2; i >= x1; i--)
1181 SendLayerData(i, y2, map);
1182
1183 // Column in reverse
1184 for (int j = y2 - 1; j >= y1; j--)
1185 SendLayerData(x1, j, map);
1186
1187 if (x2 - x1 > 0)
1188 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1189 }
1190
1191 /// <summary> 1171 /// <summary>
1192 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1172 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1193 /// </summary> 1173 /// </summary>
1194 /// <param name="map">heightmap</param> 1174 /// <param name="map">heightmap</param>
1195 /// <param name="px">X coordinate for patches 0..12</param> 1175 /// <param name="px">X coordinate for patches 0..12</param>
1196 /// <param name="py">Y coordinate for patches 0..15</param> 1176 /// <param name="py">Y coordinate for patches 0..15</param>
1197 // private void SendLayerPacket(float[] map, int y, int x) 1177 private void SendLayerPacket(int x, int y, float[] map)
1198 // { 1178 {
1199 // int[] patches = new int[4]; 1179 int[] patches = new int[4];
1200 // patches[0] = x + 0 + y * 16; 1180 patches[0] = x + 0 + y * 16;
1201 // patches[1] = x + 1 + y * 16; 1181 patches[1] = x + 1 + y * 16;
1202 // patches[2] = x + 2 + y * 16; 1182 patches[2] = x + 2 + y * 16;
1203 // patches[3] = x + 3 + y * 16; 1183 patches[3] = x + 3 + y * 16;
1204 1184
1205 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1185 float[] heightmap = (map.Length == 65536) ?
1206 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1186 map :
1207 // } 1187 LLHeightFieldMoronize(map);
1188
1189 try
1190 {
1191 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1192 OutPacket(layerpack, ThrottleOutPacketType.Land);
1193 }
1194 catch
1195 {
1196 for (int px = x ; px < x + 4 ; px++)
1197 SendLayerData(px, y, map);
1198 }
1199 }
1208 1200
1209 /// <summary> 1201 /// <summary>
1210 /// Sends a specified patch to a client 1202 /// Sends a specified patch to a client
@@ -1224,7 +1216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1224 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1216 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1225 layerpack.Header.Reliable = true; 1217 layerpack.Header.Reliable = true;
1226 1218
1227 OutPacket(layerpack, ThrottleOutPacketType.Land); 1219 OutPacket(layerpack, ThrottleOutPacketType.Task);
1228 } 1220 }
1229 catch (Exception e) 1221 catch (Exception e)
1230 { 1222 {
@@ -1594,7 +1586,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1594 1586
1595 public void SendKillObject(List<uint> localIDs) 1587 public void SendKillObject(List<uint> localIDs)
1596 { 1588 {
1597// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1589// foreach (uint id in localIDs)
1590// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1598 1591
1599 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1592 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1600 // TODO: don't create new blocks if recycling an old packet 1593 // TODO: don't create new blocks if recycling an old packet
@@ -1616,17 +1609,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1616 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1609 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1617 // condition where a kill can be processed before an out-of-date update for the same object. 1610 // condition where a kill can be processed before an out-of-date update for the same object.
1618 // ProcessEntityUpdates() also takes the m_killRecord lock. 1611 // ProcessEntityUpdates() also takes the m_killRecord lock.
1619 lock (m_killRecord) 1612// lock (m_killRecord)
1620 { 1613// {
1621 foreach (uint localID in localIDs) 1614// foreach (uint localID in localIDs)
1622 m_killRecord.Add(localID); 1615// m_killRecord.Add(localID);
1623 1616
1624 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1617 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1625 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1618 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1626 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1619 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1627 // scene objects in a viewer until that viewer is relogged in. 1620 // scene objects in a viewer until that viewer is relogged in.
1628 OutPacket(kill, ThrottleOutPacketType.Task); 1621 OutPacket(kill, ThrottleOutPacketType.Task);
1629 } 1622// }
1630 } 1623 }
1631 } 1624 }
1632 1625
@@ -2085,9 +2078,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2085 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2078 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2086 } 2079 }
2087 2080
2088 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2089 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2081 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2090 { 2082 {
2083 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2084 }
2085
2086 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2087 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2088 {
2091 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2089 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2092 2090
2093 UpdateCreateInventoryItemPacket InventoryReply 2091 UpdateCreateInventoryItemPacket InventoryReply
@@ -2097,6 +2095,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2097 // TODO: don't create new blocks if recycling an old packet 2095 // TODO: don't create new blocks if recycling an old packet
2098 InventoryReply.AgentData.AgentID = AgentId; 2096 InventoryReply.AgentData.AgentID = AgentId;
2099 InventoryReply.AgentData.SimApproved = true; 2097 InventoryReply.AgentData.SimApproved = true;
2098 InventoryReply.AgentData.TransactionID = transactionID;
2100 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2099 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2101 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2100 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2102 InventoryReply.InventoryData[0].ItemID = Item.ID; 2101 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2166,16 +2165,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2166 replytask.InventoryData.TaskID = taskID; 2165 replytask.InventoryData.TaskID = taskID;
2167 replytask.InventoryData.Serial = serial; 2166 replytask.InventoryData.Serial = serial;
2168 replytask.InventoryData.Filename = fileName; 2167 replytask.InventoryData.Filename = fileName;
2169 OutPacket(replytask, ThrottleOutPacketType.Asset); 2168 OutPacket(replytask, ThrottleOutPacketType.Task);
2170 } 2169 }
2171 2170
2172 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2171 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2173 { 2172 {
2173 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2174 if (isTaskInventory)
2175 type = ThrottleOutPacketType.Task;
2176
2174 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2177 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2175 sendXfer.XferID.ID = xferID; 2178 sendXfer.XferID.ID = xferID;
2176 sendXfer.XferID.Packet = packet; 2179 sendXfer.XferID.Packet = packet;
2177 sendXfer.DataPacket.Data = data; 2180 sendXfer.DataPacket.Data = data;
2178 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2181 OutPacket(sendXfer, type);
2179 } 2182 }
2180 2183
2181 public void SendAbortXferPacket(ulong xferID) 2184 public void SendAbortXferPacket(ulong xferID)
@@ -2362,6 +2365,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2362 OutPacket(sound, ThrottleOutPacketType.Task); 2365 OutPacket(sound, ThrottleOutPacketType.Task);
2363 } 2366 }
2364 2367
2368 public void SendTransferAbort(TransferRequestPacket transferRequest)
2369 {
2370 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2371 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2372 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2373 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2374 OutPacket(abort, ThrottleOutPacketType.Task);
2375 }
2376
2365 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2377 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2366 { 2378 {
2367 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2379 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2670,6 +2682,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2670 float friction = part.Friction; 2682 float friction = part.Friction;
2671 float bounce = part.Restitution; 2683 float bounce = part.Restitution;
2672 float gravmod = part.GravityModifier; 2684 float gravmod = part.GravityModifier;
2685
2673 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2686 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2674 } 2687 }
2675 } 2688 }
@@ -2740,8 +2753,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2740 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2753 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2741 return; 2754 return;
2742 } 2755 }
2756 int WearableOut = 0;
2757 bool isWearable = false;
2758
2759 if (req.AssetInf != null)
2760 isWearable =
2761 ((AssetType) req.AssetInf.Type ==
2762 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2743 2763
2744 //m_log.Debug("sending asset " + req.RequestAssetID); 2764
2765 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2766
2767
2768 //if (isWearable)
2769 // m_log.Debug((AssetType)req.AssetInf.Type);
2770
2745 TransferInfoPacket Transfer = new TransferInfoPacket(); 2771 TransferInfoPacket Transfer = new TransferInfoPacket();
2746 Transfer.TransferInfo.ChannelType = 2; 2772 Transfer.TransferInfo.ChannelType = 2;
2747 Transfer.TransferInfo.Status = 0; 2773 Transfer.TransferInfo.Status = 0;
@@ -2763,7 +2789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2763 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2789 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2764 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2790 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2765 Transfer.Header.Zerocoded = true; 2791 Transfer.Header.Zerocoded = true;
2766 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2792 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2767 2793
2768 if (req.NumPackets == 1) 2794 if (req.NumPackets == 1)
2769 { 2795 {
@@ -2774,12 +2800,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2774 TransferPacket.TransferData.Data = req.AssetInf.Data; 2800 TransferPacket.TransferData.Data = req.AssetInf.Data;
2775 TransferPacket.TransferData.Status = 1; 2801 TransferPacket.TransferData.Status = 1;
2776 TransferPacket.Header.Zerocoded = true; 2802 TransferPacket.Header.Zerocoded = true;
2777 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2803 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2778 } 2804 }
2779 else 2805 else
2780 { 2806 {
2781 int processedLength = 0; 2807 int processedLength = 0;
2782 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2808// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2809
2810 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2783 int packetNumber = 0; 2811 int packetNumber = 0;
2784 2812
2785 while (processedLength < req.AssetInf.Data.Length) 2813 while (processedLength < req.AssetInf.Data.Length)
@@ -2805,7 +2833,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2805 TransferPacket.TransferData.Status = 1; 2833 TransferPacket.TransferData.Status = 1;
2806 } 2834 }
2807 TransferPacket.Header.Zerocoded = true; 2835 TransferPacket.Header.Zerocoded = true;
2808 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2836 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2809 2837
2810 processedLength += chunkSize; 2838 processedLength += chunkSize;
2811 packetNumber++; 2839 packetNumber++;
@@ -2850,7 +2878,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2850 reply.Data.ParcelID = parcelID; 2878 reply.Data.ParcelID = parcelID;
2851 reply.Data.OwnerID = land.OwnerID; 2879 reply.Data.OwnerID = land.OwnerID;
2852 reply.Data.Name = Utils.StringToBytes(land.Name); 2880 reply.Data.Name = Utils.StringToBytes(land.Name);
2853 reply.Data.Desc = Utils.StringToBytes(land.Description); 2881 if (land != null && land.Description != null && land.Description != String.Empty)
2882 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2883 else
2884 reply.Data.Desc = new Byte[0];
2854 reply.Data.ActualArea = land.Area; 2885 reply.Data.ActualArea = land.Area;
2855 reply.Data.BillableArea = land.Area; // TODO: what is this? 2886 reply.Data.BillableArea = land.Area; // TODO: what is this?
2856 2887
@@ -3557,24 +3588,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3557 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3588 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3558 AgentWearablesUpdatePacket.WearableDataBlock awb; 3589 AgentWearablesUpdatePacket.WearableDataBlock awb;
3559 int idx = 0; 3590 int idx = 0;
3560 for (int i = 0; i < wearables.Length; i++) 3591
3561 { 3592 for (int i = 0; i < wearables.Length; i++)
3562 for (int j = 0; j < wearables[i].Count; j++) 3593 {
3563 { 3594 for (int j = 0; j < wearables[i].Count; j++)
3564 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3595 {
3565 awb.WearableType = (byte)i; 3596 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3566 awb.AssetID = wearables[i][j].AssetID; 3597 awb.WearableType = (byte) i;
3567 awb.ItemID = wearables[i][j].ItemID; 3598 awb.AssetID = wearables[i][j].AssetID;
3568 aw.WearableData[idx] = awb; 3599 awb.ItemID = wearables[i][j].ItemID;
3569 idx++; 3600 aw.WearableData[idx] = awb;
3570 3601 idx++;
3571// m_log.DebugFormat( 3602
3572// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3603 // m_log.DebugFormat(
3573// awb.ItemID, awb.AssetID, i, Name); 3604 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3574 } 3605 // awb.ItemID, awb.AssetID, i, Name);
3575 } 3606 }
3607 }
3576 3608
3577 OutPacket(aw, ThrottleOutPacketType.Task); 3609 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3578 } 3610 }
3579 3611
3580 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3612 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3585,7 +3617,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3585 3617
3586 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3618 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3587 // TODO: don't create new blocks if recycling an old packet 3619 // TODO: don't create new blocks if recycling an old packet
3588 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3620 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3589 avp.ObjectData.TextureEntry = textureEntry; 3621 avp.ObjectData.TextureEntry = textureEntry;
3590 3622
3591 AvatarAppearancePacket.VisualParamBlock avblock = null; 3623 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3716,7 +3748,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3716 /// </summary> 3748 /// </summary>
3717 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3749 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3718 { 3750 {
3719 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3751 if (entity is SceneObjectPart)
3752 {
3753 SceneObjectPart e = (SceneObjectPart)entity;
3754 SceneObjectGroup g = e.ParentGroup;
3755 if (g.RootPart.Shape.State > 30) // HUD
3756 if (g.OwnerID != AgentId)
3757 return; // Don't send updates for other people's HUDs
3758 }
3759
3720 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3760 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3721 3761
3722 lock (m_entityUpdates.SyncRoot) 3762 lock (m_entityUpdates.SyncRoot)
@@ -3783,27 +3823,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3783 3823
3784 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3824 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3785 // condition where a kill can be processed before an out-of-date update for the same object. 3825 // condition where a kill can be processed before an out-of-date update for the same object.
3786 lock (m_killRecord) 3826 float avgTimeDilation = 1.0f;
3827 IEntityUpdate iupdate;
3828 Int32 timeinqueue; // this is just debugging code & can be dropped later
3829
3830 while (updatesThisCall < maxUpdates)
3787 { 3831 {
3788 float avgTimeDilation = 1.0f; 3832 lock (m_entityUpdates.SyncRoot)
3789 IEntityUpdate iupdate; 3833 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3790 Int32 timeinqueue; // this is just debugging code & can be dropped later 3834 break;
3791 3835
3792 while (updatesThisCall < maxUpdates) 3836 EntityUpdate update = (EntityUpdate)iupdate;
3837
3838 avgTimeDilation += update.TimeDilation;
3839 avgTimeDilation *= 0.5f;
3840
3841 if (update.Entity is SceneObjectPart)
3793 { 3842 {
3794 lock (m_entityUpdates.SyncRoot) 3843 SceneObjectPart part = (SceneObjectPart)update.Entity;
3795 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3796 break;
3797 3844
3798 EntityUpdate update = (EntityUpdate)iupdate; 3845 if (part.ParentGroup.IsDeleted)
3799 3846 continue;
3800 avgTimeDilation += update.TimeDilation;
3801 avgTimeDilation *= 0.5f;
3802 3847
3803 if (update.Entity is SceneObjectPart) 3848 if (part.ParentGroup.IsAttachment)
3849 { // Someone else's HUD, why are we getting these?
3850 if (part.ParentGroup.OwnerID != AgentId &&
3851 part.ParentGroup.RootPart.Shape.State > 30)
3852 continue;
3853 ScenePresence sp;
3854 // Owner is not in the sim, don't update it to
3855 // anyone
3856 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3857 continue;
3858
3859 List<SceneObjectGroup> atts = sp.GetAttachments();
3860 bool found = false;
3861 foreach (SceneObjectGroup att in atts)
3862 {
3863 if (att == part.ParentGroup)
3864 {
3865 found = true;
3866 break;
3867 }
3868 }
3869
3870 // It's an attachment of a valid avatar, but
3871 // doesn't seem to be attached, skip
3872 if (!found)
3873 continue;
3874
3875 // On vehicle crossing, the attachments are received
3876 // while the avatar is still a child. Don't send
3877 // updates here because the LocalId has not yet
3878 // been updated and the viewer will derender the
3879 // attachments until the avatar becomes root.
3880 if (sp.IsChildAgent)
3881 continue;
3882
3883 // If the object is an attachment we don't want it to be in the kill
3884 // record. Else attaching from inworld and subsequently dropping
3885 // it will no longer work.
3886// lock (m_killRecord)
3887// {
3888// m_killRecord.Remove(part.LocalId);
3889// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3890// }
3891 }
3892 else
3804 { 3893 {
3805 SceneObjectPart part = (SceneObjectPart)update.Entity;
3806
3807 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3894 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3808 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3895 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3809 // safety measure. 3896 // safety measure.
@@ -3814,21 +3901,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3814 // 3901 //
3815 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3902 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3816 // after the root prim has been deleted. 3903 // after the root prim has been deleted.
3817 if (m_killRecord.Contains(part.LocalId)) 3904 //
3818 { 3905 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3819 // m_log.WarnFormat( 3906// lock (m_killRecord)
3820 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3907// {
3821 // part.LocalId, Name); 3908// if (m_killRecord.Contains(part.LocalId))
3822 continue; 3909// continue;
3823 } 3910// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3824 3911// continue;
3825 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3912// }
3913 }
3914
3915 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3916 {
3917 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3918 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3826 { 3919 {
3827 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3920 part.Shape.LightEntry = false;
3828 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3829 {
3830 part.Shape.LightEntry = false;
3831 }
3832 } 3921 }
3833 3922
3834 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 3923 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
@@ -3839,224 +3928,166 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3839 part.Shape.ProfileHollow = 27500; 3928 part.Shape.ProfileHollow = 27500;
3840 } 3929 }
3841 } 3930 }
3842 3931
3843 #region UpdateFlags to packet type conversion 3932 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3844
3845 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3846
3847 bool canUseCompressed = true;
3848 bool canUseImproved = true;
3849
3850 // Compressed object updates only make sense for LL primitives
3851 if (!(update.Entity is SceneObjectPart))
3852 { 3933 {
3853 canUseCompressed = false; 3934 // Ensure that mesh has at least 8 valid faces
3935 part.Shape.ProfileBegin = 12500;
3936 part.Shape.ProfileEnd = 0;
3937 part.Shape.ProfileHollow = 27500;
3854 } 3938 }
3855 3939 }
3856 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3940
3941 ++updatesThisCall;
3942
3943 #region UpdateFlags to packet type conversion
3944
3945 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3946
3947 bool canUseCompressed = true;
3948 bool canUseImproved = true;
3949
3950 // Compressed object updates only make sense for LL primitives
3951 if (!(update.Entity is SceneObjectPart))
3952 {
3953 canUseCompressed = false;
3954 }
3955
3956 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3957 {
3958 canUseCompressed = false;
3959 canUseImproved = false;
3960 }
3961 else
3962 {
3963 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3964 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3965 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3966 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3857 { 3967 {
3858 canUseCompressed = false; 3968 canUseCompressed = false;
3859 canUseImproved = false;
3860 } 3969 }
3861 else 3970
3971 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3972 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3973 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3974 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3975 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3976 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3977 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3978 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3979 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3980 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3981 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3982 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3983 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3984 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3862 { 3985 {
3863 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3986 canUseImproved = false;
3864 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3865 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3866 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3867 {
3868 canUseCompressed = false;
3869 }
3870
3871 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3872 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3873 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3874 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3875 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3876 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3877 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3878 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3879 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3880 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3881 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3882 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3883 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3884 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3885 {
3886 canUseImproved = false;
3887 }
3888 } 3987 }
3988 }
3889 3989
3890 #endregion UpdateFlags to packet type conversion 3990 #endregion UpdateFlags to packet type conversion
3891
3892 #region Block Construction
3893
3894 // TODO: Remove this once we can build compressed updates
3895 canUseCompressed = false;
3896
3897 if (!canUseImproved && !canUseCompressed)
3898 {
3899 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3900 3991
3901 if (update.Entity is ScenePresence) 3992 #region Block Construction
3902 {
3903 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3904 }
3905 else
3906 {
3907 SceneObjectPart part = (SceneObjectPart)update.Entity;
3908 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3909
3910 // If the part has become a private hud since the update was scheduled then we do not
3911 // want to send it to other avatars.
3912 if (part.ParentGroup.IsAttachment
3913 && part.ParentGroup.HasPrivateAttachmentPoint
3914 && part.ParentGroup.AttachedAvatar != AgentId)
3915 continue;
3916
3917 // If the part has since been deleted, then drop the update. In the case of attachments,
3918 // this is to avoid spurious updates to other viewers since post-processing of attachments
3919 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3920 // of the test above).
3921 //
3922 // Actual deletions (kills) happen in another method.
3923 if (part.ParentGroup.IsDeleted)
3924 continue;
3925 }
3926 3993
3927 objectUpdateBlocks.Value.Add(updateBlock); 3994 // TODO: Remove this once we can build compressed updates
3928 objectUpdates.Value.Add(update); 3995 canUseCompressed = false;
3929 }
3930 else if (!canUseImproved)
3931 {
3932 SceneObjectPart part = (SceneObjectPart)update.Entity;
3933 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
3934 = CreateCompressedUpdateBlock(part, updateFlags);
3935
3936 // If the part has since been deleted, then drop the update. In the case of attachments,
3937 // this is to avoid spurious updates to other viewers since post-processing of attachments
3938 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3939 // of the test above).
3940 //
3941 // Actual deletions (kills) happen in another method.
3942 if (part.ParentGroup.IsDeleted)
3943 continue;
3944 3996
3945 compressedUpdateBlocks.Value.Add(compressedBlock); 3997 if (!canUseImproved && !canUseCompressed)
3946 compressedUpdates.Value.Add(update); 3998 {
3999 if (update.Entity is ScenePresence)
4000 {
4001 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3947 } 4002 }
3948 else 4003 else
3949 { 4004 {
3950 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4005 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3951 {
3952 // Self updates go into a special list
3953 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3954 terseAgentUpdates.Value.Add(update);
3955 }
3956 else
3957 {
3958 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
3959 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
3960
3961 // Everything else goes here
3962 if (update.Entity is SceneObjectPart)
3963 {
3964 SceneObjectPart part = (SceneObjectPart)update.Entity;
3965
3966 // If the part has become a private hud since the update was scheduled then we do not
3967 // want to send it to other avatars.
3968 if (part.ParentGroup.IsAttachment
3969 && part.ParentGroup.HasPrivateAttachmentPoint
3970 && part.ParentGroup.AttachedAvatar != AgentId)
3971 continue;
3972
3973 // If the part has since been deleted, then drop the update. In the case of attachments,
3974 // this is to avoid spurious updates to other viewers since post-processing of attachments
3975 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3976 // of the test above).
3977 //
3978 // Actual deletions (kills) happen in another method.
3979 if (part.ParentGroup.IsDeleted)
3980 continue;
3981 }
3982
3983 terseUpdateBlocks.Value.Add(terseUpdateBlock);
3984 terseUpdates.Value.Add(update);
3985 }
3986 } 4006 }
3987
3988 ++updatesThisCall;
3989
3990 #endregion Block Construction
3991 } 4007 }
3992 4008 else if (!canUseImproved)
3993 #region Packet Sending 4009 {
3994 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 4010 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3995 4011 }
3996 if (terseAgentUpdateBlocks.IsValueCreated) 4012 else
3997 { 4013 {
3998 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4014 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
4015 // Self updates go into a special list
4016 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4017 else
4018 // Everything else goes here
4019 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4020 }
3999 4021
4000 ImprovedTerseObjectUpdatePacket packet 4022 #endregion Block Construction
4001 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4023 }
4002 4024
4003 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4025 #region Packet Sending
4004 packet.RegionData.TimeDilation = timeDilation; 4026
4005 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4027 const float TIME_DILATION = 1.0f;
4028 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4029
4030 if (terseAgentUpdateBlocks.IsValueCreated)
4031 {
4032 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
4006 4033
4007 for (int i = 0; i < blocks.Count; i++) 4034 ImprovedTerseObjectUpdatePacket packet
4008 packet.ObjectData[i] = blocks[i]; 4035 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4009 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4036 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4010 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4037 packet.RegionData.TimeDilation = timeDilation;
4011 } 4038 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4012 4039
4013 if (objectUpdateBlocks.IsValueCreated) 4040 for (int i = 0; i < blocks.Count; i++)
4014 { 4041 packet.ObjectData[i] = blocks[i];
4015 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4016
4017 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4018 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4019 packet.RegionData.TimeDilation = timeDilation;
4020 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4021
4022 for (int i = 0; i < blocks.Count; i++)
4023 packet.ObjectData[i] = blocks[i];
4024 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4025 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4026 }
4027
4028 if (compressedUpdateBlocks.IsValueCreated)
4029 {
4030 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4031
4032 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4033 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4034 packet.RegionData.TimeDilation = timeDilation;
4035 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4036
4037 for (int i = 0; i < blocks.Count; i++)
4038 packet.ObjectData[i] = blocks[i];
4039 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4040 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4041 }
4042 4042
4043 if (terseUpdateBlocks.IsValueCreated) 4043 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4044 { 4044 }
4045 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4046
4047 ImprovedTerseObjectUpdatePacket packet
4048 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4049 PacketType.ImprovedTerseObjectUpdate);
4050 4045
4051 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4046 if (objectUpdateBlocks.IsValueCreated)
4052 packet.RegionData.TimeDilation = timeDilation; 4047 {
4053 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4048 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4054 4049
4055 for (int i = 0; i < blocks.Count; i++) 4050 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4056 packet.ObjectData[i] = blocks[i]; 4051 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4057 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4052 packet.RegionData.TimeDilation = timeDilation;
4058 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4053 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4059 } 4054
4055 for (int i = 0; i < blocks.Count; i++)
4056 packet.ObjectData[i] = blocks[i];
4057
4058 OutPacket(packet, ThrottleOutPacketType.Task, true);
4059 }
4060
4061 if (compressedUpdateBlocks.IsValueCreated)
4062 {
4063 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4064
4065 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4066 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4067 packet.RegionData.TimeDilation = timeDilation;
4068 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4069
4070 for (int i = 0; i < blocks.Count; i++)
4071 packet.ObjectData[i] = blocks[i];
4072
4073 OutPacket(packet, ThrottleOutPacketType.Task, true);
4074 }
4075
4076 if (terseUpdateBlocks.IsValueCreated)
4077 {
4078 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4079
4080 ImprovedTerseObjectUpdatePacket packet
4081 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4082 PacketType.ImprovedTerseObjectUpdate);
4083 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4084 packet.RegionData.TimeDilation = timeDilation;
4085 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4086
4087 for (int i = 0; i < blocks.Count; i++)
4088 packet.ObjectData[i] = blocks[i];
4089
4090 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4060 } 4091 }
4061 4092
4062 #endregion Packet Sending 4093 #endregion Packet Sending
@@ -4349,11 +4380,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4349 4380
4350 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4381 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4351 // of the object rather than the properties when the packet was created 4382 // of the object rather than the properties when the packet was created
4352 OutPacket(packet, ThrottleOutPacketType.Task, true, 4383 // HACK : Remove intelligent resending until it's fixed in core
4353 delegate(OutgoingPacket oPacket) 4384 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4354 { 4385 // delegate(OutgoingPacket oPacket)
4355 ResendPropertyUpdates(updates, oPacket); 4386 // {
4356 }); 4387 // ResendPropertyUpdates(updates, oPacket);
4388 // });
4389 OutPacket(packet, ThrottleOutPacketType.Task, true);
4357 4390
4358 // pbcnt += blocks.Count; 4391 // pbcnt += blocks.Count;
4359 // ppcnt++; 4392 // ppcnt++;
@@ -4379,11 +4412,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4379 // of the object rather than the properties when the packet was created 4412 // of the object rather than the properties when the packet was created
4380 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4413 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4381 updates.Add(familyUpdates.Value[i]); 4414 updates.Add(familyUpdates.Value[i]);
4382 OutPacket(packet, ThrottleOutPacketType.Task, true, 4415 // HACK : Remove intelligent resending until it's fixed in core
4383 delegate(OutgoingPacket oPacket) 4416 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4384 { 4417 // delegate(OutgoingPacket oPacket)
4385 ResendPropertyUpdates(updates, oPacket); 4418 // {
4386 }); 4419 // ResendPropertyUpdates(updates, oPacket);
4420 // });
4421 OutPacket(packet, ThrottleOutPacketType.Task, true);
4387 4422
4388 // fpcnt++; 4423 // fpcnt++;
4389 // fbcnt++; 4424 // fbcnt++;
@@ -4755,7 +4790,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4755 4790
4756 if (landData.SimwideArea > 0) 4791 if (landData.SimwideArea > 0)
4757 { 4792 {
4758 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4793 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4794 // Never report more than sim total capacity
4795 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4796 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4759 updateMessage.SimWideMaxPrims = simulatorCapacity; 4797 updateMessage.SimWideMaxPrims = simulatorCapacity;
4760 } 4798 }
4761 else 4799 else
@@ -4884,14 +4922,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4884 4922
4885 if (notifyCount > 0) 4923 if (notifyCount > 0)
4886 { 4924 {
4887 if (notifyCount > 32) 4925// if (notifyCount > 32)
4888 { 4926// {
4889 m_log.InfoFormat( 4927// m_log.InfoFormat(
4890 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4928// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4891 + " - a developer might want to investigate whether this is a hard limit", 32); 4929// + " - a developer might want to investigate whether this is a hard limit", 32);
4892 4930//
4893 notifyCount = 32; 4931// notifyCount = 32;
4894 } 4932// }
4895 4933
4896 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4934 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4897 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4935 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4946,9 +4984,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4946 { 4984 {
4947 ScenePresence presence = (ScenePresence)entity; 4985 ScenePresence presence = (ScenePresence)entity;
4948 4986
4987 position = presence.OffsetPosition;
4988 rotation = presence.Rotation;
4989
4990 if (presence.ParentID != 0)
4991 {
4992 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
4993 if (part != null && part != part.ParentGroup.RootPart)
4994 {
4995 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
4996 rotation = part.RotationOffset * presence.Rotation;
4997 }
4998 angularVelocity = Vector3.Zero;
4999 }
5000 else
5001 {
5002 angularVelocity = presence.AngularVelocity;
5003 rotation = presence.Rotation;
5004 }
5005
4949 attachPoint = 0; 5006 attachPoint = 0;
4950 collisionPlane = presence.CollisionPlane; 5007 collisionPlane = presence.CollisionPlane;
4951 position = presence.OffsetPosition;
4952 velocity = presence.Velocity; 5008 velocity = presence.Velocity;
4953 acceleration = Vector3.Zero; 5009 acceleration = Vector3.Zero;
4954 5010
@@ -4957,9 +5013,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4957 // may improve movement smoothness. 5013 // may improve movement smoothness.
4958// acceleration = new Vector3(1, 0, 0); 5014// acceleration = new Vector3(1, 0, 0);
4959 5015
4960 angularVelocity = presence.AngularVelocity;
4961 rotation = presence.Rotation;
4962
4963 if (sendTexture) 5016 if (sendTexture)
4964 textureEntry = presence.Appearance.Texture.GetBytes(); 5017 textureEntry = presence.Appearance.Texture.GetBytes();
4965 else 5018 else
@@ -5065,13 +5118,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5065 5118
5066 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5119 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5067 { 5120 {
5121 Vector3 offsetPosition = data.OffsetPosition;
5122 Quaternion rotation = data.Rotation;
5123 uint parentID = data.ParentID;
5124
5125 if (parentID != 0)
5126 {
5127 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5128 if (part != null && part != part.ParentGroup.RootPart)
5129 {
5130 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5131 rotation = part.RotationOffset * data.Rotation;
5132 parentID = part.ParentGroup.RootPart.LocalId;
5133 }
5134 }
5135
5068 byte[] objectData = new byte[76]; 5136 byte[] objectData = new byte[76];
5069 5137
5070 data.CollisionPlane.ToBytes(objectData, 0); 5138 data.CollisionPlane.ToBytes(objectData, 0);
5071 data.OffsetPosition.ToBytes(objectData, 16); 5139 offsetPosition.ToBytes(objectData, 16);
5072// data.Velocity.ToBytes(objectData, 28); 5140// data.Velocity.ToBytes(objectData, 28);
5073// data.Acceleration.ToBytes(objectData, 40); 5141// data.Acceleration.ToBytes(objectData, 40);
5074 data.Rotation.ToBytes(objectData, 52); 5142 rotation.ToBytes(objectData, 52);
5075 //data.AngularVelocity.ToBytes(objectData, 64); 5143 //data.AngularVelocity.ToBytes(objectData, 64);
5076 5144
5077 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5145 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5085,14 +5153,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5085 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5153 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5086 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5154 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5087 update.ObjectData = objectData; 5155 update.ObjectData = objectData;
5088 update.ParentID = data.ParentID; 5156 update.ParentID = parentID;
5089 update.PathCurve = 16; 5157 update.PathCurve = 16;
5090 update.PathScaleX = 100; 5158 update.PathScaleX = 100;
5091 update.PathScaleY = 100; 5159 update.PathScaleY = 100;
5092 update.PCode = (byte)PCode.Avatar; 5160 update.PCode = (byte)PCode.Avatar;
5093 update.ProfileCurve = 1; 5161 update.ProfileCurve = 1;
5094 update.PSBlock = Utils.EmptyBytes; 5162 update.PSBlock = Utils.EmptyBytes;
5095 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5163 update.Scale = data.Appearance.AvatarSize;
5164// update.Scale.Z -= 0.2f;
5165
5096 update.Text = Utils.EmptyBytes; 5166 update.Text = Utils.EmptyBytes;
5097 update.TextColor = new byte[4]; 5167 update.TextColor = new byte[4];
5098 5168
@@ -5103,10 +5173,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5103 update.TextureEntry = Utils.EmptyBytes; 5173 update.TextureEntry = Utils.EmptyBytes;
5104// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5174// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5105 5175
5176/* 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)
5106 update.UpdateFlags = (uint)( 5177 update.UpdateFlags = (uint)(
5107 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5178 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5108 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5179 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5109 PrimFlags.ObjectOwnerModify); 5180 PrimFlags.ObjectOwnerModify);
5181*/
5182 update.UpdateFlags = 0;
5110 5183
5111 return update; 5184 return update;
5112 } 5185 }
@@ -5277,8 +5350,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5277 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5350 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5278 // for each AgentUpdate packet. 5351 // for each AgentUpdate packet.
5279 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5352 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5280 5353
5281 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5354 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5355 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5356 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5282 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5357 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5283 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5358 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5284 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5359 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5430,6 +5505,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5430 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5505 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5431 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5506 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5432 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5507 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5508 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5433 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5509 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5434 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5510 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5435 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5511 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5496,6 +5572,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5496 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5572 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5497 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5573 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5498 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5574 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5575 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5499 5576
5500 AddGenericPacketHandler("autopilot", HandleAutopilot); 5577 AddGenericPacketHandler("autopilot", HandleAutopilot);
5501 } 5578 }
@@ -5534,6 +5611,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5534 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || 5611 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5535 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || 5612 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5536 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || 5613 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5614 (x.ControlFlags != 0) ||
5537 (x.Far != m_lastAgentUpdateArgs.Far) || 5615 (x.Far != m_lastAgentUpdateArgs.Far) ||
5538 (x.Flags != m_lastAgentUpdateArgs.Flags) || 5616 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5539 (x.State != m_lastAgentUpdateArgs.State) || 5617 (x.State != m_lastAgentUpdateArgs.State) ||
@@ -5793,6 +5871,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5793 return true; 5871 return true;
5794 } 5872 }
5795 5873
5874 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
5875 {
5876 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
5877 if (p.AgentData.SessionID != SessionId ||
5878 p.AgentData.AgentID != AgentId)
5879 return true;
5880
5881 m_VelocityInterpolate = false;
5882 return true;
5883 }
5884
5885 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
5886 {
5887 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
5888 if (p.AgentData.SessionID != SessionId ||
5889 p.AgentData.AgentID != AgentId)
5890 return true;
5891
5892 m_VelocityInterpolate = true;
5893 return true;
5894 }
5895
5896
5796 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 5897 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5797 { 5898 {
5798 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 5899 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6213,26 +6314,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6213 // Temporarily protect ourselves from the mantis #951 failure. 6314 // Temporarily protect ourselves from the mantis #951 failure.
6214 // However, we could do this for several other handlers where a failure isn't terminal 6315 // However, we could do this for several other handlers where a failure isn't terminal
6215 // for the client session anyway, in order to protect ourselves against bad code in plugins 6316 // for the client session anyway, in order to protect ourselves against bad code in plugins
6317 Vector3 avSize = appear.AgentData.Size;
6216 try 6318 try
6217 { 6319 {
6218 byte[] visualparams = new byte[appear.VisualParam.Length]; 6320 byte[] visualparams = new byte[appear.VisualParam.Length];
6219 for (int i = 0; i < appear.VisualParam.Length; i++) 6321 for (int i = 0; i < appear.VisualParam.Length; i++)
6220 visualparams[i] = appear.VisualParam[i].ParamValue; 6322 visualparams[i] = appear.VisualParam[i].ParamValue;
6221 6323 //var b = appear.WearableData[0];
6324
6222 Primitive.TextureEntry te = null; 6325 Primitive.TextureEntry te = null;
6223 if (appear.ObjectData.TextureEntry.Length > 1) 6326 if (appear.ObjectData.TextureEntry.Length > 1)
6224 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6327 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6328
6329 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6330 for (int i=0; i<appear.WearableData.Length;i++)
6331 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6225 6332
6226 List<CachedTextureRequestArg> hashes = new List<CachedTextureRequestArg>(); 6333
6227 for (int i = 0; i < appear.WearableData.Length; i++)
6228 {
6229 CachedTextureRequestArg arg = new CachedTextureRequestArg();
6230 arg.BakedTextureIndex = appear.WearableData[i].TextureIndex;
6231 arg.WearableHashID = appear.WearableData[i].CacheID;
6232 hashes.Add(arg);
6233 }
6234 6334
6235 handlerSetAppearance(sender, te, visualparams, hashes); 6335 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6236 } 6336 }
6237 catch (Exception e) 6337 catch (Exception e)
6238 { 6338 {
@@ -6441,6 +6541,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6441 { 6541 {
6442 handlerCompleteMovementToRegion(sender, true); 6542 handlerCompleteMovementToRegion(sender, true);
6443 } 6543 }
6544 else
6545 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6546
6444 handlerCompleteMovementToRegion = null; 6547 handlerCompleteMovementToRegion = null;
6445 6548
6446 return true; 6549 return true;
@@ -6458,7 +6561,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6458 return true; 6561 return true;
6459 } 6562 }
6460 #endregion 6563 #endregion
6461 6564/*
6462 StartAnim handlerStartAnim = null; 6565 StartAnim handlerStartAnim = null;
6463 StopAnim handlerStopAnim = null; 6566 StopAnim handlerStopAnim = null;
6464 6567
@@ -6482,6 +6585,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6482 } 6585 }
6483 } 6586 }
6484 return true; 6587 return true;
6588*/
6589 ChangeAnim handlerChangeAnim = null;
6590
6591 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6592 {
6593 handlerChangeAnim = OnChangeAnim;
6594 if (handlerChangeAnim != null)
6595 {
6596 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6597 }
6598 }
6599
6600 handlerChangeAnim = OnChangeAnim;
6601 if (handlerChangeAnim != null)
6602 {
6603 handlerChangeAnim(UUID.Zero, false, true);
6604 }
6605
6606 return true;
6485 } 6607 }
6486 6608
6487 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6609 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6707,6 +6829,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6707 #endregion 6829 #endregion
6708 6830
6709 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6831 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6832 GenericCall2 handler = OnUpdateThrottles;
6833 if (handler != null)
6834 {
6835 handler();
6836 }
6710 return true; 6837 return true;
6711 } 6838 }
6712 6839
@@ -7131,7 +7258,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7131 physdata.Bounce = phsblock.Restitution; 7258 physdata.Bounce = phsblock.Restitution;
7132 physdata.Density = phsblock.Density; 7259 physdata.Density = phsblock.Density;
7133 physdata.Friction = phsblock.Friction; 7260 physdata.Friction = phsblock.Friction;
7134 physdata.GravitationModifier = phsblock.GravityMultiplier; 7261 physdata.GravitationModifier = phsblock.GravityMultiplier;
7135 } 7262 }
7136 7263
7137 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7264 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7717,6 +7844,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7717 // surrounding scene 7844 // surrounding scene
7718 if ((ImageType)block.Type == ImageType.Baked) 7845 if ((ImageType)block.Type == ImageType.Baked)
7719 args.Priority *= 2.0f; 7846 args.Priority *= 2.0f;
7847 int wearableout = 0;
7720 7848
7721 ImageManager.EnqueueReq(args); 7849 ImageManager.EnqueueReq(args);
7722 } 7850 }
@@ -8735,16 +8863,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8735 8863
8736 #region Parcel related packets 8864 #region Parcel related packets
8737 8865
8866 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
8867 // to be done with minimal resources as possible
8868 // variables temporary here while in test
8869
8870 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
8871 bool RegionHandleRequestsInService = false;
8872
8738 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 8873 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8739 { 8874 {
8740 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 8875 UUID currentUUID;
8741 8876
8742 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 8877 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8743 if (handlerRegionHandleRequest != null) 8878
8879 if (handlerRegionHandleRequest == null)
8880 return true;
8881
8882 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
8883
8884 lock (RegionHandleRequests)
8744 { 8885 {
8745 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 8886 if (RegionHandleRequestsInService)
8887 {
8888 // we are already busy doing a previus request
8889 // so enqueue it
8890 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
8891 return true;
8892 }
8893
8894 // else do it
8895 currentUUID = rhrPack.RequestBlock.RegionID;
8896 RegionHandleRequestsInService = true;
8746 } 8897 }
8747 return true; 8898
8899 while (true)
8900 {
8901 handlerRegionHandleRequest(this, currentUUID);
8902
8903 lock (RegionHandleRequests)
8904 {
8905 // exit condition, nothing to do or closed
8906 // current code seems to assume we may loose the handler at anytime,
8907 // so keep checking it
8908 handlerRegionHandleRequest = OnRegionHandleRequest;
8909
8910 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
8911 {
8912 RegionHandleRequests.Clear();
8913 RegionHandleRequestsInService = false;
8914 return true;
8915 }
8916 currentUUID = RegionHandleRequests.Dequeue();
8917 }
8918 }
8919
8920 return true; // actually unreached
8748 } 8921 }
8749 8922
8750 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 8923 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -10000,7 +10173,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10000 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10173 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
10001 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10174 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
10002 UpdateMuteListEntry.MuteData.MuteType, 10175 UpdateMuteListEntry.MuteData.MuteType,
10003 UpdateMuteListEntry.AgentData.AgentID); 10176 UpdateMuteListEntry.MuteData.MuteFlags);
10004 return true; 10177 return true;
10005 } 10178 }
10006 return false; 10179 return false;
@@ -10015,8 +10188,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10015 { 10188 {
10016 handlerRemoveMuteListEntry(this, 10189 handlerRemoveMuteListEntry(this,
10017 RemoveMuteListEntry.MuteData.MuteID, 10190 RemoveMuteListEntry.MuteData.MuteID,
10018 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10191 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
10019 RemoveMuteListEntry.AgentData.AgentID);
10020 return true; 10192 return true;
10021 } 10193 }
10022 return false; 10194 return false;
@@ -10060,10 +10232,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10060 return false; 10232 return false;
10061 } 10233 }
10062 10234
10235 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10236 {
10237 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10238 (ChangeInventoryItemFlagsPacket)packet;
10239 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10240 if (handlerChangeInventoryItemFlags != null)
10241 {
10242 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10243 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10244 return true;
10245 }
10246 return false;
10247 }
10248
10063 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10249 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10064 { 10250 {
10065 return true; 10251 return true;
10066 } 10252 }
10253
10254 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10255 {
10256 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10257
10258 #region Packet Session and User Check
10259 if (m_checkPackets)
10260 {
10261 if (packet.AgentData.SessionID != SessionId ||
10262 packet.AgentData.AgentID != AgentId)
10263 return true;
10264 }
10265 #endregion
10266 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10267 List<InventoryItemBase> items = new List<InventoryItemBase>();
10268 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10269 {
10270 InventoryItemBase b = new InventoryItemBase();
10271 b.ID = n.OldItemID;
10272 b.Folder = n.OldFolderID;
10273 items.Add(b);
10274 }
10275
10276 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10277 if (handlerMoveItemsAndLeaveCopy != null)
10278 {
10279 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10280 }
10281
10282 return true;
10283 }
10067 10284
10068 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10285 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10069 { 10286 {
@@ -10490,6 +10707,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10490 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10707 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10491 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10708 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10492 10709
10710 Scene scene = (Scene)m_scene;
10711 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10712 {
10713 ScenePresence p;
10714 if (scene.TryGetScenePresence(sender.AgentId, out p))
10715 {
10716 if (p.GodLevel >= 200)
10717 {
10718 groupProfileReply.GroupData.OpenEnrollment = true;
10719 groupProfileReply.GroupData.MembershipFee = 0;
10720 }
10721 }
10722 }
10723
10493 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10724 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10494 } 10725 }
10495 return true; 10726 return true;
@@ -11063,11 +11294,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11063 11294
11064 StartLure handlerStartLure = OnStartLure; 11295 StartLure handlerStartLure = OnStartLure;
11065 if (handlerStartLure != null) 11296 if (handlerStartLure != null)
11066 handlerStartLure(startLureRequest.Info.LureType, 11297 {
11067 Utils.BytesToString( 11298 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11068 startLureRequest.Info.Message), 11299 {
11069 startLureRequest.TargetData[0].TargetID, 11300 handlerStartLure(startLureRequest.Info.LureType,
11070 this); 11301 Utils.BytesToString(
11302 startLureRequest.Info.Message),
11303 startLureRequest.TargetData[i].TargetID,
11304 this);
11305 }
11306 }
11071 return true; 11307 return true;
11072 } 11308 }
11073 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11309 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11181,10 +11417,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11181 } 11417 }
11182 #endregion 11418 #endregion
11183 11419
11184 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11420 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11185 if (handlerClassifiedGodDelete != null) 11421 if (handlerClassifiedGodDelete != null)
11186 handlerClassifiedGodDelete( 11422 handlerClassifiedGodDelete(
11187 classifiedGodDelete.Data.ClassifiedID, 11423 classifiedGodDelete.Data.ClassifiedID,
11424 classifiedGodDelete.Data.QueryID,
11188 this); 11425 this);
11189 return true; 11426 return true;
11190 } 11427 }
@@ -11487,12 +11724,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11487 /// <param name="simclient"></param> 11724 /// <param name="simclient"></param>
11488 /// <param name="packet"></param> 11725 /// <param name="packet"></param>
11489 /// <returns></returns> 11726 /// <returns></returns>
11490 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11727 // TODO: Convert old handler to use new method
11728 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11491 { 11729 {
11492 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 11730 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11493 11731
11494 if (cachedtex.AgentData.SessionID != SessionId) 11732 if (cachedtex.AgentData.SessionID != SessionId)
11495 return false; 11733 return false;
11734
11496 11735
11497 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); 11736 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11498 11737
@@ -11505,23 +11744,173 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11505 requestArgs.Add(arg); 11744 requestArgs.Add(arg);
11506 } 11745 }
11507 11746
11508 try 11747 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11748 if (handlerCachedTextureRequest != null)
11509 { 11749 {
11510 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; 11750 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11511 if (handlerCachedTextureRequest != null) 11751 }
11752
11753 return true;
11754 }*/
11755
11756 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11757 {
11758 //m_log.Debug("texture cached: " + packet.ToString());
11759 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11760 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11761
11762 if (cachedtex.AgentData.SessionID != SessionId)
11763 return false;
11764
11765
11766 // TODO: don't create new blocks if recycling an old packet
11767 cachedresp.AgentData.AgentID = AgentId;
11768 cachedresp.AgentData.SessionID = m_sessionId;
11769 cachedresp.AgentData.SerialNum = m_cachedTextureSerial;
11770 m_cachedTextureSerial++;
11771 cachedresp.WearableData =
11772 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11773
11774 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11775 // var item = fac.GetBakedTextureFaces(AgentId);
11776 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11777
11778 IAssetService cache = m_scene.AssetService;
11779 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11780 //bakedTextureModule = null;
11781 int maxWearablesLoop = cachedtex.WearableData.Length;
11782 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11783 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11784
11785 if (bakedTextureModule != null && cache != null)
11786 {
11787 // 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
11788
11789 WearableCacheItem[] cacheItems = null;
11790 ScenePresence p = m_scene.GetScenePresence(AgentId);
11791 if (p.Appearance != null)
11792 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11793 {
11794 try
11795 {
11796 cacheItems = bakedTextureModule.Get(AgentId);
11797 p.Appearance.WearableCacheItems = cacheItems;
11798 p.Appearance.WearableCacheItemsDirty = false;
11799 }
11800
11801 /*
11802 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11803 *
11804 catch (System.Net.Sockets.SocketException)
11805 {
11806 cacheItems = null;
11807 }
11808 catch (WebException)
11809 {
11810 cacheItems = null;
11811 }
11812 catch (InvalidOperationException)
11813 {
11814 cacheItems = null;
11815 } */
11816 catch (Exception)
11817 {
11818 cacheItems = null;
11819 }
11820
11821 }
11822 else if (p.Appearance.WearableCacheItems != null)
11823 {
11824 cacheItems = p.Appearance.WearableCacheItems;
11825 }
11826
11827 if (cache != null && cacheItems != null)
11512 { 11828 {
11513 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); 11829 foreach (WearableCacheItem item in cacheItems)
11830 {
11831
11832 if (cache.GetCached(item.TextureID.ToString()) == null)
11833 {
11834 item.TextureAsset.Temporary = true;
11835 cache.Store(item.TextureAsset);
11836 }
11837
11838
11839 }
11840 }
11841
11842 if (cacheItems != null)
11843 {
11844
11845 for (int i = 0; i < maxWearablesLoop; i++)
11846 {
11847 WearableCacheItem item =
11848 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11849
11850 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11851 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
11852 cachedresp.WearableData[i].HostName = new byte[0];
11853 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11854 {
11855
11856 cachedresp.WearableData[i].TextureID = item.TextureID;
11857 }
11858 else
11859 {
11860 cachedresp.WearableData[i].TextureID = UUID.Zero;
11861 }
11862 }
11863 }
11864 else
11865 {
11866 for (int i = 0; i < maxWearablesLoop; i++)
11867 {
11868 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11869 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11870 cachedresp.WearableData[i].TextureID = UUID.Zero;
11871 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11872 cachedresp.WearableData[i].HostName = new byte[0];
11873 }
11514 } 11874 }
11515 } 11875 }
11516 catch (Exception e) 11876 else
11517 { 11877 {
11518 m_log.ErrorFormat("[CLIENT VIEW]: AgentTextureCached packet handler threw an exception, {0}", e); 11878 if (cache == null)
11519 return false; 11879 {
11880 for (int i = 0; i < maxWearablesLoop; i++)
11881 {
11882 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11883 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11884 cachedresp.WearableData[i].TextureID = UUID.Zero;
11885 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11886 cachedresp.WearableData[i].HostName = new byte[0];
11887 }
11888 }
11889 else
11890 {
11891 for (int i = 0; i < maxWearablesLoop; i++)
11892 {
11893 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11894 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11895
11896
11897
11898 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11899 cachedresp.WearableData[i].TextureID = UUID.Zero;
11900 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11901 else
11902 cachedresp.WearableData[i].TextureID = UUID.Zero;
11903 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11904 cachedresp.WearableData[i].HostName = new byte[0];
11905 }
11906 }
11520 } 11907 }
11521 11908 cachedresp.Header.Zerocoded = true;
11909 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11910
11522 return true; 11911 return true;
11523 } 11912 }
11524 11913
11525 /// <summary> 11914 /// <summary>
11526 /// Send a response back to a client when it asks the asset server (via the region server) if it has 11915 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11527 /// its appearance texture cached. 11916 /// its appearance texture cached.
@@ -11585,209 +11974,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11585 } 11974 }
11586 else 11975 else
11587 { 11976 {
11588// m_log.DebugFormat( 11977 ClientChangeObject updatehandler = onClientChangeObject;
11589// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11590// i, block.Type, part.Name, part.LocalId);
11591 11978
11592// // Do this once since fetch parts creates a new array. 11979 if (updatehandler != null)
11593// SceneObjectPart[] parts = part.ParentGroup.Parts; 11980 {
11594// for (int j = 0; j < parts.Length; j++) 11981 ObjectChangeData udata = new ObjectChangeData();
11595// {
11596// part.StoreUndoState();
11597// parts[j].IgnoreUndoUpdate = true;
11598// }
11599 11982
11600 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 11983 /*ubit from ll JIRA:
11984 * 0x01 position
11985 * 0x02 rotation
11986 * 0x04 scale
11987
11988 * 0x08 LINK_SET
11989 * 0x10 UNIFORM for scale
11990 */
11601 11991
11602 switch (block.Type) 11992 // translate to internal changes
11603 { 11993 // not all cases .. just the ones older code did
11604 case 1:
11605 Vector3 pos1 = new Vector3(block.Data, 0);
11606 11994
11607 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11995 switch (block.Type)
11608 if (handlerUpdatePrimSinglePosition != null) 11996 {
11609 { 11997 case 1: //change position sp
11610 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11998 udata.position = new Vector3(block.Data, 0);
11611 handlerUpdatePrimSinglePosition(localId, pos1, this);
11612 }
11613 break;
11614 11999
11615 case 2: 12000 udata.change = ObjectChangeType.primP;
11616 Quaternion rot1 = new Quaternion(block.Data, 0, true); 12001 updatehandler(localId, udata, this);
12002 break;
11617 12003
11618 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 12004 case 2: // rotation sp
11619 if (handlerUpdatePrimSingleRotation != null) 12005 udata.rotation = new Quaternion(block.Data, 0, true);
11620 {
11621 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11622 handlerUpdatePrimSingleRotation(localId, rot1, this);
11623 }
11624 break;
11625 12006
11626 case 3: 12007 udata.change = ObjectChangeType.primR;
11627 Vector3 rotPos = new Vector3(block.Data, 0); 12008 updatehandler(localId, udata, this);
11628 Quaternion rot2 = new Quaternion(block.Data, 12, true); 12009 break;
11629 12010
11630 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 12011 case 3: // position plus rotation
11631 if (handlerUpdatePrimSingleRotationPosition != null) 12012 udata.position = new Vector3(block.Data, 0);
11632 { 12013 udata.rotation = new Quaternion(block.Data, 12, true);
11633 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11634 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11635 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11636 }
11637 break;
11638 12014
11639 case 4: 12015 udata.change = ObjectChangeType.primPR;
11640 case 20: 12016 updatehandler(localId, udata, this);
11641 Vector3 scale4 = new Vector3(block.Data, 0); 12017 break;
11642 12018
11643 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 12019 case 4: // scale sp
11644 if (handlerUpdatePrimScale != null) 12020 udata.scale = new Vector3(block.Data, 0);
11645 { 12021 udata.change = ObjectChangeType.primS;
11646 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11647 handlerUpdatePrimScale(localId, scale4, this);
11648 }
11649 break;
11650 12022
11651 case 5: 12023 updatehandler(localId, udata, this);
11652 Vector3 scale1 = new Vector3(block.Data, 12); 12024 break;
11653 Vector3 pos11 = new Vector3(block.Data, 0);
11654 12025
11655 handlerUpdatePrimScale = OnUpdatePrimScale; 12026 case 0x14: // uniform scale sp
11656 if (handlerUpdatePrimScale != null) 12027 udata.scale = new Vector3(block.Data, 0);
11657 {
11658 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11659 handlerUpdatePrimScale(localId, scale1, this);
11660 12028
11661 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12029 udata.change = ObjectChangeType.primUS;
11662 if (handlerUpdatePrimSinglePosition != null) 12030 updatehandler(localId, udata, this);
11663 { 12031 break;
11664 handlerUpdatePrimSinglePosition(localId, pos11, this);
11665 }
11666 }
11667 break;
11668 12032
11669 case 9: 12033 case 5: // scale and position sp
11670 Vector3 pos2 = new Vector3(block.Data, 0); 12034 udata.position = new Vector3(block.Data, 0);
12035 udata.scale = new Vector3(block.Data, 12);
11671 12036
11672 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 12037 udata.change = ObjectChangeType.primPS;
12038 updatehandler(localId, udata, this);
12039 break;
11673 12040
11674 if (handlerUpdateVector != null) 12041 case 0x15: //uniform scale and position
11675 { 12042 udata.position = new Vector3(block.Data, 0);
11676 handlerUpdateVector(localId, pos2, this); 12043 udata.scale = new Vector3(block.Data, 12);
11677 }
11678 break;
11679 12044
11680 case 10: 12045 udata.change = ObjectChangeType.primPUS;
11681 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12046 updatehandler(localId, udata, this);
12047 break;
11682 12048
11683 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12049 // now group related (bit 4)
11684 if (handlerUpdatePrimRotation != null) 12050 case 9: //( 8 + 1 )group position
11685 { 12051 udata.position = new Vector3(block.Data, 0);
11686 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11687 handlerUpdatePrimRotation(localId, rot3, this);
11688 }
11689 break;
11690 12052
11691 case 11: 12053 udata.change = ObjectChangeType.groupP;
11692 Vector3 pos3 = new Vector3(block.Data, 0); 12054 updatehandler(localId, udata, this);
11693 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12055 break;
11694 12056
11695 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12057 case 0x0A: // (8 + 2) group rotation
11696 if (handlerUpdatePrimGroupRotation != null) 12058 udata.rotation = new Quaternion(block.Data, 0, true);
11697 {
11698 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11699 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11700 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11701 }
11702 break;
11703 case 12:
11704 case 28:
11705 Vector3 scale7 = new Vector3(block.Data, 0);
11706 12059
11707 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12060 udata.change = ObjectChangeType.groupR;
11708 if (handlerUpdatePrimGroupScale != null) 12061 updatehandler(localId, udata, this);
11709 { 12062 break;
11710 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11711 handlerUpdatePrimGroupScale(localId, scale7, this);
11712 }
11713 break;
11714 12063
11715 case 13: 12064 case 0x0B: //( 8 + 2 + 1) group rotation and position
11716 Vector3 scale2 = new Vector3(block.Data, 12); 12065 udata.position = new Vector3(block.Data, 0);
11717 Vector3 pos4 = new Vector3(block.Data, 0); 12066 udata.rotation = new Quaternion(block.Data, 12, true);
11718 12067
11719 handlerUpdatePrimScale = OnUpdatePrimScale; 12068 udata.change = ObjectChangeType.groupPR;
11720 if (handlerUpdatePrimScale != null) 12069 updatehandler(localId, udata, this);
11721 { 12070 break;
11722 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11723 handlerUpdatePrimScale(localId, scale2, this);
11724 12071
11725 // Change the position based on scale (for bug number 246) 12072 case 0x0C: // (8 + 4) group scale
11726 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12073 // only afects root prim and only sent by viewer editor object tab scaling
11727 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12074 // mouse edition only allows uniform scaling
11728 if (handlerUpdatePrimSinglePosition != null) 12075 // SL MAY CHANGE THIS in viewers
11729 {
11730 handlerUpdatePrimSinglePosition(localId, pos4, this);
11731 }
11732 }
11733 break;
11734 12076
11735 case 29: 12077 udata.scale = new Vector3(block.Data, 0);
11736 Vector3 scale5 = new Vector3(block.Data, 12);
11737 Vector3 pos5 = new Vector3(block.Data, 0);
11738 12078
11739 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12079 udata.change = ObjectChangeType.groupS;
11740 if (handlerUpdatePrimGroupScale != null) 12080 updatehandler(localId, udata, this);
11741 {
11742 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11743 part.StoreUndoState(true);
11744 part.IgnoreUndoUpdate = true;
11745 handlerUpdatePrimGroupScale(localId, scale5, this);
11746 handlerUpdateVector = OnUpdatePrimGroupPosition;
11747 12081
11748 if (handlerUpdateVector != null) 12082 break;
11749 {
11750 handlerUpdateVector(localId, pos5, this);
11751 }
11752 12083
11753 part.IgnoreUndoUpdate = false; 12084 case 0x0D: //(8 + 4 + 1) group scale and position
11754 } 12085 // exception as above
11755 12086
11756 break; 12087 udata.position = new Vector3(block.Data, 0);
12088 udata.scale = new Vector3(block.Data, 12);
11757 12089
11758 case 21: 12090 udata.change = ObjectChangeType.groupPS;
11759 Vector3 scale6 = new Vector3(block.Data, 12); 12091 updatehandler(localId, udata, this);
11760 Vector3 pos6 = new Vector3(block.Data, 0); 12092 break;
11761 12093
11762 handlerUpdatePrimScale = OnUpdatePrimScale; 12094 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11763 if (handlerUpdatePrimScale != null) 12095 udata.scale = new Vector3(block.Data, 0);
11764 {
11765 part.StoreUndoState(false);
11766 part.IgnoreUndoUpdate = true;
11767 12096
11768 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12097 udata.change = ObjectChangeType.groupUS;
11769 handlerUpdatePrimScale(localId, scale6, this); 12098 updatehandler(localId, udata, this);
11770 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12099 break;
11771 if (handlerUpdatePrimSinglePosition != null)
11772 {
11773 handlerUpdatePrimSinglePosition(localId, pos6, this);
11774 }
11775 12100
11776 part.IgnoreUndoUpdate = false; 12101 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11777 } 12102 udata.position = new Vector3(block.Data, 0);
11778 break; 12103 udata.scale = new Vector3(block.Data, 12);
11779 12104
11780 default: 12105 udata.change = ObjectChangeType.groupPUS;
11781 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12106 updatehandler(localId, udata, this);
11782 break; 12107 break;
12108
12109 default:
12110 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12111 break;
12112 }
11783 } 12113 }
11784 12114
11785// for (int j = 0; j < parts.Length; j++)
11786// parts[j].IgnoreUndoUpdate = false;
11787 } 12115 }
11788 } 12116 }
11789 } 12117 }
11790
11791 return true; 12118 return true;
11792 } 12119 }
11793 12120
@@ -11848,9 +12175,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11848 public void SetChildAgentThrottle(byte[] throttles) 12175 public void SetChildAgentThrottle(byte[] throttles)
11849 { 12176 {
11850 m_udpClient.SetThrottles(throttles); 12177 m_udpClient.SetThrottles(throttles);
12178 GenericCall2 handler = OnUpdateThrottles;
12179 if (handler != null)
12180 {
12181 handler();
12182 }
11851 } 12183 }
11852 12184
11853 /// <summary> 12185 /// <summary>
12186 /// Sets the throttles from values supplied by the client
12187 /// </summary>
12188 /// <param name="throttles"></param>
12189 public void SetAgentThrottleSilent(int throttle, int setting)
12190 {
12191 m_udpClient.ForceThrottleSetting(throttle,setting);
12192 //m_udpClient.SetThrottles(throttles);
12193
12194 }
12195
12196
12197 /// <summary>
11854 /// Get the current throttles for this client as a packed byte array 12198 /// Get the current throttles for this client as a packed byte array
11855 /// </summary> 12199 /// </summary>
11856 /// <param name="multiplier">Unused</param> 12200 /// <param name="multiplier">Unused</param>
@@ -12231,7 +12575,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12231// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12575// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12232// requestID, taskID, (SourceType)sourceType, Name); 12576// requestID, taskID, (SourceType)sourceType, Name);
12233 12577
12578
12579 //Note, the bool returned from the below function is useless since it is always false.
12234 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12580 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12581
12235 } 12582 }
12236 12583
12237 /// <summary> 12584 /// <summary>
@@ -12297,7 +12644,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12297 /// <returns></returns> 12644 /// <returns></returns>
12298 private static int CalculateNumPackets(byte[] data) 12645 private static int CalculateNumPackets(byte[] data)
12299 { 12646 {
12300 const uint m_maxPacketSize = 600; 12647// const uint m_maxPacketSize = 600;
12648 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12301 int numPackets = 1; 12649 int numPackets = 1;
12302 12650
12303 if (data == null) 12651 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 8eb2e06..fab66ce 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -121,7 +121,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
121 /// <summary>Handlers for incoming packets</summary> 121 /// <summary>Handlers for incoming packets</summary>
122 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 122 //PacketEventDictionary packetEvents = new PacketEventDictionary();
123 /// <summary>Incoming packets that are awaiting handling</summary> 123 /// <summary>Incoming packets that are awaiting handling</summary>
124 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 124 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
125
126 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
125 127
126 /// <summary></summary> 128 /// <summary></summary>
127 //private UDPClientCollection m_clients = new UDPClientCollection(); 129 //private UDPClientCollection m_clients = new UDPClientCollection();
@@ -176,6 +178,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
176 /// <summary>Flag to signal when clients should send pings</summary> 178 /// <summary>Flag to signal when clients should send pings</summary>
177 protected bool m_sendPing; 179 protected bool m_sendPing;
178 180
181 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
179 private Pool<IncomingPacket> m_incomingPacketPool; 182 private Pool<IncomingPacket> m_incomingPacketPool;
180 183
181 /// <summary> 184 /// <summary>
@@ -782,6 +785,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
782 785
783 #region Queue or Send 786 #region Queue or Send
784 787
788 bool highPriority = false;
789
790 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
791 {
792 category = (ThrottleOutPacketType)((int)category & 127);
793 highPriority = true;
794 }
795
785 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 796 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
786 // If we were not provided a method for handling unacked, use the UDPServer default method 797 // If we were not provided a method for handling unacked, use the UDPServer default method
787 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 798 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
@@ -790,7 +801,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
790 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 801 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
791 // packet so that it isn't sent before a queued update packet. 802 // packet so that it isn't sent before a queued update packet.
792 bool requestQueue = type == PacketType.KillObject; 803 bool requestQueue = type == PacketType.KillObject;
793 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 804 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
794 SendPacketFinal(outgoingPacket); 805 SendPacketFinal(outgoingPacket);
795 806
796 #endregion Queue or Send 807 #endregion Queue or Send
@@ -1075,21 +1086,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1075 1086
1076 #region Packet to Client Mapping 1087 #region Packet to Client Mapping
1077 1088
1078 // UseCircuitCode handling 1089 // If there is already a client for this endpoint, don't process UseCircuitCode
1079 if (packet.Type == PacketType.UseCircuitCode) 1090 IClientAPI client = null;
1091 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1080 { 1092 {
1081 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1093 // UseCircuitCode handling
1082 // buffer. 1094 if (packet.Type == PacketType.UseCircuitCode)
1083 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1095 {
1096 // And if there is a UseCircuitCode pending, also drop it
1097 lock (m_pendingCache)
1098 {
1099 if (m_pendingCache.Contains(endPoint))
1100 return;
1084 1101
1085 Util.FireAndForget(HandleUseCircuitCode, array); 1102 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1103 }
1086 1104
1087 return; 1105 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1106 // buffer.
1107 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1108
1109 Util.FireAndForget(HandleUseCircuitCode, array);
1110
1111 return;
1112 }
1113 }
1114
1115 // If this is a pending connection, enqueue, don't process yet
1116 lock (m_pendingCache)
1117 {
1118 Queue<UDPPacketBuffer> queue;
1119 if (m_pendingCache.TryGetValue(endPoint, out queue))
1120 {
1121 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1122 queue.Enqueue(buffer);
1123 return;
1124 }
1088 } 1125 }
1089 1126
1090 // Determine which agent this packet came from 1127 // Determine which agent this packet came from
1091 IClientAPI client; 1128 if (client == null || !(client is LLClientView))
1092 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1093 { 1129 {
1094 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1130 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1095 return; 1131 return;
@@ -1098,7 +1134,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1098 udpClient = ((LLClientView)client).UDPClient; 1134 udpClient = ((LLClientView)client).UDPClient;
1099 1135
1100 if (!udpClient.IsConnected) 1136 if (!udpClient.IsConnected)
1137 {
1138// m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1101 return; 1139 return;
1140 }
1102 1141
1103 #endregion Packet to Client Mapping 1142 #endregion Packet to Client Mapping
1104 1143
@@ -1228,7 +1267,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1228 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1267 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1229 } 1268 }
1230 1269
1231 packetInbox.Enqueue(incomingPacket); 1270 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1271 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1272 packetInbox.EnqueueHigh(incomingPacket);
1273 else
1274 packetInbox.EnqueueLow(incomingPacket);
1232 } 1275 }
1233 1276
1234 #region BinaryStats 1277 #region BinaryStats
@@ -1376,10 +1419,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1376 { 1419 {
1377 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); 1420 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1378 bool tp = (aCircuit.teleportFlags > 0); 1421 bool tp = (aCircuit.teleportFlags > 0);
1379 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get meshes from
1380 if (!tp) 1422 if (!tp)
1381 client.SceneAgent.SendInitialDataToMe(); 1423 client.SceneAgent.SendInitialDataToMe();
1382 } 1424 }
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;
1383 } 1451 }
1384 else 1452 else
1385 { 1453 {
@@ -1387,6 +1455,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1387 m_log.WarnFormat( 1455 m_log.WarnFormat(
1388 "[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}",
1389 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);
1390 } 1460 }
1391 1461
1392 // m_log.DebugFormat( 1462 // m_log.DebugFormat(
@@ -1505,7 +1575,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1505 if (!client.SceneAgent.IsChildAgent) 1575 if (!client.SceneAgent.IsChildAgent)
1506 client.Kick("Simulator logged you out due to connection timeout"); 1576 client.Kick("Simulator logged you out due to connection timeout");
1507 1577
1508 client.CloseWithoutChecks(); 1578 client.CloseWithoutChecks(true);
1509 } 1579 }
1510 } 1580 }
1511 1581
@@ -1517,6 +1587,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1517 1587
1518 while (IsRunningInbound) 1588 while (IsRunningInbound)
1519 { 1589 {
1590 m_scene.ThreadAlive(1);
1520 try 1591 try
1521 { 1592 {
1522 IncomingPacket incomingPacket = null; 1593 IncomingPacket incomingPacket = null;
@@ -1564,6 +1635,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1564 1635
1565 while (base.IsRunningOutbound) 1636 while (base.IsRunningOutbound)
1566 { 1637 {
1638 m_scene.ThreadAlive(2);
1567 try 1639 try
1568 { 1640 {
1569 m_packetSent = false; 1641 m_packetSent = false;
@@ -1794,8 +1866,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1794 Packet packet = incomingPacket.Packet; 1866 Packet packet = incomingPacket.Packet;
1795 LLClientView client = incomingPacket.Client; 1867 LLClientView client = incomingPacket.Client;
1796 1868
1797 if (client.IsActive) 1869// if (client.IsActive)
1798 { 1870// {
1799 m_currentIncomingClient = client; 1871 m_currentIncomingClient = client;
1800 1872
1801 try 1873 try
@@ -1822,13 +1894,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1822 { 1894 {
1823 m_currentIncomingClient = null; 1895 m_currentIncomingClient = null;
1824 } 1896 }
1825 } 1897// }
1826 else 1898// else
1827 { 1899// {
1828 m_log.DebugFormat( 1900// m_log.DebugFormat(
1829 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1901// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1830 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1902// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1831 } 1903// }
1832 1904
1833 IncomingPacketsProcessed++; 1905 IncomingPacketsProcessed++;
1834 } 1906 }
@@ -1840,8 +1912,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1840 if (!client.IsLoggingOut) 1912 if (!client.IsLoggingOut)
1841 { 1913 {
1842 client.IsLoggingOut = true; 1914 client.IsLoggingOut = true;
1843 client.Close(); 1915 client.Close(false, false);
1844 } 1916 }
1845 } 1917 }
1846 } 1918 }
1847} \ 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,