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.cs1479
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs121
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
16 files changed, 3743 insertions, 1180 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 afbe56b..3995620 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 m_stopPacket = TexturePacketCount(); 234 m_stopPacket = TexturePacketCount();
235 } 235 }
236 236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
237 m_currentPacket = StartPacket; 240 m_currentPacket = StartPacket;
238 } 241 }
239 } 242 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index e014471..9de564b 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,14 +348,15 @@ 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
348 private int m_moneyBalance; 358 private int m_moneyBalance;
359 private bool m_deliverPackets = true;
349 private int m_animationSequenceNumber = 1; 360 private int m_animationSequenceNumber = 1;
350 private bool m_SendLogoutPacketWhenClosing = true; 361 private bool m_SendLogoutPacketWhenClosing = true;
351 362
@@ -392,6 +403,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
392 get { return m_startpos; } 403 get { return m_startpos; }
393 set { m_startpos = value; } 404 set { m_startpos = value; }
394 } 405 }
406 public bool DeliverPackets
407 {
408 get { return m_deliverPackets; }
409 set {
410 m_deliverPackets = value;
411 m_udpClient.m_deliverPackets = value;
412 }
413 }
395 public UUID AgentId { get { return m_agentId; } } 414 public UUID AgentId { get { return m_agentId; } }
396 public ISceneAgent SceneAgent { get; set; } 415 public ISceneAgent SceneAgent { get; set; }
397 public UUID ActiveGroupId { get { return m_activeGroupID; } } 416 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -443,6 +462,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
443 } 462 }
444 463
445 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 464 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
465
446 466
447 #endregion Properties 467 #endregion Properties
448 468
@@ -469,7 +489,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
469 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 489 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
470 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 490 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
471 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 491 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
472 m_killRecord = new HashSet<uint>(); 492// m_killRecord = new HashSet<uint>();
473// m_attachmentsSent = new HashSet<uint>(); 493// m_attachmentsSent = new HashSet<uint>();
474 494
475 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 495 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -499,12 +519,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
499 519
500 #region Client Methods 520 #region Client Methods
501 521
522
523 /// <summary>
524 /// Close down the client view
525 /// </summary>
502 public void Close() 526 public void Close()
503 { 527 {
504 Close(false); 528 Close(true, false);
505 } 529 }
506 530
507 public void Close(bool force) 531 public void Close(bool sendStop, bool force)
508 { 532 {
509 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 533 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
510 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 534 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -516,7 +540,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
516 return; 540 return;
517 541
518 IsActive = false; 542 IsActive = false;
519 CloseWithoutChecks(); 543 CloseWithoutChecks(sendStop);
520 } 544 }
521 } 545 }
522 546
@@ -529,12 +553,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
529 /// 553 ///
530 /// Callers must lock ClosingSyncLock before calling. 554 /// Callers must lock ClosingSyncLock before calling.
531 /// </remarks> 555 /// </remarks>
532 public void CloseWithoutChecks() 556 public void CloseWithoutChecks(bool sendStop)
533 { 557 {
534 m_log.DebugFormat( 558 m_log.DebugFormat(
535 "[CLIENT]: Close has been called for {0} attached to scene {1}", 559 "[CLIENT]: Close has been called for {0} attached to scene {1}",
536 Name, m_scene.RegionInfo.RegionName); 560 Name, m_scene.RegionInfo.RegionName);
537 561
562 if (sendStop)
563 {
564 // Send the STOP packet
565 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
566 OutPacket(disable, ThrottleOutPacketType.Unknown);
567 }
568
538 // Shutdown the image manager 569 // Shutdown the image manager
539 ImageManager.Close(); 570 ImageManager.Close();
540 571
@@ -557,6 +588,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
557 // Disable UDP handling for this client 588 // Disable UDP handling for this client
558 m_udpClient.Shutdown(); 589 m_udpClient.Shutdown();
559 590
591
560 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 592 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
561 //GC.Collect(); 593 //GC.Collect();
562 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 594 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -797,7 +829,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
797 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; 829 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
798 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported 830 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
799 831
800 OutPacket(handshake, ThrottleOutPacketType.Task); 832 OutPacket(handshake, ThrottleOutPacketType.Unknown);
801 } 833 }
802 834
803 835
@@ -838,7 +870,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
838 reply.ChatData.OwnerID = ownerID; 870 reply.ChatData.OwnerID = ownerID;
839 reply.ChatData.SourceID = fromAgentID; 871 reply.ChatData.SourceID = fromAgentID;
840 872
841 OutPacket(reply, ThrottleOutPacketType.Task); 873 OutPacket(reply, ThrottleOutPacketType.Unknown);
842 } 874 }
843 875
844 /// <summary> 876 /// <summary>
@@ -871,32 +903,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
871 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 903 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
872 msg.MessageBlock.BinaryBucket = im.binaryBucket; 904 msg.MessageBlock.BinaryBucket = im.binaryBucket;
873 905
874 if (im.message.StartsWith("[grouptest]")) 906 OutPacket(msg, ThrottleOutPacketType.Task);
875 { // this block is test code for implementing group IM - delete when group IM is finished
876 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
877 if (eq != null)
878 {
879 im.dialog = 17;
880
881 //eq.ChatterboxInvitation(
882 // new UUID("00000000-68f9-1111-024e-222222111123"),
883 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
884 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
885
886 eq.ChatterboxInvitation(
887 new UUID("00000000-68f9-1111-024e-222222111123"),
888 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
889 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
890
891 eq.ChatterBoxSessionAgentListUpdates(
892 new UUID("00000000-68f9-1111-024e-222222111123"),
893 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
894 }
895
896 Console.WriteLine("SendInstantMessage: " + msg);
897 }
898 else
899 OutPacket(msg, ThrottleOutPacketType.Task);
900 } 907 }
901 } 908 }
902 909
@@ -1134,6 +1141,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1134 public virtual void SendLayerData(float[] map) 1141 public virtual void SendLayerData(float[] map)
1135 { 1142 {
1136 Util.FireAndForget(DoSendLayerData, map); 1143 Util.FireAndForget(DoSendLayerData, map);
1144
1145 // Send it sync, and async. It's not that much data
1146 // and it improves user experience just so much!
1147 DoSendLayerData(map);
1137 } 1148 }
1138 1149
1139 /// <summary> 1150 /// <summary>
@@ -1146,16 +1157,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 1157
1147 try 1158 try
1148 { 1159 {
1149 //for (int y = 0; y < 16; y++) 1160 for (int y = 0; y < 16; y++)
1150 //{ 1161 {
1151 // for (int x = 0; x < 16; x++) 1162 for (int x = 0; x < 16; x+=4)
1152 // { 1163 {
1153 // SendLayerData(x, y, map); 1164 SendLayerPacket(x, y, map);
1154 // } 1165 }
1155 //} 1166 }
1156
1157 // Send LayerData in a spiral pattern. Fun!
1158 SendLayerTopRight(map, 0, 0, 15, 15);
1159 } 1167 }
1160 catch (Exception e) 1168 catch (Exception e)
1161 { 1169 {
@@ -1163,51 +1171,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1163 } 1171 }
1164 } 1172 }
1165 1173
1166 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1167 {
1168 // Row
1169 for (int i = x1; i <= x2; i++)
1170 SendLayerData(i, y1, map);
1171
1172 // Column
1173 for (int j = y1 + 1; j <= y2; j++)
1174 SendLayerData(x2, j, map);
1175
1176 if (x2 - x1 > 0)
1177 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1178 }
1179
1180 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1181 {
1182 // Row in reverse
1183 for (int i = x2; i >= x1; i--)
1184 SendLayerData(i, y2, map);
1185
1186 // Column in reverse
1187 for (int j = y2 - 1; j >= y1; j--)
1188 SendLayerData(x1, j, map);
1189
1190 if (x2 - x1 > 0)
1191 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1192 }
1193
1194 /// <summary> 1174 /// <summary>
1195 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1175 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1196 /// </summary> 1176 /// </summary>
1197 /// <param name="map">heightmap</param> 1177 /// <param name="map">heightmap</param>
1198 /// <param name="px">X coordinate for patches 0..12</param> 1178 /// <param name="px">X coordinate for patches 0..12</param>
1199 /// <param name="py">Y coordinate for patches 0..15</param> 1179 /// <param name="py">Y coordinate for patches 0..15</param>
1200 // private void SendLayerPacket(float[] map, int y, int x) 1180 private void SendLayerPacket(int x, int y, float[] map)
1201 // { 1181 {
1202 // int[] patches = new int[4]; 1182 int[] patches = new int[4];
1203 // patches[0] = x + 0 + y * 16; 1183 patches[0] = x + 0 + y * 16;
1204 // patches[1] = x + 1 + y * 16; 1184 patches[1] = x + 1 + y * 16;
1205 // patches[2] = x + 2 + y * 16; 1185 patches[2] = x + 2 + y * 16;
1206 // patches[3] = x + 3 + y * 16; 1186 patches[3] = x + 3 + y * 16;
1207 1187
1208 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1188 float[] heightmap = (map.Length == 65536) ?
1209 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1189 map :
1210 // } 1190 LLHeightFieldMoronize(map);
1191
1192 try
1193 {
1194 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1195 OutPacket(layerpack, ThrottleOutPacketType.Land);
1196 }
1197 catch
1198 {
1199 for (int px = x ; px < x + 4 ; px++)
1200 SendLayerData(px, y, map);
1201 }
1202 }
1211 1203
1212 /// <summary> 1204 /// <summary>
1213 /// Sends a specified patch to a client 1205 /// Sends a specified patch to a client
@@ -1227,7 +1219,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1227 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1219 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1228 layerpack.Header.Reliable = true; 1220 layerpack.Header.Reliable = true;
1229 1221
1230 OutPacket(layerpack, ThrottleOutPacketType.Land); 1222 OutPacket(layerpack, ThrottleOutPacketType.Task);
1231 } 1223 }
1232 catch (Exception e) 1224 catch (Exception e)
1233 { 1225 {
@@ -1590,7 +1582,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1590 1582
1591 public void SendKillObject(List<uint> localIDs) 1583 public void SendKillObject(List<uint> localIDs)
1592 { 1584 {
1593// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1585// foreach (uint id in localIDs)
1586// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1594 1587
1595 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1588 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1596 // TODO: don't create new blocks if recycling an old packet 1589 // TODO: don't create new blocks if recycling an old packet
@@ -1612,17 +1605,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1612 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1605 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1613 // condition where a kill can be processed before an out-of-date update for the same object. 1606 // condition where a kill can be processed before an out-of-date update for the same object.
1614 // ProcessEntityUpdates() also takes the m_killRecord lock. 1607 // ProcessEntityUpdates() also takes the m_killRecord lock.
1615 lock (m_killRecord) 1608// lock (m_killRecord)
1616 { 1609// {
1617 foreach (uint localID in localIDs) 1610// foreach (uint localID in localIDs)
1618 m_killRecord.Add(localID); 1611// m_killRecord.Add(localID);
1619 1612
1620 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1613 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1621 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1614 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1622 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1615 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1623 // scene objects in a viewer until that viewer is relogged in. 1616 // scene objects in a viewer until that viewer is relogged in.
1624 OutPacket(kill, ThrottleOutPacketType.Task); 1617 OutPacket(kill, ThrottleOutPacketType.Task);
1625 } 1618// }
1626 } 1619 }
1627 } 1620 }
1628 1621
@@ -2081,9 +2074,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2081 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2074 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2082 } 2075 }
2083 2076
2084 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2085 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2077 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2086 { 2078 {
2079 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2080 }
2081
2082 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2083 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2084 {
2087 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2085 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2088 2086
2089 UpdateCreateInventoryItemPacket InventoryReply 2087 UpdateCreateInventoryItemPacket InventoryReply
@@ -2093,6 +2091,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2093 // TODO: don't create new blocks if recycling an old packet 2091 // TODO: don't create new blocks if recycling an old packet
2094 InventoryReply.AgentData.AgentID = AgentId; 2092 InventoryReply.AgentData.AgentID = AgentId;
2095 InventoryReply.AgentData.SimApproved = true; 2093 InventoryReply.AgentData.SimApproved = true;
2094 InventoryReply.AgentData.TransactionID = transactionID;
2096 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2095 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2097 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2096 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2098 InventoryReply.InventoryData[0].ItemID = Item.ID; 2097 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2162,16 +2161,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2162 replytask.InventoryData.TaskID = taskID; 2161 replytask.InventoryData.TaskID = taskID;
2163 replytask.InventoryData.Serial = serial; 2162 replytask.InventoryData.Serial = serial;
2164 replytask.InventoryData.Filename = fileName; 2163 replytask.InventoryData.Filename = fileName;
2165 OutPacket(replytask, ThrottleOutPacketType.Asset); 2164 OutPacket(replytask, ThrottleOutPacketType.Task);
2166 } 2165 }
2167 2166
2168 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2167 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2169 { 2168 {
2169 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2170 if (isTaskInventory)
2171 type = ThrottleOutPacketType.Task;
2172
2170 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2173 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2171 sendXfer.XferID.ID = xferID; 2174 sendXfer.XferID.ID = xferID;
2172 sendXfer.XferID.Packet = packet; 2175 sendXfer.XferID.Packet = packet;
2173 sendXfer.DataPacket.Data = data; 2176 sendXfer.DataPacket.Data = data;
2174 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2177 OutPacket(sendXfer, type);
2175 } 2178 }
2176 2179
2177 public void SendAbortXferPacket(ulong xferID) 2180 public void SendAbortXferPacket(ulong xferID)
@@ -2353,6 +2356,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2353 OutPacket(sound, ThrottleOutPacketType.Task); 2356 OutPacket(sound, ThrottleOutPacketType.Task);
2354 } 2357 }
2355 2358
2359 public void SendTransferAbort(TransferRequestPacket transferRequest)
2360 {
2361 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2362 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2363 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2364 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2365 OutPacket(abort, ThrottleOutPacketType.Task);
2366 }
2367
2356 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2368 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2357 { 2369 {
2358 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2370 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2661,6 +2673,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2661 float friction = part.Friction; 2673 float friction = part.Friction;
2662 float bounce = part.Restitution; 2674 float bounce = part.Restitution;
2663 float gravmod = part.GravityModifier; 2675 float gravmod = part.GravityModifier;
2676
2664 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2677 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2665 } 2678 }
2666 } 2679 }
@@ -2731,8 +2744,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2731 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2744 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2732 return; 2745 return;
2733 } 2746 }
2747 int WearableOut = 0;
2748 bool isWearable = false;
2749
2750 if (req.AssetInf != null)
2751 isWearable =
2752 ((AssetType) req.AssetInf.Type ==
2753 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2734 2754
2735 //m_log.Debug("sending asset " + req.RequestAssetID); 2755
2756 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2757
2758
2759 //if (isWearable)
2760 // m_log.Debug((AssetType)req.AssetInf.Type);
2761
2736 TransferInfoPacket Transfer = new TransferInfoPacket(); 2762 TransferInfoPacket Transfer = new TransferInfoPacket();
2737 Transfer.TransferInfo.ChannelType = 2; 2763 Transfer.TransferInfo.ChannelType = 2;
2738 Transfer.TransferInfo.Status = 0; 2764 Transfer.TransferInfo.Status = 0;
@@ -2754,7 +2780,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2754 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2780 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2755 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2781 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2756 Transfer.Header.Zerocoded = true; 2782 Transfer.Header.Zerocoded = true;
2757 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2783 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2758 2784
2759 if (req.NumPackets == 1) 2785 if (req.NumPackets == 1)
2760 { 2786 {
@@ -2765,12 +2791,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2765 TransferPacket.TransferData.Data = req.AssetInf.Data; 2791 TransferPacket.TransferData.Data = req.AssetInf.Data;
2766 TransferPacket.TransferData.Status = 1; 2792 TransferPacket.TransferData.Status = 1;
2767 TransferPacket.Header.Zerocoded = true; 2793 TransferPacket.Header.Zerocoded = true;
2768 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2794 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2769 } 2795 }
2770 else 2796 else
2771 { 2797 {
2772 int processedLength = 0; 2798 int processedLength = 0;
2773 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2799// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2800
2801 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2774 int packetNumber = 0; 2802 int packetNumber = 0;
2775 2803
2776 while (processedLength < req.AssetInf.Data.Length) 2804 while (processedLength < req.AssetInf.Data.Length)
@@ -2796,7 +2824,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2796 TransferPacket.TransferData.Status = 1; 2824 TransferPacket.TransferData.Status = 1;
2797 } 2825 }
2798 TransferPacket.Header.Zerocoded = true; 2826 TransferPacket.Header.Zerocoded = true;
2799 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2827 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2800 2828
2801 processedLength += chunkSize; 2829 processedLength += chunkSize;
2802 packetNumber++; 2830 packetNumber++;
@@ -2841,7 +2869,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2841 reply.Data.ParcelID = parcelID; 2869 reply.Data.ParcelID = parcelID;
2842 reply.Data.OwnerID = land.OwnerID; 2870 reply.Data.OwnerID = land.OwnerID;
2843 reply.Data.Name = Utils.StringToBytes(land.Name); 2871 reply.Data.Name = Utils.StringToBytes(land.Name);
2844 reply.Data.Desc = Utils.StringToBytes(land.Description); 2872 if (land != null && land.Description != null && land.Description != String.Empty)
2873 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2874 else
2875 reply.Data.Desc = new Byte[0];
2845 reply.Data.ActualArea = land.Area; 2876 reply.Data.ActualArea = land.Area;
2846 reply.Data.BillableArea = land.Area; // TODO: what is this? 2877 reply.Data.BillableArea = land.Area; // TODO: what is this?
2847 2878
@@ -3548,24 +3579,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3548 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3579 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3549 AgentWearablesUpdatePacket.WearableDataBlock awb; 3580 AgentWearablesUpdatePacket.WearableDataBlock awb;
3550 int idx = 0; 3581 int idx = 0;
3551 for (int i = 0; i < wearables.Length; i++) 3582
3552 { 3583 for (int i = 0; i < wearables.Length; i++)
3553 for (int j = 0; j < wearables[i].Count; j++) 3584 {
3554 { 3585 for (int j = 0; j < wearables[i].Count; j++)
3555 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3586 {
3556 awb.WearableType = (byte)i; 3587 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3557 awb.AssetID = wearables[i][j].AssetID; 3588 awb.WearableType = (byte) i;
3558 awb.ItemID = wearables[i][j].ItemID; 3589 awb.AssetID = wearables[i][j].AssetID;
3559 aw.WearableData[idx] = awb; 3590 awb.ItemID = wearables[i][j].ItemID;
3560 idx++; 3591 aw.WearableData[idx] = awb;
3561 3592 idx++;
3562// m_log.DebugFormat( 3593
3563// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3594 // m_log.DebugFormat(
3564// awb.ItemID, awb.AssetID, i, Name); 3595 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3565 } 3596 // awb.ItemID, awb.AssetID, i, Name);
3566 } 3597 }
3598 }
3567 3599
3568 OutPacket(aw, ThrottleOutPacketType.Task); 3600 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3569 } 3601 }
3570 3602
3571 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3603 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3576,7 +3608,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3576 3608
3577 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3609 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3578 // TODO: don't create new blocks if recycling an old packet 3610 // TODO: don't create new blocks if recycling an old packet
3579 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3611 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3580 avp.ObjectData.TextureEntry = textureEntry; 3612 avp.ObjectData.TextureEntry = textureEntry;
3581 3613
3582 AvatarAppearancePacket.VisualParamBlock avblock = null; 3614 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3707,7 +3739,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3707 /// </summary> 3739 /// </summary>
3708 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3740 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3709 { 3741 {
3710 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3742 if (entity is SceneObjectPart)
3743 {
3744 SceneObjectPart e = (SceneObjectPart)entity;
3745 SceneObjectGroup g = e.ParentGroup;
3746 if (g.RootPart.Shape.State > 30) // HUD
3747 if (g.OwnerID != AgentId)
3748 return; // Don't send updates for other people's HUDs
3749 }
3750
3711 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3751 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3712 3752
3713 lock (m_entityUpdates.SyncRoot) 3753 lock (m_entityUpdates.SyncRoot)
@@ -3774,27 +3814,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3774 3814
3775 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3815 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3776 // condition where a kill can be processed before an out-of-date update for the same object. 3816 // condition where a kill can be processed before an out-of-date update for the same object.
3777 lock (m_killRecord) 3817 float avgTimeDilation = 1.0f;
3818 IEntityUpdate iupdate;
3819 Int32 timeinqueue; // this is just debugging code & can be dropped later
3820
3821 while (updatesThisCall < maxUpdates)
3778 { 3822 {
3779 float avgTimeDilation = 1.0f; 3823 lock (m_entityUpdates.SyncRoot)
3780 IEntityUpdate iupdate; 3824 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3781 Int32 timeinqueue; // this is just debugging code & can be dropped later 3825 break;
3826
3827 EntityUpdate update = (EntityUpdate)iupdate;
3828
3829 avgTimeDilation += update.TimeDilation;
3830 avgTimeDilation *= 0.5f;
3782 3831
3783 while (updatesThisCall < maxUpdates) 3832 if (update.Entity is SceneObjectPart)
3784 { 3833 {
3785 lock (m_entityUpdates.SyncRoot) 3834 SceneObjectPart part = (SceneObjectPart)update.Entity;
3786 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3787 break;
3788 3835
3789 EntityUpdate update = (EntityUpdate)iupdate; 3836 if (part.ParentGroup.IsDeleted)
3790 3837 continue;
3791 avgTimeDilation += update.TimeDilation;
3792 avgTimeDilation *= 0.5f;
3793 3838
3794 if (update.Entity is SceneObjectPart) 3839 if (part.ParentGroup.IsAttachment)
3840 { // Someone else's HUD, why are we getting these?
3841 if (part.ParentGroup.OwnerID != AgentId &&
3842 part.ParentGroup.RootPart.Shape.State > 30)
3843 continue;
3844 ScenePresence sp;
3845 // Owner is not in the sim, don't update it to
3846 // anyone
3847 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3848 continue;
3849
3850 List<SceneObjectGroup> atts = sp.GetAttachments();
3851 bool found = false;
3852 foreach (SceneObjectGroup att in atts)
3853 {
3854 if (att == part.ParentGroup)
3855 {
3856 found = true;
3857 break;
3858 }
3859 }
3860
3861 // It's an attachment of a valid avatar, but
3862 // doesn't seem to be attached, skip
3863 if (!found)
3864 continue;
3865
3866 // On vehicle crossing, the attachments are received
3867 // while the avatar is still a child. Don't send
3868 // updates here because the LocalId has not yet
3869 // been updated and the viewer will derender the
3870 // attachments until the avatar becomes root.
3871 if (sp.IsChildAgent)
3872 continue;
3873
3874 // If the object is an attachment we don't want it to be in the kill
3875 // record. Else attaching from inworld and subsequently dropping
3876 // it will no longer work.
3877// lock (m_killRecord)
3878// {
3879// m_killRecord.Remove(part.LocalId);
3880// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3881// }
3882 }
3883 else
3795 { 3884 {
3796 SceneObjectPart part = (SceneObjectPart)update.Entity;
3797
3798 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3885 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3799 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3886 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3800 // safety measure. 3887 // safety measure.
@@ -3805,21 +3892,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3805 // 3892 //
3806 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3893 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3807 // after the root prim has been deleted. 3894 // after the root prim has been deleted.
3808 if (m_killRecord.Contains(part.LocalId)) 3895 //
3809 { 3896 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3810 // m_log.WarnFormat( 3897// lock (m_killRecord)
3811 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3898// {
3812 // part.LocalId, Name); 3899// if (m_killRecord.Contains(part.LocalId))
3813 continue; 3900// continue;
3814 } 3901// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3815 3902// continue;
3816 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3903// }
3904 }
3905
3906 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3907 {
3908 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3909 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3817 { 3910 {
3818 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3911 part.Shape.LightEntry = false;
3819 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3820 {
3821 part.Shape.LightEntry = false;
3822 }
3823 } 3912 }
3824 3913
3825 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 3914 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
@@ -3830,224 +3919,166 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3830 part.Shape.ProfileHollow = 27500; 3919 part.Shape.ProfileHollow = 27500;
3831 } 3920 }
3832 } 3921 }
3833 3922
3834 #region UpdateFlags to packet type conversion 3923 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3835
3836 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3837
3838 bool canUseCompressed = true;
3839 bool canUseImproved = true;
3840
3841 // Compressed object updates only make sense for LL primitives
3842 if (!(update.Entity is SceneObjectPart))
3843 { 3924 {
3844 canUseCompressed = false; 3925 // Ensure that mesh has at least 8 valid faces
3926 part.Shape.ProfileBegin = 12500;
3927 part.Shape.ProfileEnd = 0;
3928 part.Shape.ProfileHollow = 27500;
3845 } 3929 }
3846 3930 }
3847 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3931
3932 ++updatesThisCall;
3933
3934 #region UpdateFlags to packet type conversion
3935
3936 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3937
3938 bool canUseCompressed = true;
3939 bool canUseImproved = true;
3940
3941 // Compressed object updates only make sense for LL primitives
3942 if (!(update.Entity is SceneObjectPart))
3943 {
3944 canUseCompressed = false;
3945 }
3946
3947 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3948 {
3949 canUseCompressed = false;
3950 canUseImproved = false;
3951 }
3952 else
3953 {
3954 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3955 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3956 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3957 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3848 { 3958 {
3849 canUseCompressed = false; 3959 canUseCompressed = false;
3850 canUseImproved = false;
3851 } 3960 }
3852 else 3961
3962 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3963 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3964 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3965 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3966 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3967 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3968 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3969 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3970 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3971 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3972 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3973 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3974 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3975 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3853 { 3976 {
3854 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3977 canUseImproved = false;
3855 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3856 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3857 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3858 {
3859 canUseCompressed = false;
3860 }
3861
3862 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3863 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3864 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3865 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3866 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3867 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3868 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3869 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3870 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3871 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3872 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3873 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3874 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3875 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3876 {
3877 canUseImproved = false;
3878 }
3879 } 3978 }
3979 }
3880 3980
3881 #endregion UpdateFlags to packet type conversion 3981 #endregion UpdateFlags to packet type conversion
3882
3883 #region Block Construction
3884
3885 // TODO: Remove this once we can build compressed updates
3886 canUseCompressed = false;
3887
3888 if (!canUseImproved && !canUseCompressed)
3889 {
3890 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3891 3982
3892 if (update.Entity is ScenePresence) 3983 #region Block Construction
3893 {
3894 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3895 }
3896 else
3897 {
3898 SceneObjectPart part = (SceneObjectPart)update.Entity;
3899 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3900
3901 // If the part has become a private hud since the update was scheduled then we do not
3902 // want to send it to other avatars.
3903 if (part.ParentGroup.IsAttachment
3904 && part.ParentGroup.HasPrivateAttachmentPoint
3905 && part.ParentGroup.AttachedAvatar != AgentId)
3906 continue;
3907
3908 // If the part has since been deleted, then drop the update. In the case of attachments,
3909 // this is to avoid spurious updates to other viewers since post-processing of attachments
3910 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3911 // of the test above).
3912 //
3913 // Actual deletions (kills) happen in another method.
3914 if (part.ParentGroup.IsDeleted)
3915 continue;
3916 }
3917 3984
3918 objectUpdateBlocks.Value.Add(updateBlock); 3985 // TODO: Remove this once we can build compressed updates
3919 objectUpdates.Value.Add(update); 3986 canUseCompressed = false;
3920 }
3921 else if (!canUseImproved)
3922 {
3923 SceneObjectPart part = (SceneObjectPart)update.Entity;
3924 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
3925 = CreateCompressedUpdateBlock(part, updateFlags);
3926
3927 // If the part has since been deleted, then drop the update. In the case of attachments,
3928 // this is to avoid spurious updates to other viewers since post-processing of attachments
3929 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3930 // of the test above).
3931 //
3932 // Actual deletions (kills) happen in another method.
3933 if (part.ParentGroup.IsDeleted)
3934 continue;
3935 3987
3936 compressedUpdateBlocks.Value.Add(compressedBlock); 3988 if (!canUseImproved && !canUseCompressed)
3937 compressedUpdates.Value.Add(update); 3989 {
3990 if (update.Entity is ScenePresence)
3991 {
3992 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3938 } 3993 }
3939 else 3994 else
3940 { 3995 {
3941 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3996 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3942 {
3943 // Self updates go into a special list
3944 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3945 terseAgentUpdates.Value.Add(update);
3946 }
3947 else
3948 {
3949 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
3950 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
3951
3952 // Everything else goes here
3953 if (update.Entity is SceneObjectPart)
3954 {
3955 SceneObjectPart part = (SceneObjectPart)update.Entity;
3956
3957 // If the part has become a private hud since the update was scheduled then we do not
3958 // want to send it to other avatars.
3959 if (part.ParentGroup.IsAttachment
3960 && part.ParentGroup.HasPrivateAttachmentPoint
3961 && part.ParentGroup.AttachedAvatar != AgentId)
3962 continue;
3963
3964 // If the part has since been deleted, then drop the update. In the case of attachments,
3965 // this is to avoid spurious updates to other viewers since post-processing of attachments
3966 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3967 // of the test above).
3968 //
3969 // Actual deletions (kills) happen in another method.
3970 if (part.ParentGroup.IsDeleted)
3971 continue;
3972 }
3973
3974 terseUpdateBlocks.Value.Add(terseUpdateBlock);
3975 terseUpdates.Value.Add(update);
3976 }
3977 } 3997 }
3978
3979 ++updatesThisCall;
3980
3981 #endregion Block Construction
3982 } 3998 }
3983 3999 else if (!canUseImproved)
3984 #region Packet Sending
3985 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3986
3987 if (terseAgentUpdateBlocks.IsValueCreated)
3988 { 4000 {
3989 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4001 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
4002 }
4003 else
4004 {
4005 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
4006 // Self updates go into a special list
4007 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4008 else
4009 // Everything else goes here
4010 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4011 }
3990 4012
3991 ImprovedTerseObjectUpdatePacket packet 4013 #endregion Block Construction
3992 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4014 }
3993 4015
3994 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4016 #region Packet Sending
3995 packet.RegionData.TimeDilation = timeDilation; 4017
3996 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4018 const float TIME_DILATION = 1.0f;
4019 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4020
4021 if (terseAgentUpdateBlocks.IsValueCreated)
4022 {
4023 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3997 4024
3998 for (int i = 0; i < blocks.Count; i++) 4025 ImprovedTerseObjectUpdatePacket packet
3999 packet.ObjectData[i] = blocks[i]; 4026 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4000 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4027 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4001 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4028 packet.RegionData.TimeDilation = timeDilation;
4002 } 4029 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4003 4030
4004 if (objectUpdateBlocks.IsValueCreated) 4031 for (int i = 0; i < blocks.Count; i++)
4005 { 4032 packet.ObjectData[i] = blocks[i];
4006 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4007
4008 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4009 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4010 packet.RegionData.TimeDilation = timeDilation;
4011 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4012
4013 for (int i = 0; i < blocks.Count; i++)
4014 packet.ObjectData[i] = blocks[i];
4015 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4016 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4017 }
4018
4019 if (compressedUpdateBlocks.IsValueCreated)
4020 {
4021 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4022
4023 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4024 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4025 packet.RegionData.TimeDilation = timeDilation;
4026 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4027
4028 for (int i = 0; i < blocks.Count; i++)
4029 packet.ObjectData[i] = blocks[i];
4030 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4031 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4032 }
4033 4033
4034 if (terseUpdateBlocks.IsValueCreated) 4034 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4035 { 4035 }
4036 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4037
4038 ImprovedTerseObjectUpdatePacket packet
4039 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4040 PacketType.ImprovedTerseObjectUpdate);
4041 4036
4042 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4037 if (objectUpdateBlocks.IsValueCreated)
4043 packet.RegionData.TimeDilation = timeDilation; 4038 {
4044 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4039 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4045 4040
4046 for (int i = 0; i < blocks.Count; i++) 4041 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4047 packet.ObjectData[i] = blocks[i]; 4042 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4048 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4043 packet.RegionData.TimeDilation = timeDilation;
4049 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4044 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4050 } 4045
4046 for (int i = 0; i < blocks.Count; i++)
4047 packet.ObjectData[i] = blocks[i];
4048
4049 OutPacket(packet, ThrottleOutPacketType.Task, true);
4050 }
4051
4052 if (compressedUpdateBlocks.IsValueCreated)
4053 {
4054 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4055
4056 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4057 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4058 packet.RegionData.TimeDilation = timeDilation;
4059 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4060
4061 for (int i = 0; i < blocks.Count; i++)
4062 packet.ObjectData[i] = blocks[i];
4063
4064 OutPacket(packet, ThrottleOutPacketType.Task, true);
4065 }
4066
4067 if (terseUpdateBlocks.IsValueCreated)
4068 {
4069 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4070
4071 ImprovedTerseObjectUpdatePacket packet
4072 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4073 PacketType.ImprovedTerseObjectUpdate);
4074 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4075 packet.RegionData.TimeDilation = timeDilation;
4076 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4077
4078 for (int i = 0; i < blocks.Count; i++)
4079 packet.ObjectData[i] = blocks[i];
4080
4081 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4051 } 4082 }
4052 4083
4053 #endregion Packet Sending 4084 #endregion Packet Sending
@@ -4340,11 +4371,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4340 4371
4341 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4372 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4342 // of the object rather than the properties when the packet was created 4373 // of the object rather than the properties when the packet was created
4343 OutPacket(packet, ThrottleOutPacketType.Task, true, 4374 // HACK : Remove intelligent resending until it's fixed in core
4344 delegate(OutgoingPacket oPacket) 4375 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4345 { 4376 // delegate(OutgoingPacket oPacket)
4346 ResendPropertyUpdates(updates, oPacket); 4377 // {
4347 }); 4378 // ResendPropertyUpdates(updates, oPacket);
4379 // });
4380 OutPacket(packet, ThrottleOutPacketType.Task, true);
4348 4381
4349 // pbcnt += blocks.Count; 4382 // pbcnt += blocks.Count;
4350 // ppcnt++; 4383 // ppcnt++;
@@ -4370,11 +4403,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4370 // of the object rather than the properties when the packet was created 4403 // of the object rather than the properties when the packet was created
4371 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4404 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4372 updates.Add(familyUpdates.Value[i]); 4405 updates.Add(familyUpdates.Value[i]);
4373 OutPacket(packet, ThrottleOutPacketType.Task, true, 4406 // HACK : Remove intelligent resending until it's fixed in core
4374 delegate(OutgoingPacket oPacket) 4407 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4375 { 4408 // delegate(OutgoingPacket oPacket)
4376 ResendPropertyUpdates(updates, oPacket); 4409 // {
4377 }); 4410 // ResendPropertyUpdates(updates, oPacket);
4411 // });
4412 OutPacket(packet, ThrottleOutPacketType.Task, true);
4378 4413
4379 // fpcnt++; 4414 // fpcnt++;
4380 // fbcnt++; 4415 // fbcnt++;
@@ -4746,7 +4781,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4746 4781
4747 if (landData.SimwideArea > 0) 4782 if (landData.SimwideArea > 0)
4748 { 4783 {
4749 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4784 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4785 // Never report more than sim total capacity
4786 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4787 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4750 updateMessage.SimWideMaxPrims = simulatorCapacity; 4788 updateMessage.SimWideMaxPrims = simulatorCapacity;
4751 } 4789 }
4752 else 4790 else
@@ -4875,14 +4913,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4875 4913
4876 if (notifyCount > 0) 4914 if (notifyCount > 0)
4877 { 4915 {
4878 if (notifyCount > 32) 4916// if (notifyCount > 32)
4879 { 4917// {
4880 m_log.InfoFormat( 4918// m_log.InfoFormat(
4881 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4919// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4882 + " - a developer might want to investigate whether this is a hard limit", 32); 4920// + " - a developer might want to investigate whether this is a hard limit", 32);
4883 4921//
4884 notifyCount = 32; 4922// notifyCount = 32;
4885 } 4923// }
4886 4924
4887 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4925 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4888 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4926 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4937,9 +4975,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4937 { 4975 {
4938 ScenePresence presence = (ScenePresence)entity; 4976 ScenePresence presence = (ScenePresence)entity;
4939 4977
4978 position = presence.OffsetPosition;
4979 rotation = presence.Rotation;
4980
4981 if (presence.ParentID != 0)
4982 {
4983 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
4984 if (part != null && part != part.ParentGroup.RootPart)
4985 {
4986 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
4987 rotation = part.RotationOffset * presence.Rotation;
4988 }
4989 angularVelocity = Vector3.Zero;
4990 }
4991 else
4992 {
4993 angularVelocity = presence.AngularVelocity;
4994 rotation = presence.Rotation;
4995 }
4996
4940 attachPoint = 0; 4997 attachPoint = 0;
4941 collisionPlane = presence.CollisionPlane; 4998 collisionPlane = presence.CollisionPlane;
4942 position = presence.OffsetPosition;
4943 velocity = presence.Velocity; 4999 velocity = presence.Velocity;
4944 acceleration = Vector3.Zero; 5000 acceleration = Vector3.Zero;
4945 5001
@@ -4948,9 +5004,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4948 // may improve movement smoothness. 5004 // may improve movement smoothness.
4949// acceleration = new Vector3(1, 0, 0); 5005// acceleration = new Vector3(1, 0, 0);
4950 5006
4951 angularVelocity = presence.AngularVelocity;
4952 rotation = presence.Rotation;
4953
4954 if (sendTexture) 5007 if (sendTexture)
4955 textureEntry = presence.Appearance.Texture.GetBytes(); 5008 textureEntry = presence.Appearance.Texture.GetBytes();
4956 else 5009 else
@@ -5056,13 +5109,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5056 5109
5057 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5110 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5058 { 5111 {
5112 Vector3 offsetPosition = data.OffsetPosition;
5113 Quaternion rotation = data.Rotation;
5114 uint parentID = data.ParentID;
5115
5116 if (parentID != 0)
5117 {
5118 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5119 if (part != null && part != part.ParentGroup.RootPart)
5120 {
5121 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5122 rotation = part.RotationOffset * data.Rotation;
5123 parentID = part.ParentGroup.RootPart.LocalId;
5124 }
5125 }
5126
5059 byte[] objectData = new byte[76]; 5127 byte[] objectData = new byte[76];
5060 5128
5061 data.CollisionPlane.ToBytes(objectData, 0); 5129 data.CollisionPlane.ToBytes(objectData, 0);
5062 data.OffsetPosition.ToBytes(objectData, 16); 5130 offsetPosition.ToBytes(objectData, 16);
5063// data.Velocity.ToBytes(objectData, 28); 5131// data.Velocity.ToBytes(objectData, 28);
5064// data.Acceleration.ToBytes(objectData, 40); 5132// data.Acceleration.ToBytes(objectData, 40);
5065 data.Rotation.ToBytes(objectData, 52); 5133 rotation.ToBytes(objectData, 52);
5066 //data.AngularVelocity.ToBytes(objectData, 64); 5134 //data.AngularVelocity.ToBytes(objectData, 64);
5067 5135
5068 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5136 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5076,14 +5144,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5076 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5144 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5077 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5145 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5078 update.ObjectData = objectData; 5146 update.ObjectData = objectData;
5079 update.ParentID = data.ParentID; 5147 update.ParentID = parentID;
5080 update.PathCurve = 16; 5148 update.PathCurve = 16;
5081 update.PathScaleX = 100; 5149 update.PathScaleX = 100;
5082 update.PathScaleY = 100; 5150 update.PathScaleY = 100;
5083 update.PCode = (byte)PCode.Avatar; 5151 update.PCode = (byte)PCode.Avatar;
5084 update.ProfileCurve = 1; 5152 update.ProfileCurve = 1;
5085 update.PSBlock = Utils.EmptyBytes; 5153 update.PSBlock = Utils.EmptyBytes;
5086 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5154 update.Scale = data.Appearance.AvatarSize;
5155// update.Scale.Z -= 0.2f;
5156
5087 update.Text = Utils.EmptyBytes; 5157 update.Text = Utils.EmptyBytes;
5088 update.TextColor = new byte[4]; 5158 update.TextColor = new byte[4];
5089 5159
@@ -5094,10 +5164,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5094 update.TextureEntry = Utils.EmptyBytes; 5164 update.TextureEntry = Utils.EmptyBytes;
5095// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5165// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5096 5166
5167/* 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)
5097 update.UpdateFlags = (uint)( 5168 update.UpdateFlags = (uint)(
5098 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5169 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5099 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5170 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5100 PrimFlags.ObjectOwnerModify); 5171 PrimFlags.ObjectOwnerModify);
5172*/
5173 update.UpdateFlags = 0;
5101 5174
5102 return update; 5175 return update;
5103 } 5176 }
@@ -5268,8 +5341,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5268 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5341 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5269 // for each AgentUpdate packet. 5342 // for each AgentUpdate packet.
5270 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5343 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5271 5344
5272 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5345 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5346 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5347 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5273 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5348 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5274 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5349 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5275 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5350 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5421,6 +5496,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5421 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5496 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5422 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5497 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5423 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5498 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5499 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5424 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5500 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5425 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5501 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5426 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5502 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5487,6 +5563,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5487 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5563 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5488 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5564 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5489 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5565 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5566 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5490 5567
5491 AddGenericPacketHandler("autopilot", HandleAutopilot); 5568 AddGenericPacketHandler("autopilot", HandleAutopilot);
5492 } 5569 }
@@ -5525,6 +5602,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5525 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || 5602 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5526 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || 5603 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5527 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || 5604 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5605 (x.ControlFlags != 0) ||
5528 (x.Far != m_lastAgentUpdateArgs.Far) || 5606 (x.Far != m_lastAgentUpdateArgs.Far) ||
5529 (x.Flags != m_lastAgentUpdateArgs.Flags) || 5607 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5530 (x.State != m_lastAgentUpdateArgs.State) || 5608 (x.State != m_lastAgentUpdateArgs.State) ||
@@ -5784,6 +5862,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5784 return true; 5862 return true;
5785 } 5863 }
5786 5864
5865 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
5866 {
5867 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
5868 if (p.AgentData.SessionID != SessionId ||
5869 p.AgentData.AgentID != AgentId)
5870 return true;
5871
5872 m_VelocityInterpolate = false;
5873 return true;
5874 }
5875
5876 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
5877 {
5878 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
5879 if (p.AgentData.SessionID != SessionId ||
5880 p.AgentData.AgentID != AgentId)
5881 return true;
5882
5883 m_VelocityInterpolate = true;
5884 return true;
5885 }
5886
5887
5787 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 5888 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5788 { 5889 {
5789 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 5890 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6204,17 +6305,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6204 // Temporarily protect ourselves from the mantis #951 failure. 6305 // Temporarily protect ourselves from the mantis #951 failure.
6205 // However, we could do this for several other handlers where a failure isn't terminal 6306 // However, we could do this for several other handlers where a failure isn't terminal
6206 // for the client session anyway, in order to protect ourselves against bad code in plugins 6307 // for the client session anyway, in order to protect ourselves against bad code in plugins
6308 Vector3 avSize = appear.AgentData.Size;
6207 try 6309 try
6208 { 6310 {
6209 byte[] visualparams = new byte[appear.VisualParam.Length]; 6311 byte[] visualparams = new byte[appear.VisualParam.Length];
6210 for (int i = 0; i < appear.VisualParam.Length; i++) 6312 for (int i = 0; i < appear.VisualParam.Length; i++)
6211 visualparams[i] = appear.VisualParam[i].ParamValue; 6313 visualparams[i] = appear.VisualParam[i].ParamValue;
6212 6314 //var b = appear.WearableData[0];
6315
6213 Primitive.TextureEntry te = null; 6316 Primitive.TextureEntry te = null;
6214 if (appear.ObjectData.TextureEntry.Length > 1) 6317 if (appear.ObjectData.TextureEntry.Length > 1)
6215 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6318 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6319
6320 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6321 for (int i=0; i<appear.WearableData.Length;i++)
6322 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6216 6323
6217 handlerSetAppearance(sender, te, visualparams); 6324
6325
6326 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6218 } 6327 }
6219 catch (Exception e) 6328 catch (Exception e)
6220 { 6329 {
@@ -6423,6 +6532,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6423 { 6532 {
6424 handlerCompleteMovementToRegion(sender, true); 6533 handlerCompleteMovementToRegion(sender, true);
6425 } 6534 }
6535 else
6536 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6537
6426 handlerCompleteMovementToRegion = null; 6538 handlerCompleteMovementToRegion = null;
6427 6539
6428 return true; 6540 return true;
@@ -6440,7 +6552,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6440 return true; 6552 return true;
6441 } 6553 }
6442 #endregion 6554 #endregion
6443 6555/*
6444 StartAnim handlerStartAnim = null; 6556 StartAnim handlerStartAnim = null;
6445 StopAnim handlerStopAnim = null; 6557 StopAnim handlerStopAnim = null;
6446 6558
@@ -6464,6 +6576,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6464 } 6576 }
6465 } 6577 }
6466 return true; 6578 return true;
6579*/
6580 ChangeAnim handlerChangeAnim = null;
6581
6582 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6583 {
6584 handlerChangeAnim = OnChangeAnim;
6585 if (handlerChangeAnim != null)
6586 {
6587 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6588 }
6589 }
6590
6591 handlerChangeAnim = OnChangeAnim;
6592 if (handlerChangeAnim != null)
6593 {
6594 handlerChangeAnim(UUID.Zero, false, true);
6595 }
6596
6597 return true;
6467 } 6598 }
6468 6599
6469 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6600 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6689,6 +6820,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6689 #endregion 6820 #endregion
6690 6821
6691 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6822 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6823 GenericCall2 handler = OnUpdateThrottles;
6824 if (handler != null)
6825 {
6826 handler();
6827 }
6692 return true; 6828 return true;
6693 } 6829 }
6694 6830
@@ -7113,7 +7249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7113 physdata.Bounce = phsblock.Restitution; 7249 physdata.Bounce = phsblock.Restitution;
7114 physdata.Density = phsblock.Density; 7250 physdata.Density = phsblock.Density;
7115 physdata.Friction = phsblock.Friction; 7251 physdata.Friction = phsblock.Friction;
7116 physdata.GravitationModifier = phsblock.GravityMultiplier; 7252 physdata.GravitationModifier = phsblock.GravityMultiplier;
7117 } 7253 }
7118 7254
7119 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7255 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7699,6 +7835,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7699 // surrounding scene 7835 // surrounding scene
7700 if ((ImageType)block.Type == ImageType.Baked) 7836 if ((ImageType)block.Type == ImageType.Baked)
7701 args.Priority *= 2.0f; 7837 args.Priority *= 2.0f;
7838 int wearableout = 0;
7702 7839
7703 ImageManager.EnqueueReq(args); 7840 ImageManager.EnqueueReq(args);
7704 } 7841 }
@@ -8717,16 +8854,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8717 8854
8718 #region Parcel related packets 8855 #region Parcel related packets
8719 8856
8857 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
8858 // to be done with minimal resources as possible
8859 // variables temporary here while in test
8860
8861 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
8862 bool RegionHandleRequestsInService = false;
8863
8720 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 8864 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8721 { 8865 {
8722 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 8866 UUID currentUUID;
8723 8867
8724 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 8868 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8725 if (handlerRegionHandleRequest != null) 8869
8870 if (handlerRegionHandleRequest == null)
8871 return true;
8872
8873 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
8874
8875 lock (RegionHandleRequests)
8876 {
8877 if (RegionHandleRequestsInService)
8878 {
8879 // we are already busy doing a previus request
8880 // so enqueue it
8881 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
8882 return true;
8883 }
8884
8885 // else do it
8886 currentUUID = rhrPack.RequestBlock.RegionID;
8887 RegionHandleRequestsInService = true;
8888 }
8889
8890 while (true)
8726 { 8891 {
8727 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 8892 handlerRegionHandleRequest(this, currentUUID);
8893
8894 lock (RegionHandleRequests)
8895 {
8896 // exit condition, nothing to do or closed
8897 // current code seems to assume we may loose the handler at anytime,
8898 // so keep checking it
8899 handlerRegionHandleRequest = OnRegionHandleRequest;
8900
8901 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
8902 {
8903 RegionHandleRequests.Clear();
8904 RegionHandleRequestsInService = false;
8905 return true;
8906 }
8907 currentUUID = RegionHandleRequests.Dequeue();
8908 }
8728 } 8909 }
8729 return true; 8910
8911 return true; // actually unreached
8730 } 8912 }
8731 8913
8732 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 8914 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -9982,7 +10164,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9982 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10164 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9983 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10165 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9984 UpdateMuteListEntry.MuteData.MuteType, 10166 UpdateMuteListEntry.MuteData.MuteType,
9985 UpdateMuteListEntry.AgentData.AgentID); 10167 UpdateMuteListEntry.MuteData.MuteFlags);
9986 return true; 10168 return true;
9987 } 10169 }
9988 return false; 10170 return false;
@@ -9997,8 +10179,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9997 { 10179 {
9998 handlerRemoveMuteListEntry(this, 10180 handlerRemoveMuteListEntry(this,
9999 RemoveMuteListEntry.MuteData.MuteID, 10181 RemoveMuteListEntry.MuteData.MuteID,
10000 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10182 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
10001 RemoveMuteListEntry.AgentData.AgentID);
10002 return true; 10183 return true;
10003 } 10184 }
10004 return false; 10185 return false;
@@ -10042,10 +10223,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10042 return false; 10223 return false;
10043 } 10224 }
10044 10225
10226 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10227 {
10228 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10229 (ChangeInventoryItemFlagsPacket)packet;
10230 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10231 if (handlerChangeInventoryItemFlags != null)
10232 {
10233 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10234 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10235 return true;
10236 }
10237 return false;
10238 }
10239
10045 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10240 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10046 { 10241 {
10047 return true; 10242 return true;
10048 } 10243 }
10244
10245 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10246 {
10247 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10248
10249 #region Packet Session and User Check
10250 if (m_checkPackets)
10251 {
10252 if (packet.AgentData.SessionID != SessionId ||
10253 packet.AgentData.AgentID != AgentId)
10254 return true;
10255 }
10256 #endregion
10257 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10258 List<InventoryItemBase> items = new List<InventoryItemBase>();
10259 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10260 {
10261 InventoryItemBase b = new InventoryItemBase();
10262 b.ID = n.OldItemID;
10263 b.Folder = n.OldFolderID;
10264 items.Add(b);
10265 }
10266
10267 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10268 if (handlerMoveItemsAndLeaveCopy != null)
10269 {
10270 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10271 }
10272
10273 return true;
10274 }
10049 10275
10050 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10276 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10051 { 10277 {
@@ -10472,6 +10698,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10472 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10698 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10473 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10699 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10474 10700
10701 Scene scene = (Scene)m_scene;
10702 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10703 {
10704 ScenePresence p;
10705 if (scene.TryGetScenePresence(sender.AgentId, out p))
10706 {
10707 if (p.GodLevel >= 200)
10708 {
10709 groupProfileReply.GroupData.OpenEnrollment = true;
10710 groupProfileReply.GroupData.MembershipFee = 0;
10711 }
10712 }
10713 }
10714
10475 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10715 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10476 } 10716 }
10477 return true; 10717 return true;
@@ -11045,11 +11285,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11045 11285
11046 StartLure handlerStartLure = OnStartLure; 11286 StartLure handlerStartLure = OnStartLure;
11047 if (handlerStartLure != null) 11287 if (handlerStartLure != null)
11048 handlerStartLure(startLureRequest.Info.LureType, 11288 {
11049 Utils.BytesToString( 11289 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11050 startLureRequest.Info.Message), 11290 {
11051 startLureRequest.TargetData[0].TargetID, 11291 handlerStartLure(startLureRequest.Info.LureType,
11052 this); 11292 Utils.BytesToString(
11293 startLureRequest.Info.Message),
11294 startLureRequest.TargetData[i].TargetID,
11295 this);
11296 }
11297 }
11053 return true; 11298 return true;
11054 } 11299 }
11055 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11300 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11163,10 +11408,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11163 } 11408 }
11164 #endregion 11409 #endregion
11165 11410
11166 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11411 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11167 if (handlerClassifiedGodDelete != null) 11412 if (handlerClassifiedGodDelete != null)
11168 handlerClassifiedGodDelete( 11413 handlerClassifiedGodDelete(
11169 classifiedGodDelete.Data.ClassifiedID, 11414 classifiedGodDelete.Data.ClassifiedID,
11415 classifiedGodDelete.Data.QueryID,
11170 this); 11416 this);
11171 return true; 11417 return true;
11172 } 11418 }
@@ -11469,12 +11715,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11469 /// <param name="simclient"></param> 11715 /// <param name="simclient"></param>
11470 /// <param name="packet"></param> 11716 /// <param name="packet"></param>
11471 /// <returns></returns> 11717 /// <returns></returns>
11472 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11718 // TODO: Convert old handler to use new method
11719 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11473 { 11720 {
11474 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 11721 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11475 11722
11476 if (cachedtex.AgentData.SessionID != SessionId) 11723 if (cachedtex.AgentData.SessionID != SessionId)
11477 return false; 11724 return false;
11725
11478 11726
11479 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); 11727 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11480 11728
@@ -11494,8 +11742,166 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11494 } 11742 }
11495 11743
11496 return true; 11744 return true;
11745 }*/
11746
11747 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11748 {
11749 //m_log.Debug("texture cached: " + packet.ToString());
11750 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11751 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11752
11753 if (cachedtex.AgentData.SessionID != SessionId)
11754 return false;
11755
11756
11757 // TODO: don't create new blocks if recycling an old packet
11758 cachedresp.AgentData.AgentID = AgentId;
11759 cachedresp.AgentData.SessionID = m_sessionId;
11760 cachedresp.AgentData.SerialNum = m_cachedTextureSerial;
11761 m_cachedTextureSerial++;
11762 cachedresp.WearableData =
11763 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11764
11765 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11766 // var item = fac.GetBakedTextureFaces(AgentId);
11767 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11768
11769 IAssetService cache = m_scene.AssetService;
11770 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11771 //bakedTextureModule = null;
11772 int maxWearablesLoop = cachedtex.WearableData.Length;
11773 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11774 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11775
11776 if (bakedTextureModule != null && cache != null)
11777 {
11778 // 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
11779
11780 WearableCacheItem[] cacheItems = null;
11781 ScenePresence p = m_scene.GetScenePresence(AgentId);
11782 if (p.Appearance != null)
11783 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11784 {
11785 try
11786 {
11787 cacheItems = bakedTextureModule.Get(AgentId);
11788 p.Appearance.WearableCacheItems = cacheItems;
11789 p.Appearance.WearableCacheItemsDirty = false;
11790 }
11791
11792 /*
11793 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11794 *
11795 catch (System.Net.Sockets.SocketException)
11796 {
11797 cacheItems = null;
11798 }
11799 catch (WebException)
11800 {
11801 cacheItems = null;
11802 }
11803 catch (InvalidOperationException)
11804 {
11805 cacheItems = null;
11806 } */
11807 catch (Exception)
11808 {
11809 cacheItems = null;
11810 }
11811
11812 }
11813 else if (p.Appearance.WearableCacheItems != null)
11814 {
11815 cacheItems = p.Appearance.WearableCacheItems;
11816 }
11817
11818 if (cache != null && cacheItems != null)
11819 {
11820 foreach (WearableCacheItem item in cacheItems)
11821 {
11822
11823 if (cache.GetCached(item.TextureID.ToString()) == null)
11824 {
11825 item.TextureAsset.Temporary = true;
11826 cache.Store(item.TextureAsset);
11827 }
11828
11829
11830 }
11831 }
11832
11833 if (cacheItems != null)
11834 {
11835
11836 for (int i = 0; i < maxWearablesLoop; i++)
11837 {
11838 WearableCacheItem item =
11839 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11840
11841 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11842 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
11843 cachedresp.WearableData[i].HostName = new byte[0];
11844 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11845 {
11846
11847 cachedresp.WearableData[i].TextureID = item.TextureID;
11848 }
11849 else
11850 {
11851 cachedresp.WearableData[i].TextureID = UUID.Zero;
11852 }
11853 }
11854 }
11855 else
11856 {
11857 for (int i = 0; i < maxWearablesLoop; i++)
11858 {
11859 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11860 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11861 cachedresp.WearableData[i].TextureID = UUID.Zero;
11862 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11863 cachedresp.WearableData[i].HostName = new byte[0];
11864 }
11865 }
11866 }
11867 else
11868 {
11869 if (cache == null)
11870 {
11871 for (int i = 0; i < maxWearablesLoop; i++)
11872 {
11873 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11874 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11875 cachedresp.WearableData[i].TextureID = UUID.Zero;
11876 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11877 cachedresp.WearableData[i].HostName = new byte[0];
11878 }
11879 }
11880 else
11881 {
11882 for (int i = 0; i < maxWearablesLoop; i++)
11883 {
11884 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11885 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11886
11887
11888
11889 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11890 cachedresp.WearableData[i].TextureID = UUID.Zero;
11891 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11892 else
11893 cachedresp.WearableData[i].TextureID = UUID.Zero;
11894 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11895 cachedresp.WearableData[i].HostName = new byte[0];
11896 }
11897 }
11898 }
11899 cachedresp.Header.Zerocoded = true;
11900 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11901
11902 return true;
11497 } 11903 }
11498 11904
11499 /// <summary> 11905 /// <summary>
11500 /// Send a response back to a client when it asks the asset server (via the region server) if it has 11906 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11501 /// its appearance texture cached. 11907 /// its appearance texture cached.
@@ -11559,209 +11965,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11559 } 11965 }
11560 else 11966 else
11561 { 11967 {
11562// m_log.DebugFormat( 11968 ClientChangeObject updatehandler = onClientChangeObject;
11563// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11564// i, block.Type, part.Name, part.LocalId);
11565 11969
11566// // Do this once since fetch parts creates a new array. 11970 if (updatehandler != null)
11567// SceneObjectPart[] parts = part.ParentGroup.Parts; 11971 {
11568// for (int j = 0; j < parts.Length; j++) 11972 ObjectChangeData udata = new ObjectChangeData();
11569// {
11570// part.StoreUndoState();
11571// parts[j].IgnoreUndoUpdate = true;
11572// }
11573 11973
11574 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 11974 /*ubit from ll JIRA:
11975 * 0x01 position
11976 * 0x02 rotation
11977 * 0x04 scale
11978
11979 * 0x08 LINK_SET
11980 * 0x10 UNIFORM for scale
11981 */
11575 11982
11576 switch (block.Type) 11983 // translate to internal changes
11577 { 11984 // not all cases .. just the ones older code did
11578 case 1:
11579 Vector3 pos1 = new Vector3(block.Data, 0);
11580 11985
11581 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11986 switch (block.Type)
11582 if (handlerUpdatePrimSinglePosition != null) 11987 {
11583 { 11988 case 1: //change position sp
11584 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11989 udata.position = new Vector3(block.Data, 0);
11585 handlerUpdatePrimSinglePosition(localId, pos1, this);
11586 }
11587 break;
11588 11990
11589 case 2: 11991 udata.change = ObjectChangeType.primP;
11590 Quaternion rot1 = new Quaternion(block.Data, 0, true); 11992 updatehandler(localId, udata, this);
11993 break;
11591 11994
11592 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 11995 case 2: // rotation sp
11593 if (handlerUpdatePrimSingleRotation != null) 11996 udata.rotation = new Quaternion(block.Data, 0, true);
11594 {
11595 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11596 handlerUpdatePrimSingleRotation(localId, rot1, this);
11597 }
11598 break;
11599 11997
11600 case 3: 11998 udata.change = ObjectChangeType.primR;
11601 Vector3 rotPos = new Vector3(block.Data, 0); 11999 updatehandler(localId, udata, this);
11602 Quaternion rot2 = new Quaternion(block.Data, 12, true); 12000 break;
11603 12001
11604 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 12002 case 3: // position plus rotation
11605 if (handlerUpdatePrimSingleRotationPosition != null) 12003 udata.position = new Vector3(block.Data, 0);
11606 { 12004 udata.rotation = new Quaternion(block.Data, 12, true);
11607 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11608 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11609 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11610 }
11611 break;
11612 12005
11613 case 4: 12006 udata.change = ObjectChangeType.primPR;
11614 case 20: 12007 updatehandler(localId, udata, this);
11615 Vector3 scale4 = new Vector3(block.Data, 0); 12008 break;
11616 12009
11617 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 12010 case 4: // scale sp
11618 if (handlerUpdatePrimScale != null) 12011 udata.scale = new Vector3(block.Data, 0);
11619 { 12012 udata.change = ObjectChangeType.primS;
11620 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11621 handlerUpdatePrimScale(localId, scale4, this);
11622 }
11623 break;
11624 12013
11625 case 5: 12014 updatehandler(localId, udata, this);
11626 Vector3 scale1 = new Vector3(block.Data, 12); 12015 break;
11627 Vector3 pos11 = new Vector3(block.Data, 0);
11628 12016
11629 handlerUpdatePrimScale = OnUpdatePrimScale; 12017 case 0x14: // uniform scale sp
11630 if (handlerUpdatePrimScale != null) 12018 udata.scale = new Vector3(block.Data, 0);
11631 {
11632 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11633 handlerUpdatePrimScale(localId, scale1, this);
11634 12019
11635 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12020 udata.change = ObjectChangeType.primUS;
11636 if (handlerUpdatePrimSinglePosition != null) 12021 updatehandler(localId, udata, this);
11637 { 12022 break;
11638 handlerUpdatePrimSinglePosition(localId, pos11, this);
11639 }
11640 }
11641 break;
11642 12023
11643 case 9: 12024 case 5: // scale and position sp
11644 Vector3 pos2 = new Vector3(block.Data, 0); 12025 udata.position = new Vector3(block.Data, 0);
12026 udata.scale = new Vector3(block.Data, 12);
11645 12027
11646 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 12028 udata.change = ObjectChangeType.primPS;
12029 updatehandler(localId, udata, this);
12030 break;
11647 12031
11648 if (handlerUpdateVector != null) 12032 case 0x15: //uniform scale and position
11649 { 12033 udata.position = new Vector3(block.Data, 0);
11650 handlerUpdateVector(localId, pos2, this); 12034 udata.scale = new Vector3(block.Data, 12);
11651 }
11652 break;
11653 12035
11654 case 10: 12036 udata.change = ObjectChangeType.primPUS;
11655 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12037 updatehandler(localId, udata, this);
12038 break;
11656 12039
11657 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12040 // now group related (bit 4)
11658 if (handlerUpdatePrimRotation != null) 12041 case 9: //( 8 + 1 )group position
11659 { 12042 udata.position = new Vector3(block.Data, 0);
11660 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11661 handlerUpdatePrimRotation(localId, rot3, this);
11662 }
11663 break;
11664 12043
11665 case 11: 12044 udata.change = ObjectChangeType.groupP;
11666 Vector3 pos3 = new Vector3(block.Data, 0); 12045 updatehandler(localId, udata, this);
11667 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12046 break;
11668 12047
11669 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12048 case 0x0A: // (8 + 2) group rotation
11670 if (handlerUpdatePrimGroupRotation != null) 12049 udata.rotation = new Quaternion(block.Data, 0, true);
11671 {
11672 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11673 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11674 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11675 }
11676 break;
11677 case 12:
11678 case 28:
11679 Vector3 scale7 = new Vector3(block.Data, 0);
11680 12050
11681 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12051 udata.change = ObjectChangeType.groupR;
11682 if (handlerUpdatePrimGroupScale != null) 12052 updatehandler(localId, udata, this);
11683 { 12053 break;
11684 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11685 handlerUpdatePrimGroupScale(localId, scale7, this);
11686 }
11687 break;
11688 12054
11689 case 13: 12055 case 0x0B: //( 8 + 2 + 1) group rotation and position
11690 Vector3 scale2 = new Vector3(block.Data, 12); 12056 udata.position = new Vector3(block.Data, 0);
11691 Vector3 pos4 = new Vector3(block.Data, 0); 12057 udata.rotation = new Quaternion(block.Data, 12, true);
11692 12058
11693 handlerUpdatePrimScale = OnUpdatePrimScale; 12059 udata.change = ObjectChangeType.groupPR;
11694 if (handlerUpdatePrimScale != null) 12060 updatehandler(localId, udata, this);
11695 { 12061 break;
11696 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11697 handlerUpdatePrimScale(localId, scale2, this);
11698 12062
11699 // Change the position based on scale (for bug number 246) 12063 case 0x0C: // (8 + 4) group scale
11700 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12064 // only afects root prim and only sent by viewer editor object tab scaling
11701 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12065 // mouse edition only allows uniform scaling
11702 if (handlerUpdatePrimSinglePosition != null) 12066 // SL MAY CHANGE THIS in viewers
11703 {
11704 handlerUpdatePrimSinglePosition(localId, pos4, this);
11705 }
11706 }
11707 break;
11708 12067
11709 case 29: 12068 udata.scale = new Vector3(block.Data, 0);
11710 Vector3 scale5 = new Vector3(block.Data, 12);
11711 Vector3 pos5 = new Vector3(block.Data, 0);
11712 12069
11713 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12070 udata.change = ObjectChangeType.groupS;
11714 if (handlerUpdatePrimGroupScale != null) 12071 updatehandler(localId, udata, this);
11715 {
11716 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11717 part.StoreUndoState(true);
11718 part.IgnoreUndoUpdate = true;
11719 handlerUpdatePrimGroupScale(localId, scale5, this);
11720 handlerUpdateVector = OnUpdatePrimGroupPosition;
11721 12072
11722 if (handlerUpdateVector != null) 12073 break;
11723 {
11724 handlerUpdateVector(localId, pos5, this);
11725 }
11726 12074
11727 part.IgnoreUndoUpdate = false; 12075 case 0x0D: //(8 + 4 + 1) group scale and position
11728 } 12076 // exception as above
11729 12077
11730 break; 12078 udata.position = new Vector3(block.Data, 0);
12079 udata.scale = new Vector3(block.Data, 12);
11731 12080
11732 case 21: 12081 udata.change = ObjectChangeType.groupPS;
11733 Vector3 scale6 = new Vector3(block.Data, 12); 12082 updatehandler(localId, udata, this);
11734 Vector3 pos6 = new Vector3(block.Data, 0); 12083 break;
11735 12084
11736 handlerUpdatePrimScale = OnUpdatePrimScale; 12085 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11737 if (handlerUpdatePrimScale != null) 12086 udata.scale = new Vector3(block.Data, 0);
11738 {
11739 part.StoreUndoState(false);
11740 part.IgnoreUndoUpdate = true;
11741 12087
11742 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12088 udata.change = ObjectChangeType.groupUS;
11743 handlerUpdatePrimScale(localId, scale6, this); 12089 updatehandler(localId, udata, this);
11744 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12090 break;
11745 if (handlerUpdatePrimSinglePosition != null)
11746 {
11747 handlerUpdatePrimSinglePosition(localId, pos6, this);
11748 }
11749 12091
11750 part.IgnoreUndoUpdate = false; 12092 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11751 } 12093 udata.position = new Vector3(block.Data, 0);
11752 break; 12094 udata.scale = new Vector3(block.Data, 12);
11753 12095
11754 default: 12096 udata.change = ObjectChangeType.groupPUS;
11755 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12097 updatehandler(localId, udata, this);
11756 break; 12098 break;
12099
12100 default:
12101 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12102 break;
12103 }
11757 } 12104 }
11758 12105
11759// for (int j = 0; j < parts.Length; j++)
11760// parts[j].IgnoreUndoUpdate = false;
11761 } 12106 }
11762 } 12107 }
11763 } 12108 }
11764
11765 return true; 12109 return true;
11766 } 12110 }
11767 12111
@@ -11822,9 +12166,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11822 public void SetChildAgentThrottle(byte[] throttles) 12166 public void SetChildAgentThrottle(byte[] throttles)
11823 { 12167 {
11824 m_udpClient.SetThrottles(throttles); 12168 m_udpClient.SetThrottles(throttles);
12169 GenericCall2 handler = OnUpdateThrottles;
12170 if (handler != null)
12171 {
12172 handler();
12173 }
11825 } 12174 }
11826 12175
11827 /// <summary> 12176 /// <summary>
12177 /// Sets the throttles from values supplied by the client
12178 /// </summary>
12179 /// <param name="throttles"></param>
12180 public void SetAgentThrottleSilent(int throttle, int setting)
12181 {
12182 m_udpClient.ForceThrottleSetting(throttle,setting);
12183 //m_udpClient.SetThrottles(throttles);
12184
12185 }
12186
12187
12188 /// <summary>
11828 /// Get the current throttles for this client as a packed byte array 12189 /// Get the current throttles for this client as a packed byte array
11829 /// </summary> 12190 /// </summary>
11830 /// <param name="multiplier">Unused</param> 12191 /// <param name="multiplier">Unused</param>
@@ -12216,7 +12577,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12216// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12577// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12217// requestID, taskID, (SourceType)sourceType, Name); 12578// requestID, taskID, (SourceType)sourceType, Name);
12218 12579
12580
12581 //Note, the bool returned from the below function is useless since it is always false.
12219 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12582 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12583
12220 } 12584 }
12221 12585
12222 /// <summary> 12586 /// <summary>
@@ -12282,7 +12646,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12282 /// <returns></returns> 12646 /// <returns></returns>
12283 private static int CalculateNumPackets(byte[] data) 12647 private static int CalculateNumPackets(byte[] data)
12284 { 12648 {
12285 const uint m_maxPacketSize = 600; 12649// const uint m_maxPacketSize = 600;
12650 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12286 int numPackets = 1; 12651 int numPackets = 1;
12287 12652
12288 if (data == null) 12653 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 985aa4d..33ca08c 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
@@ -1374,6 +1417,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1374 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1417 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1375 if (client != null) 1418 if (client != null)
1376 client.SceneAgent.SendInitialDataToMe(); 1419 client.SceneAgent.SendInitialDataToMe();
1420
1421 // Now we know we can handle more data
1422 Thread.Sleep(200);
1423
1424 // Obtain the queue and remove it from the cache
1425 Queue<UDPPacketBuffer> queue = null;
1426
1427 lock (m_pendingCache)
1428 {
1429 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1430 {
1431 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1432 return;
1433 }
1434 m_pendingCache.Remove(endPoint);
1435 }
1436
1437 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1438
1439 // Reinject queued packets
1440 while(queue.Count > 0)
1441 {
1442 UDPPacketBuffer buf = queue.Dequeue();
1443 PacketReceived(buf);
1444 }
1445 queue = null;
1377 } 1446 }
1378 else 1447 else
1379 { 1448 {
@@ -1381,6 +1450,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1381 m_log.WarnFormat( 1450 m_log.WarnFormat(
1382 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1451 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1383 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1452 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1453 lock (m_pendingCache)
1454 m_pendingCache.Remove(endPoint);
1384 } 1455 }
1385 1456
1386 // m_log.DebugFormat( 1457 // m_log.DebugFormat(
@@ -1499,7 +1570,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1499 if (!client.SceneAgent.IsChildAgent) 1570 if (!client.SceneAgent.IsChildAgent)
1500 client.Kick("Simulator logged you out due to connection timeout"); 1571 client.Kick("Simulator logged you out due to connection timeout");
1501 1572
1502 client.CloseWithoutChecks(); 1573 client.CloseWithoutChecks(true);
1503 } 1574 }
1504 } 1575 }
1505 1576
@@ -1511,6 +1582,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1511 1582
1512 while (IsRunningInbound) 1583 while (IsRunningInbound)
1513 { 1584 {
1585 m_scene.ThreadAlive(1);
1514 try 1586 try
1515 { 1587 {
1516 IncomingPacket incomingPacket = null; 1588 IncomingPacket incomingPacket = null;
@@ -1558,6 +1630,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1558 1630
1559 while (base.IsRunningOutbound) 1631 while (base.IsRunningOutbound)
1560 { 1632 {
1633 m_scene.ThreadAlive(2);
1561 try 1634 try
1562 { 1635 {
1563 m_packetSent = false; 1636 m_packetSent = false;
@@ -1788,8 +1861,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1788 Packet packet = incomingPacket.Packet; 1861 Packet packet = incomingPacket.Packet;
1789 LLClientView client = incomingPacket.Client; 1862 LLClientView client = incomingPacket.Client;
1790 1863
1791 if (client.IsActive) 1864// if (client.IsActive)
1792 { 1865// {
1793 m_currentIncomingClient = client; 1866 m_currentIncomingClient = client;
1794 1867
1795 try 1868 try
@@ -1816,13 +1889,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1816 { 1889 {
1817 m_currentIncomingClient = null; 1890 m_currentIncomingClient = null;
1818 } 1891 }
1819 } 1892// }
1820 else 1893// else
1821 { 1894// {
1822 m_log.DebugFormat( 1895// m_log.DebugFormat(
1823 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1896// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1824 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1897// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1825 } 1898// }
1826 1899
1827 IncomingPacketsProcessed++; 1900 IncomingPacketsProcessed++;
1828 } 1901 }
@@ -1834,8 +1907,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1834 if (!client.IsLoggingOut) 1907 if (!client.IsLoggingOut)
1835 { 1908 {
1836 client.IsLoggingOut = true; 1909 client.IsLoggingOut = true;
1837 client.Close(); 1910 client.Close(false, false);
1838 } 1911 }
1839 } 1912 }
1840 } 1913 }
1841} \ No newline at end of file 1914}
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,