aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs897
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs4
-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.cs414
-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.cs192
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs10
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1506
-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, 3569 insertions, 1151 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 5c6bc1c..98ab433 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>(
@@ -212,6 +287,10 @@ namespace OpenSim.Region.ClientStack.Linden
212 = new RestStreamHandler( 287 = new RestStreamHandler(
213 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); 288 "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
214 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 289 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
290 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
291 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
292 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
293 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
215 294
216 IRequestHandler UpdateAgentInformationHandler 295 IRequestHandler UpdateAgentInformationHandler
217 = new RestStreamHandler( 296 = new RestStreamHandler(
@@ -270,6 +349,9 @@ namespace OpenSim.Region.ClientStack.Linden
270 m_log.DebugFormat( 349 m_log.DebugFormat(
271 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 350 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
272 351
352 if (!m_HostCapsObj.WaitForActivation())
353 return string.Empty;
354
273 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 355 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
274 { 356 {
275 m_log.WarnFormat( 357 m_log.WarnFormat(
@@ -410,62 +492,176 @@ namespace OpenSim.Region.ClientStack.Linden
410 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 492 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
411 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 493 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
412 494
495 // start by getting the client
496 IClientAPI client = null;
497 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
498
499 // check current state so we only have one service at a time
500 lock (m_ModelCost)
501 {
502 switch (m_FileAgentInventoryState)
503 {
504 case FileAgentInventoryState.processRequest:
505 case FileAgentInventoryState.processUpload:
506 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
507 resperror.message = "Uploader busy processing previus request";
508 resperror.identifier = UUID.Zero;
509
510 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
511 errorResponse.uploader = "";
512 errorResponse.state = "error";
513 errorResponse.error = resperror;
514 return errorResponse;
515 break;
516 case FileAgentInventoryState.waitUpload:
517 // todo stop current uploader server
518 break;
519 case FileAgentInventoryState.idle:
520 default:
521 break;
522 }
523
524 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
525 }
526
527 int cost = 0;
528 int nreqtextures = 0;
529 int nreqmeshs= 0;
530 int nreqinstances = 0;
531 bool IsAtestUpload = false;
532
533 string assetName = llsdRequest.name;
534
535 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
536
413 if (llsdRequest.asset_type == "texture" || 537 if (llsdRequest.asset_type == "texture" ||
414 llsdRequest.asset_type == "animation" || 538 llsdRequest.asset_type == "animation" ||
539 llsdRequest.asset_type == "mesh" ||
415 llsdRequest.asset_type == "sound") 540 llsdRequest.asset_type == "sound")
416 { 541 {
417 ScenePresence avatar = null; 542 ScenePresence avatar = null;
418 IClientAPI client = null;
419 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 543 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
420 544
421 // check user level 545 // check user level
422 if (avatar != null) 546 if (avatar != null)
423 { 547 {
424 client = avatar.ControllingClient;
425
426 if (avatar.UserLevel < m_levelUpload) 548 if (avatar.UserLevel < m_levelUpload)
427 { 549 {
428 if (client != null) 550 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
429 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 551 resperror.message = "Insufficient permissions to upload";
552 resperror.identifier = UUID.Zero;
430 553
431 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 554 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
432 errorResponse.uploader = ""; 555 errorResponse.uploader = "";
433 errorResponse.state = "error"; 556 errorResponse.state = "error";
557 errorResponse.error = resperror;
558 lock (m_ModelCost)
559 m_FileAgentInventoryState = FileAgentInventoryState.idle;
434 return errorResponse; 560 return errorResponse;
435 } 561 }
436 } 562 }
437 563
438 // check funds 564 // check test upload and funds
439 if (client != null) 565 if (client != null)
440 { 566 {
441 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 567 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
442 568
569 int baseCost = 0;
443 if (mm != null) 570 if (mm != null)
571 baseCost = mm.UploadCharge;
572
573 string warning = String.Empty;
574
575 if (llsdRequest.asset_type == "mesh")
444 { 576 {
445 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 577 string error;
578 int modelcost;
579
580 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
581 meshcostdata, out error, ref warning))
446 { 582 {
447 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 583 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
584 resperror.message = error;
585 resperror.identifier = UUID.Zero;
448 586
449 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 587 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
450 errorResponse.uploader = ""; 588 errorResponse.uploader = "";
451 errorResponse.state = "error"; 589 errorResponse.state = "error";
590 errorResponse.error = resperror;
591
592 lock (m_ModelCost)
593 m_FileAgentInventoryState = FileAgentInventoryState.idle;
452 return errorResponse; 594 return errorResponse;
453 } 595 }
596 cost = modelcost;
597 }
598 else
599 {
600 cost = baseCost;
601 }
602
603 if (cost > 0 && mm != null)
604 {
605 // check for test upload
606
607 if (m_ForceFreeTestUpload) // all are test
608 {
609 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
610 assetName = "TEST-" + assetName;
611
612 IsAtestUpload = true;
613 }
614
615 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
616 {
617
618 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
619 }
620
621
622 if(IsAtestUpload) // let user know, still showing cost estimation
623 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";
624
625 // check funds
626 else
627 {
628 if (!mm.UploadCovered(client.AgentId, (int)cost))
629 {
630 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
631 resperror.message = "Insuficient funds";
632 resperror.identifier = UUID.Zero;
633
634 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
635 errorResponse.uploader = "";
636 errorResponse.state = "error";
637 errorResponse.error = resperror;
638 lock (m_ModelCost)
639 m_FileAgentInventoryState = FileAgentInventoryState.idle;
640 return errorResponse;
641 }
642 }
454 } 643 }
644
645 if (client != null && warning != String.Empty)
646 client.SendAgentAlertMessage(warning, true);
455 } 647 }
456 } 648 }
457 649
458 string assetName = llsdRequest.name;
459 string assetDes = llsdRequest.description; 650 string assetDes = llsdRequest.description;
460 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 651 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
461 UUID newAsset = UUID.Random(); 652 UUID newAsset = UUID.Random();
462 UUID newInvItem = UUID.Random(); 653 UUID newInvItem = UUID.Random();
463 UUID parentFolder = llsdRequest.folder_id; 654 UUID parentFolder = llsdRequest.folder_id;
464 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 655 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
656 UUID texturesFolder = UUID.Zero;
657
658 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
659 texturesFolder = llsdRequest.texture_folder_id;
465 660
466 AssetUploader uploader = 661 AssetUploader uploader =
467 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 662 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
468 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 663 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
664 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
469 665
470 m_HostCapsObj.HttpListener.AddStreamHandler( 666 m_HostCapsObj.HttpListener.AddStreamHandler(
471 new BinaryStreamHandler( 667 new BinaryStreamHandler(
@@ -483,10 +679,22 @@ namespace OpenSim.Region.ClientStack.Linden
483 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 679 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
484 uploaderPath; 680 uploaderPath;
485 681
682
486 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 683 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
487 uploadResponse.uploader = uploaderURL; 684 uploadResponse.uploader = uploaderURL;
488 uploadResponse.state = "upload"; 685 uploadResponse.state = "upload";
686 uploadResponse.upload_price = (int)cost;
687
688 if (llsdRequest.asset_type == "mesh")
689 {
690 uploadResponse.data = meshcostdata;
691 }
692
489 uploader.OnUpLoad += UploadCompleteHandler; 693 uploader.OnUpLoad += UploadCompleteHandler;
694
695 lock (m_ModelCost)
696 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
697
490 return uploadResponse; 698 return uploadResponse;
491 } 699 }
492 700
@@ -498,8 +706,14 @@ namespace OpenSim.Region.ClientStack.Linden
498 /// <param name="data"></param> 706 /// <param name="data"></param>
499 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 707 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
500 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 708 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
501 string assetType) 709 string assetType, int cost,
710 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
711 bool IsAtestUpload, ref string error)
502 { 712 {
713
714 lock (m_ModelCost)
715 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
716
503 m_log.DebugFormat( 717 m_log.DebugFormat(
504 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 718 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
505 assetID, inventoryItem, inventoryType, assetType); 719 assetID, inventoryItem, inventoryType, assetType);
@@ -507,117 +721,247 @@ namespace OpenSim.Region.ClientStack.Linden
507 sbyte assType = 0; 721 sbyte assType = 0;
508 sbyte inType = 0; 722 sbyte inType = 0;
509 723
724 IClientAPI client = null;
725
726 UUID owner_id = m_HostCapsObj.AgentID;
727 UUID creatorID;
728
729 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
730
731 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
732
733 if (istest && m_testAssetsCreatorID != UUID.Zero)
734 creatorID = m_testAssetsCreatorID;
735 else
736 creatorID = owner_id;
737
738 string creatorIDstr = creatorID.ToString();
739
740 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
741 if (mm != null)
742 {
743 // make sure client still has enougth credit
744 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
745 {
746 error = "Insufficient funds.";
747 return;
748 }
749 }
750
751 // strings to types
510 if (inventoryType == "sound") 752 if (inventoryType == "sound")
511 { 753 {
512 inType = 1; 754 inType = (sbyte)InventoryType.Sound;
513 assType = 1; 755 assType = (sbyte)AssetType.Sound;
514 } 756 }
515 else if (inventoryType == "animation") 757 else if (inventoryType == "animation")
516 { 758 {
517 inType = 19; 759 inType = (sbyte)InventoryType.Animation;
518 assType = 20; 760 assType = (sbyte)AssetType.Animation;
519 } 761 }
520 else if (inventoryType == "wearable") 762 else if (inventoryType == "wearable")
521 { 763 {
522 inType = 18; 764 inType = (sbyte)InventoryType.Wearable;
523 switch (assetType) 765 switch (assetType)
524 { 766 {
525 case "bodypart": 767 case "bodypart":
526 assType = 13; 768 assType = (sbyte)AssetType.Bodypart;
527 break; 769 break;
528 case "clothing": 770 case "clothing":
529 assType = 5; 771 assType = (sbyte)AssetType.Clothing;
530 break; 772 break;
531 } 773 }
532 } 774 }
533 else if (inventoryType == "object") 775 else if (inventoryType == "object")
534 { 776 {
535 inType = (sbyte)InventoryType.Object; 777 if (assetType == "mesh") // this code for now is for mesh models uploads only
536 assType = (sbyte)AssetType.Object;
537
538 List<Vector3> positions = new List<Vector3>();
539 List<Quaternion> rotations = new List<Quaternion>();
540 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
541 OSDArray instance_list = (OSDArray)request["instance_list"];
542 OSDArray mesh_list = (OSDArray)request["mesh_list"];
543 OSDArray texture_list = (OSDArray)request["texture_list"];
544 SceneObjectGroup grp = null;
545
546 List<UUID> textures = new List<UUID>();
547 for (int i = 0; i < texture_list.Count; i++)
548 { 778 {
549 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 779 inType = (sbyte)InventoryType.Object;
550 textureAsset.Data = texture_list[i].AsBinary(); 780 assType = (sbyte)AssetType.Object;
551 m_assetService.Store(textureAsset);
552 textures.Add(textureAsset.FullID);
553 }
554 781
555 for (int i = 0; i < mesh_list.Count; i++) 782 List<Vector3> positions = new List<Vector3>();
556 { 783 List<Quaternion> rotations = new List<Quaternion>();
557 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 784 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
558 785
559 Primitive.TextureEntry textureEntry 786 // compare and get updated information
560 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
561 OSDMap inner_instance_list = (OSDMap)instance_list[i];
562 787
563 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 788 bool mismatchError = true;
564 for (uint face = 0; face < face_list.Count; face++) 789
790 while (mismatchError)
565 { 791 {
566 OSDMap faceMap = (OSDMap)face_list[(int)face]; 792 mismatchError = false;
567 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 793 }
568 if(faceMap.ContainsKey("fullbright"))
569 f.Fullbright = faceMap["fullbright"].AsBoolean();
570 if (faceMap.ContainsKey ("diffuse_color"))
571 f.RGBA = faceMap["diffuse_color"].AsColor4();
572 794
573 int textureNum = faceMap["image"].AsInteger(); 795 if (mismatchError)
574 float imagerot = faceMap["imagerot"].AsInteger(); 796 {
575 float offsets = (float)faceMap["offsets"].AsReal(); 797 error = "Upload and fee estimation information don't match";
576 float offsett = (float)faceMap["offsett"].AsReal(); 798 lock (m_ModelCost)
577 float scales = (float)faceMap["scales"].AsReal(); 799 m_FileAgentInventoryState = FileAgentInventoryState.idle;
578 float scalet = (float)faceMap["scalet"].AsReal();
579 800
580 if(imagerot != 0) 801 return;
581 f.Rotation = imagerot; 802 }
582 803
583 if(offsets != 0) 804 OSDArray instance_list = (OSDArray)request["instance_list"];
584 f.OffsetU = offsets; 805 OSDArray mesh_list = (OSDArray)request["mesh_list"];
806 OSDArray texture_list = (OSDArray)request["texture_list"];
807 SceneObjectGroup grp = null;
585 808
586 if (offsett != 0) 809 // create and store texture assets
587 f.OffsetV = offsett; 810 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
811 texturesFolder != UUID.Zero);
588 812
589 if (scales != 0)
590 f.RepeatU = scales;
591 813
592 if (scalet != 0) 814 List<UUID> textures = new List<UUID>();
593 f.RepeatV = scalet;
594 815
595 if (textures.Count > textureNum) 816
596 f.TextureID = textures[textureNum]; 817 if (doTextInv)
597 else 818 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
598 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
599 819
600 textureEntry.FaceTextures[face] = f; 820 if(client == null) // don't put textures in inventory if there is no client
821 doTextInv = false;
822
823 for (int i = 0; i < texture_list.Count; i++)
824 {
825 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
826 textureAsset.Data = texture_list[i].AsBinary();
827 if (istest)
828 textureAsset.Local = true;
829 m_assetService.Store(textureAsset);
830 textures.Add(textureAsset.FullID);
831
832 if (doTextInv)
833 {
834 string name = assetName;
835 if (name.Length > 25)
836 name = name.Substring(0, 24);
837 name += "_Texture#" + i.ToString();
838 InventoryItemBase texitem = new InventoryItemBase();
839 texitem.Owner = m_HostCapsObj.AgentID;
840 texitem.CreatorId = creatorIDstr;
841 texitem.CreatorData = String.Empty;
842 texitem.ID = UUID.Random();
843 texitem.AssetID = textureAsset.FullID;
844 texitem.Description = "mesh model texture";
845 texitem.Name = name;
846 texitem.AssetType = (int)AssetType.Texture;
847 texitem.InvType = (int)InventoryType.Texture;
848 texitem.Folder = texturesFolder;
849
850 texitem.CurrentPermissions
851 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
852
853 texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
854 texitem.EveryOnePermissions = 0;
855 texitem.NextPermissions = (uint)PermissionMask.All;
856 texitem.CreationDate = Util.UnixTimeSinceEpoch();
857
858 m_Scene.AddInventoryItem(client, texitem);
859 texitem = null;
860 }
601 } 861 }
602 862
603 pbs.TextureEntry = textureEntry.GetBytes(); 863 // create and store meshs assets
864 List<UUID> meshAssets = new List<UUID>();
865 for (int i = 0; i < mesh_list.Count; i++)
866 {
867 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
868 meshAsset.Data = mesh_list[i].AsBinary();
869 if (istest)
870 meshAsset.Local = true;
871 m_assetService.Store(meshAsset);
872 meshAssets.Add(meshAsset.FullID);
873 }
874
875 int skipedMeshs = 0;
876 // build prims from instances
877 for (int i = 0; i < instance_list.Count; i++)
878 {
879 OSDMap inner_instance_list = (OSDMap)instance_list[i];
880
881 // skip prims that are 2 small
882 Vector3 scale = inner_instance_list["scale"].AsVector3();
883
884 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
885 {
886 skipedMeshs++;
887 continue;
888 }
889
890 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
891
892 Primitive.TextureEntry textureEntry
893 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
894
604 895
605 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 896 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
606 meshAsset.Data = mesh_list[i].AsBinary(); 897 for (uint face = 0; face < face_list.Count; face++)
607 m_assetService.Store(meshAsset); 898 {
899 OSDMap faceMap = (OSDMap)face_list[(int)face];
900 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
901 if (faceMap.ContainsKey("fullbright"))
902 f.Fullbright = faceMap["fullbright"].AsBoolean();
903 if (faceMap.ContainsKey("diffuse_color"))
904 f.RGBA = faceMap["diffuse_color"].AsColor4();
905
906 int textureNum = faceMap["image"].AsInteger();
907 float imagerot = faceMap["imagerot"].AsInteger();
908 float offsets = (float)faceMap["offsets"].AsReal();
909 float offsett = (float)faceMap["offsett"].AsReal();
910 float scales = (float)faceMap["scales"].AsReal();
911 float scalet = (float)faceMap["scalet"].AsReal();
912
913 if (imagerot != 0)
914 f.Rotation = imagerot;
915
916 if (offsets != 0)
917 f.OffsetU = offsets;
608 918
609 pbs.SculptEntry = true; 919 if (offsett != 0)
610 pbs.SculptTexture = meshAsset.FullID; 920 f.OffsetV = offsett;
611 pbs.SculptType = (byte)SculptType.Mesh;
612 pbs.SculptData = meshAsset.Data;
613 921
614 Vector3 position = inner_instance_list["position"].AsVector3(); 922 if (scales != 0)
615 Vector3 scale = inner_instance_list["scale"].AsVector3(); 923 f.RepeatU = scales;
616 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 924
925 if (scalet != 0)
926 f.RepeatV = scalet;
927
928 if (textures.Count > textureNum)
929 f.TextureID = textures[textureNum];
930 else
931 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
932
933 textureEntry.FaceTextures[face] = f;
934 }
935
936 pbs.TextureEntry = textureEntry.GetBytes();
937
938 bool hasmesh = false;
939 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
940 {
941 int meshindx = inner_instance_list["mesh"].AsInteger();
942 if (meshAssets.Count > meshindx)
943 {
944 pbs.SculptEntry = true;
945 pbs.SculptType = (byte)SculptType.Mesh;
946 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
947 // data will be requested from asset on rez (i hope)
948 hasmesh = true;
949 }
950 }
951
952 Vector3 position = inner_instance_list["position"].AsVector3();
953 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
954
955 // for now viwers do send fixed defaults
956 // but this may change
957// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
958 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
959 if(hasmesh)
960 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
961// int material = inner_instance_list["material"].AsInteger();
962 byte material = (byte)Material.Wood;
617 963
618// no longer used - begin ------------------------ 964// no longer used - begin ------------------------
619// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
620// int material = inner_instance_list["material"].AsInteger();
621// int mesh = inner_instance_list["mesh"].AsInteger(); 965// int mesh = inner_instance_list["mesh"].AsInteger();
622 966
623// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 967// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -632,24 +976,49 @@ namespace OpenSim.Region.ClientStack.Linden
632// UUID owner_id = permissions["owner_id"].AsUUID(); 976// UUID owner_id = permissions["owner_id"].AsUUID();
633// int owner_mask = permissions["owner_mask"].AsInteger(); 977// int owner_mask = permissions["owner_mask"].AsInteger();
634// no longer used - end ------------------------ 978// no longer used - end ------------------------
979
980
981 SceneObjectPart prim
982 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
983
984 prim.Scale = scale;
985 rotations.Add(rotation);
986 positions.Add(position);
987 prim.UUID = UUID.Random();
988 prim.CreatorID = creatorID;
989 prim.OwnerID = owner_id;
990 prim.GroupID = UUID.Zero;
991 prim.LastOwnerID = creatorID;
992 prim.CreationDate = Util.UnixTimeSinceEpoch();
993
994 if (grp == null)
995 prim.Name = assetName;
996 else
997 prim.Name = assetName + "#" + i.ToString();
635 998
636 UUID owner_id = m_HostCapsObj.AgentID; 999 prim.EveryoneMask = 0;
1000 prim.GroupMask = 0;
637 1001
638 SceneObjectPart prim 1002 if (restrictPerms)
639 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 1003 {
1004 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1005 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
1006 prim.NextOwnerMask = 0;
1007 }
1008 else
1009 {
1010 prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1011 prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1012 prim.NextOwnerMask = (uint)PermissionMask.Transfer;
1013 }
1014
1015 if(istest)
1016 prim.Description = "For testing only. Other uses are prohibited";
1017 else
1018 prim.Description = "";
640 1019
641 prim.Scale = scale; 1020 prim.Material = material;
642 //prim.OffsetPosition = position; 1021 prim.PhysicsShapeType = physicsShapeType;
643 rotations.Add(rotation);
644 positions.Add(position);
645 prim.UUID = UUID.Random();
646 prim.CreatorID = owner_id;
647 prim.OwnerID = owner_id;
648 prim.GroupID = UUID.Zero;
649 prim.LastOwnerID = prim.OwnerID;
650 prim.CreationDate = Util.UnixTimeSinceEpoch();
651 prim.Name = assetName;
652 prim.Description = "";
653 1022
654// prim.BaseMask = (uint)base_mask; 1023// prim.BaseMask = (uint)base_mask;
655// prim.EveryoneMask = (uint)everyone_mask; 1024// prim.EveryoneMask = (uint)everyone_mask;
@@ -657,52 +1026,64 @@ namespace OpenSim.Region.ClientStack.Linden
657// prim.NextOwnerMask = (uint)next_owner_mask; 1026// prim.NextOwnerMask = (uint)next_owner_mask;
658// prim.OwnerMask = (uint)owner_mask; 1027// prim.OwnerMask = (uint)owner_mask;
659 1028
660 if (grp == null) 1029 if (grp == null)
661 grp = new SceneObjectGroup(prim); 1030 {
662 else 1031 grp = new SceneObjectGroup(prim);
663 grp.AddPart(prim); 1032 grp.LastOwnerID = creatorID;
664 } 1033 }
1034 else
1035 grp.AddPart(prim);
1036 }
665 1037
666 Vector3 rootPos = positions[0]; 1038 Vector3 rootPos = positions[0];
667 1039
668 if (grp.Parts.Length > 1) 1040 if (grp.Parts.Length > 1)
669 { 1041 {
670 // Fix first link number 1042 // Fix first link number
671 grp.RootPart.LinkNum++; 1043 grp.RootPart.LinkNum++;
672 1044
673 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1045 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
674 Quaternion tmprot; 1046 Quaternion tmprot;
675 Vector3 offset; 1047 Vector3 offset;
676 1048
677 // fix children rotations and positions 1049 // fix children rotations and positions
678 for (int i = 1; i < rotations.Count; i++) 1050 for (int i = 1; i < rotations.Count; i++)
679 { 1051 {
680 tmprot = rotations[i]; 1052 tmprot = rotations[i];
681 tmprot = rootRotConj * tmprot; 1053 tmprot = rootRotConj * tmprot;
1054
1055 grp.Parts[i].RotationOffset = tmprot;
682 1056
683 grp.Parts[i].RotationOffset = tmprot; 1057 offset = positions[i] - rootPos;
684 1058
685 offset = positions[i] - rootPos; 1059 offset *= rootRotConj;
1060 grp.Parts[i].OffsetPosition = offset;
1061 }
686 1062
687 offset *= rootRotConj; 1063 grp.AbsolutePosition = rootPos;
688 grp.Parts[i].OffsetPosition = offset; 1064 grp.UpdateGroupRotationR(rotations[0]);
1065 }
1066 else
1067 {
1068 grp.AbsolutePosition = rootPos;
1069 grp.UpdateGroupRotationR(rotations[0]);
689 } 1070 }
690 1071
691 grp.AbsolutePosition = rootPos; 1072 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
692 grp.UpdateGroupRotationR(rotations[0]);
693 } 1073 }
694 else 1074
1075 else // not a mesh model
695 { 1076 {
696 grp.AbsolutePosition = rootPos; 1077 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
697 grp.UpdateGroupRotationR(rotations[0]); 1078 return;
698 } 1079 }
699
700 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
701 } 1080 }
702 1081
703 AssetBase asset; 1082 AssetBase asset;
704 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1083 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
705 asset.Data = data; 1084 asset.Data = data;
1085 if (istest)
1086 asset.Local = true;
706 if (AddNewAsset != null) 1087 if (AddNewAsset != null)
707 AddNewAsset(asset); 1088 AddNewAsset(asset);
708 else if (m_assetService != null) 1089 else if (m_assetService != null)
@@ -710,11 +1091,17 @@ namespace OpenSim.Region.ClientStack.Linden
710 1091
711 InventoryItemBase item = new InventoryItemBase(); 1092 InventoryItemBase item = new InventoryItemBase();
712 item.Owner = m_HostCapsObj.AgentID; 1093 item.Owner = m_HostCapsObj.AgentID;
713 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1094 item.CreatorId = creatorIDstr;
714 item.CreatorData = String.Empty; 1095 item.CreatorData = String.Empty;
715 item.ID = inventoryItem; 1096 item.ID = inventoryItem;
716 item.AssetID = asset.FullID; 1097 item.AssetID = asset.FullID;
717 item.Description = assetDescription; 1098 if (istest)
1099 {
1100 item.Description = "For testing only. Other uses are prohibited";
1101 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1102 }
1103 else
1104 item.Description = assetDescription;
718 item.Name = assetName; 1105 item.Name = assetName;
719 item.AssetType = assType; 1106 item.AssetType = assType;
720 item.InvType = inType; 1107 item.InvType = inType;
@@ -722,18 +1109,56 @@ namespace OpenSim.Region.ClientStack.Linden
722 1109
723 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1110 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
724 // (owner) permissions. This becomes a problem if next permissions are changed. 1111 // (owner) permissions. This becomes a problem if next permissions are changed.
725 item.CurrentPermissions
726 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export);
727 1112
728 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; 1113 if (restrictPerms)
729 item.EveryOnePermissions = 0; 1114 {
730 item.NextPermissions = (uint)PermissionMask.All; 1115 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1116 item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1117 item.EveryOnePermissions = 0;
1118 item.NextPermissions = 0;
1119 }
1120 else
1121 {
1122 item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1123 item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export;
1124 item.EveryOnePermissions = 0;
1125 item.NextPermissions = (uint)PermissionMask.Transfer;
1126 }
1127
731 item.CreationDate = Util.UnixTimeSinceEpoch(); 1128 item.CreationDate = Util.UnixTimeSinceEpoch();
732 1129
1130 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1131
733 if (AddNewInventoryItem != null) 1132 if (AddNewInventoryItem != null)
734 { 1133 {
735 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1134 if (istest)
1135 {
1136 m_Scene.AddInventoryItem(client, item);
1137/*
1138 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1139 if (client != null)
1140 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);
1141 */
1142 }
1143 else
1144 {
1145 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1146// if (client != null)
1147// {
1148// // let users see anything.. i don't so far
1149// string str;
1150// if (cost > 0)
1151// // dont remember where is money unit name to put here
1152// str = "Upload complete. charged " + cost.ToString() + "$";
1153// else
1154// str = "Upload complete";
1155// client.SendAgentAlertMessage(str, true);
1156// }
1157 }
736 } 1158 }
1159
1160 lock (m_ModelCost)
1161 m_FileAgentInventoryState = FileAgentInventoryState.idle;
737 } 1162 }
738 1163
739 /// <summary> 1164 /// <summary>
@@ -926,6 +1351,120 @@ namespace OpenSim.Region.ClientStack.Linden
926 return response; 1351 return response;
927 } 1352 }
928 1353
1354 public string GetObjectCost(string request, string path,
1355 string param, IOSHttpRequest httpRequest,
1356 IOSHttpResponse httpResponse)
1357 {
1358 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1359 OSDMap resp = new OSDMap();
1360
1361 OSDArray object_ids = (OSDArray)req["object_ids"];
1362
1363 for (int i = 0; i < object_ids.Count; i++)
1364 {
1365 UUID uuid = object_ids[i].AsUUID();
1366
1367 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1368
1369 if (part != null)
1370 {
1371 SceneObjectGroup grp = part.ParentGroup;
1372 if (grp != null)
1373 {
1374 float linksetCost;
1375 float linksetPhysCost;
1376 float partCost;
1377 float partPhysCost;
1378
1379 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1380
1381 OSDMap object_data = new OSDMap();
1382 object_data["linked_set_resource_cost"] = linksetCost;
1383 object_data["resource_cost"] = partCost;
1384 object_data["physics_cost"] = partPhysCost;
1385 object_data["linked_set_physics_cost"] = linksetPhysCost;
1386
1387 resp[uuid.ToString()] = object_data;
1388 }
1389 }
1390 }
1391
1392 string response = OSDParser.SerializeLLSDXmlString(resp);
1393 return response;
1394 }
1395
1396 public string ResourceCostSelected(string request, string path,
1397 string param, IOSHttpRequest httpRequest,
1398 IOSHttpResponse httpResponse)
1399 {
1400 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1401 OSDMap resp = new OSDMap();
1402
1403
1404 float phys=0;
1405 float stream=0;
1406 float simul=0;
1407
1408 if (req.ContainsKey("selected_roots"))
1409 {
1410 OSDArray object_ids = (OSDArray)req["selected_roots"];
1411
1412 // should go by SOG suming costs for all parts
1413 // ll v3 works ok with several objects select we get the list and adds ok
1414 // FS calls per object so results are wrong guess fs bug
1415 for (int i = 0; i < object_ids.Count; i++)
1416 {
1417 UUID uuid = object_ids[i].AsUUID();
1418 float Physc;
1419 float simulc;
1420 float streamc;
1421
1422 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1423 if (grp != null)
1424 {
1425 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1426 phys += Physc;
1427 stream += streamc;
1428 simul += simulc;
1429 }
1430 }
1431 }
1432 else if (req.ContainsKey("selected_prims"))
1433 {
1434 OSDArray object_ids = (OSDArray)req["selected_prims"];
1435
1436 // don't see in use in any of the 2 viewers
1437 // guess it should be for edit linked but... nothing
1438 // should go to SOP per part
1439 for (int i = 0; i < object_ids.Count; i++)
1440 {
1441 UUID uuid = object_ids[i].AsUUID();
1442
1443 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1444 if (part != null)
1445 {
1446 phys += part.PhysicsCost;
1447 stream += part.StreamingCost;
1448 simul += part.SimulationCost;
1449 }
1450 }
1451 }
1452
1453 if (simul != 0)
1454 {
1455 OSDMap object_data = new OSDMap();
1456
1457 object_data["physics"] = phys;
1458 object_data["streaming"] = stream;
1459 object_data["simulation"] = simul;
1460
1461 resp["selected"] = object_data;
1462 }
1463
1464 string response = OSDParser.SerializeLLSDXmlString(resp);
1465 return response;
1466 }
1467
929 public string UpdateAgentInformation(string request, string path, 1468 public string UpdateAgentInformation(string request, string path,
930 string param, IOSHttpRequest httpRequest, 1469 string param, IOSHttpRequest httpRequest,
931 IOSHttpResponse httpResponse) 1470 IOSHttpResponse httpResponse)
@@ -945,6 +1484,10 @@ namespace OpenSim.Region.ClientStack.Linden
945 1484
946 public class AssetUploader 1485 public class AssetUploader
947 { 1486 {
1487 private static readonly ILog m_log =
1488 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1489
1490
948 public event UpLoadedAsset OnUpLoad; 1491 public event UpLoadedAsset OnUpLoad;
949 private UpLoadedAsset handlerUpLoad = null; 1492 private UpLoadedAsset handlerUpLoad = null;
950 1493
@@ -959,10 +1502,21 @@ namespace OpenSim.Region.ClientStack.Linden
959 1502
960 private string m_invType = String.Empty; 1503 private string m_invType = String.Empty;
961 private string m_assetType = String.Empty; 1504 private string m_assetType = String.Empty;
1505 private int m_cost;
1506 private string m_error = String.Empty;
1507
1508 private Timer m_timeoutTimer = new Timer();
1509 private UUID m_texturesFolder;
1510 private int m_nreqtextures;
1511 private int m_nreqmeshs;
1512 private int m_nreqinstances;
1513 private bool m_IsAtestUpload;
962 1514
963 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1515 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
964 UUID parentFolderID, string invType, string assetType, string path, 1516 UUID parentFolderID, string invType, string assetType, string path,
965 IHttpServer httpServer, bool dumpAssetsToFile) 1517 IHttpServer httpServer, bool dumpAssetsToFile,
1518 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1519 bool IsAtestUpload)
966 { 1520 {
967 m_assetName = assetName; 1521 m_assetName = assetName;
968 m_assetDes = description; 1522 m_assetDes = description;
@@ -974,6 +1528,18 @@ namespace OpenSim.Region.ClientStack.Linden
974 m_assetType = assetType; 1528 m_assetType = assetType;
975 m_invType = invType; 1529 m_invType = invType;
976 m_dumpAssetsToFile = dumpAssetsToFile; 1530 m_dumpAssetsToFile = dumpAssetsToFile;
1531 m_cost = totalCost;
1532
1533 m_texturesFolder = texturesFolder;
1534 m_nreqtextures = nreqtextures;
1535 m_nreqmeshs = nreqmeshs;
1536 m_nreqinstances = nreqinstances;
1537 m_IsAtestUpload = IsAtestUpload;
1538
1539 m_timeoutTimer.Elapsed += TimedOut;
1540 m_timeoutTimer.Interval = 120000;
1541 m_timeoutTimer.AutoReset = false;
1542 m_timeoutTimer.Start();
977 } 1543 }
978 1544
979 /// <summary> 1545 /// <summary>
@@ -988,12 +1554,14 @@ namespace OpenSim.Region.ClientStack.Linden
988 UUID inv = inventoryItemID; 1554 UUID inv = inventoryItemID;
989 string res = String.Empty; 1555 string res = String.Empty;
990 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1556 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1557/*
991 uploadComplete.new_asset = newAssetID.ToString(); 1558 uploadComplete.new_asset = newAssetID.ToString();
992 uploadComplete.new_inventory_item = inv; 1559 uploadComplete.new_inventory_item = inv;
993 uploadComplete.state = "complete"; 1560 uploadComplete.state = "complete";
994 1561
995 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1562 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
996 1563*/
1564 m_timeoutTimer.Stop();
997 httpListener.RemoveStreamHandler("POST", uploaderPath); 1565 httpListener.RemoveStreamHandler("POST", uploaderPath);
998 1566
999 // TODO: probably make this a better set of extensions here 1567 // TODO: probably make this a better set of extensions here
@@ -1010,12 +1578,49 @@ namespace OpenSim.Region.ClientStack.Linden
1010 handlerUpLoad = OnUpLoad; 1578 handlerUpLoad = OnUpLoad;
1011 if (handlerUpLoad != null) 1579 if (handlerUpLoad != null)
1012 { 1580 {
1013 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1581 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1582 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1583 }
1584 if (m_IsAtestUpload)
1585 {
1586 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1587 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1588 resperror.identifier = inv;
1589
1590 uploadComplete.error = resperror;
1591 uploadComplete.state = "Upload4Testing";
1014 } 1592 }
1593 else
1594 {
1595 if (m_error == String.Empty)
1596 {
1597 uploadComplete.new_asset = newAssetID.ToString();
1598 uploadComplete.new_inventory_item = inv;
1599 // if (m_texturesFolder != UUID.Zero)
1600 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1601 uploadComplete.state = "complete";
1602 }
1603 else
1604 {
1605 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1606 resperror.message = m_error;
1607 resperror.identifier = inv;
1015 1608
1609 uploadComplete.error = resperror;
1610 uploadComplete.state = "failed";
1611 }
1612 }
1613
1614 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1016 return res; 1615 return res;
1017 } 1616 }
1018 1617
1618 private void TimedOut(object sender, ElapsedEventArgs args)
1619 {
1620 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1621 httpListener.RemoveStreamHandler("POST", uploaderPath);
1622 }
1623
1019 ///Left this in and commented in case there are unforseen issues 1624 ///Left this in and commented in case there are unforseen issues
1020 //private void SaveAssetToFile(string filename, byte[] data) 1625 //private void SaveAssetToFile(string filename, byte[] data)
1021 //{ 1626 //{
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 50bfda1..d6689d4 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -491,8 +491,8 @@ namespace OpenSim.Region.ClientStack.Linden
491 responsedata["content_type"] = "text/plain"; 491 responsedata["content_type"] = "text/plain";
492 responsedata["keepalive"] = false; 492 responsedata["keepalive"] = false;
493 responsedata["reusecontext"] = false; 493 responsedata["reusecontext"] = false;
494 responsedata["str_response_string"] = "Upstream error: "; 494 responsedata["str_response_string"] = "<llsd></llsd>";
495 responsedata["error_status_text"] = "Upstream error:"; 495 responsedata["error_status_text"] = "<llsd></llsd>";
496 responsedata["http_protocol_version"] = "HTTP/1.0"; 496 responsedata["http_protocol_version"] = "HTTP/1.0";
497 return responsedata; 497 return responsedata;
498 } 498 }
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..a42c96c 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,132 @@ namespace OpenSim.Region.ClientStack.Linden
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 51 public class GetTextureModule : INonSharedRegionModule
56 { 52 {
57// private static readonly ILog m_log = 53
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 struct aPollRequest
59 55 {
56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID;
58 public Hashtable request;
59 public bool send503;
60 }
61
62 public class aPollResponse
63 {
64 public Hashtable response;
65 public int bytes;
66 }
67
68
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
60 private Scene m_scene; 71 private Scene m_scene;
61 private IAssetService m_assetService;
62 72
63 private bool m_Enabled = false; 73 private static GetTextureHandler m_getTextureHandler;
64 74
65 // TODO: Change this to a config option 75 private IAssetService m_assetService = null;
66 const string REDIRECT_URL = null;
67 76
68 private string m_URL; 77 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
78 private static Thread[] m_workerThreads = null;
79
80 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
81 new OpenMetaverse.BlockingQueue<aPollRequest>();
82
83 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
69 84
70 #region ISharedRegionModule Members 85 #region ISharedRegionModule Members
71 86
72 public void Initialise(IConfigSource source) 87 public void Initialise(IConfigSource source)
73 { 88 {
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 } 89 }
83 90
84 public void AddRegion(Scene s) 91 public void AddRegion(Scene s)
85 { 92 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 93 m_scene = s;
94 m_assetService = s.AssetService;
90 } 95 }
91 96
92 public void RemoveRegion(Scene s) 97 public void RemoveRegion(Scene s)
93 { 98 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 99 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
100 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
101 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 102 m_scene = null;
99 } 103 }
100 104
101 public void RegionLoaded(Scene s) 105 public void RegionLoaded(Scene s)
102 { 106 {
103 if (!m_Enabled) 107 // We'll reuse the same handler for all requests.
104 return; 108 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 109
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 110 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
111 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
112 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
113
114 if (m_workerThreads == null)
115 {
116 m_workerThreads = new Thread[2];
117
118 for (uint i = 0; i < 2; i++)
119 {
120 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
121 String.Format("TextureWorkerThread{0}", i),
122 ThreadPriority.Normal,
123 false,
124 false,
125 null,
126 int.MaxValue);
127 }
128 }
129 }
130 private int ExtractImageThrottle(byte[] pthrottles)
131 {
132
133 byte[] adjData;
134 int pos = 0;
135
136 if (!BitConverter.IsLittleEndian)
137 {
138 byte[] newData = new byte[7 * 4];
139 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
140
141 for (int i = 0; i < 7; i++)
142 Array.Reverse(newData, i * 4, 4);
143
144 adjData = newData;
145 }
146 else
147 {
148 adjData = pthrottles;
149 }
150
151 // 0.125f converts from bits to bytes
152 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
153 //pos += 4;
154 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
155 //pos += 4;
156 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
157 // pos += 4;
158 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
159 // pos += 4;
160 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
161 // pos += 4;
162 pos = pos + 20;
163 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
164 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
165 return texture;
166 }
167
168 // 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.
169 public void ThrottleUpdate(ScenePresence p)
170 {
171 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
172 UUID user = p.UUID;
173 int imagethrottle = ExtractImageThrottle(throttles);
174 PollServiceTextureEventArgs args;
175 if (m_pollservices.TryGetValue(user,out args))
176 {
177 args.UpdateThrottle(imagethrottle);
178 }
108 } 179 }
109 180
110 public void PostInitialise() 181 public void PostInitialise()
@@ -122,24 +193,281 @@ namespace OpenSim.Region.ClientStack.Linden
122 193
123 #endregion 194 #endregion
124 195
125 public void RegisterCaps(UUID agentID, Caps caps) 196 ~GetTextureModule()
126 { 197 {
127 UUID capID = UUID.Random(); 198 foreach (Thread t in m_workerThreads)
199 Watchdog.AbortThread(t.ManagedThreadId);
128 200
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 201 }
130 if (m_URL == "localhost") 202
203 private class PollServiceTextureEventArgs : PollServiceEventArgs
204 {
205 private List<Hashtable> requests =
206 new List<Hashtable>();
207 private Dictionary<UUID, aPollResponse> responses =
208 new Dictionary<UUID, aPollResponse>();
209
210 private Scene m_scene;
211 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
212 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
213 base(null, null, null, null, pId, int.MaxValue)
131 { 214 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 215 m_scene = scene;
133 caps.RegisterHandler( 216 // x is request id, y is userid
134 "GetTexture", 217 HasEvents = (x, y) =>
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 218 {
219 lock (responses)
220 {
221 bool ret = m_throttler.hasEvents(x, responses);
222 m_throttler.ProcessTime();
223 return ret;
224
225 }
226 };
227 GetEvents = (x, y) =>
228 {
229 lock (responses)
230 {
231 try
232 {
233 return responses[x].response;
234 }
235 finally
236 {
237 responses.Remove(x);
238 }
239 }
240 };
241 // x is request id, y is request data hashtable
242 Request = (x, y) =>
243 {
244 aPollRequest reqinfo = new aPollRequest();
245 reqinfo.thepoll = this;
246 reqinfo.reqID = x;
247 reqinfo.request = y;
248 reqinfo.send503 = false;
249
250 lock (responses)
251 {
252 if (responses.Count > 0)
253 {
254 if (m_queue.Count >= 4)
255 {
256 // Never allow more than 4 fetches to wait
257 reqinfo.send503 = true;
258 }
259 }
260 }
261 m_queue.Enqueue(reqinfo);
262 };
263
264 // this should never happen except possible on shutdown
265 NoEvents = (x, y) =>
266 {
267/*
268 lock (requests)
269 {
270 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
271 requests.Remove(request);
272 }
273*/
274 Hashtable response = new Hashtable();
275
276 response["int_response_code"] = 500;
277 response["str_response_string"] = "Script timeout";
278 response["content_type"] = "text/plain";
279 response["keepalive"] = false;
280 response["reusecontext"] = false;
281
282 return response;
283 };
136 } 284 }
137 else 285
286 public void Process(aPollRequest requestinfo)
138 { 287 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 288 Hashtable response;
140 caps.RegisterHandler("GetTexture", m_URL); 289
290 UUID requestID = requestinfo.reqID;
291
292 if (requestinfo.send503)
293 {
294 response = new Hashtable();
295
296 response["int_response_code"] = 503;
297 response["str_response_string"] = "Throttled";
298 response["content_type"] = "text/plain";
299 response["keepalive"] = false;
300 response["reusecontext"] = false;
301
302 lock (responses)
303 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
304
305 return;
306 }
307
308 // If the avatar is gone, don't bother to get the texture
309 if (m_scene.GetScenePresence(Id) == null)
310 {
311 response = new Hashtable();
312
313 response["int_response_code"] = 500;
314 response["str_response_string"] = "Script timeout";
315 response["content_type"] = "text/plain";
316 response["keepalive"] = false;
317 response["reusecontext"] = false;
318
319 lock (responses)
320 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
321
322 return;
323 }
324
325 response = m_getTextureHandler.Handle(requestinfo.request);
326 lock (responses)
327 {
328 responses[requestID] = new aPollResponse()
329 {
330 bytes = (int) response["int_bytes"],
331 response = response
332 };
333
334 }
335 m_throttler.ProcessTime();
336 }
337
338 internal void UpdateThrottle(int pimagethrottle)
339 {
340 m_throttler.ThrottleBytes = pimagethrottle;
141 } 341 }
142 } 342 }
143 343
344 private void RegisterCaps(UUID agentID, Caps caps)
345 {
346 string capUrl = "/CAPS/" + UUID.Random() + "/";
347
348 // Register this as a poll service
349 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
350
351 args.Type = PollServiceEventArgs.EventType.Texture;
352 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
353
354 string hostName = m_scene.RegionInfo.ExternalHostName;
355 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
356 string protocol = "http";
357
358 if (MainServer.Instance.UseSSL)
359 {
360 hostName = MainServer.Instance.SSLCommonName;
361 port = MainServer.Instance.SSLPort;
362 protocol = "https";
363 }
364 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
365 m_pollservices[agentID] = args;
366 m_capsDict[agentID] = capUrl;
367 }
368
369 private void DeregisterCaps(UUID agentID, Caps caps)
370 {
371 string capUrl;
372 PollServiceTextureEventArgs args;
373 if (m_capsDict.TryGetValue(agentID, out capUrl))
374 {
375 MainServer.Instance.RemoveHTTPHandler("", capUrl);
376 m_capsDict.Remove(agentID);
377 }
378 if (m_pollservices.TryGetValue(agentID, out args))
379 {
380 m_pollservices.Remove(agentID);
381 }
382 }
383
384 private void DoTextureRequests()
385 {
386 while (true)
387 {
388 aPollRequest poolreq = m_queue.Dequeue();
389
390 poolreq.thepoll.Process(poolreq);
391 }
392 }
393 internal sealed class CapsDataThrottler
394 {
395
396 private volatile int currenttime = 0;
397 private volatile int lastTimeElapsed = 0;
398 private volatile int BytesSent = 0;
399 private int oversizedImages = 0;
400 public CapsDataThrottler(int pBytes, int max, int min)
401 {
402 ThrottleBytes = pBytes;
403 lastTimeElapsed = Util.EnvironmentTickCount();
404 }
405 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
406 {
407 PassTime();
408 // Note, this is called IN LOCK
409 bool haskey = responses.ContainsKey(key);
410 if (!haskey)
411 {
412 return false;
413 }
414 GetTextureModule.aPollResponse response;
415 if (responses.TryGetValue(key, out response))
416 {
417 // This is any error response
418 if (response.bytes == 0)
419 return true;
420
421 // Normal
422 if (BytesSent + response.bytes <= ThrottleBytes)
423 {
424 BytesSent += response.bytes;
425 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
426 //m_actions.Add(timeBasedAction);
427 return true;
428 }
429 // Big textures
430 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
431 {
432 Interlocked.Increment(ref oversizedImages);
433 BytesSent += response.bytes;
434 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
435 //m_actions.Add(timeBasedAction);
436 return true;
437 }
438 else
439 {
440 return false;
441 }
442 }
443
444 return haskey;
445 }
446
447 public void ProcessTime()
448 {
449 PassTime();
450 }
451
452 private void PassTime()
453 {
454 currenttime = Util.EnvironmentTickCount();
455 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
456 //processTimeBasedActions(responses);
457 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
458 {
459 lastTimeElapsed = Util.EnvironmentTickCount();
460 BytesSent -= ThrottleBytes;
461 if (BytesSent < 0) BytesSent = 0;
462 if (BytesSent < ThrottleBytes)
463 {
464 oversizedImages = 0;
465 }
466 }
467 }
468 public int ThrottleBytes;
469 }
144 } 470 }
471
472
145} 473}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 45d33cd..1b68603 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -129,15 +129,15 @@ namespace OpenSim.Region.ClientStack.Linden
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); 129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130 130
131 OSDMap data = new OSDMap(); 131 OSDMap data = new OSDMap();
132 ScenePresence sp = m_scene.GetScenePresence(agentID); 132// ScenePresence sp = m_scene.GetScenePresence(m_agentID);
133 data["username"] = sp.Firstname + "." + sp.Lastname; 133// data["username"] = sp.Firstname + "." + sp.Lastname;
134 data["display_name_next_update"] = new OSDDate(DateTime.Now); 134// data["display_name_next_update"] = new OSDDate(DateTime.Now);
135 data["legacy_first_name"] = sp.Firstname; 135// data["legacy_first_name"] = sp.Firstname;
136 data["mesh_upload_status"] = "valid"; 136 data["mesh_upload_status"] = "valid";
137 data["display_name"] = sp.Firstname + " " + sp.Lastname; 137// data["display_name"] = sp.Firstname + " " + sp.Lastname;
138 data["legacy_last_name"] = sp.Lastname; 138// data["legacy_last_name"] = sp.Lastname;
139 data["id"] = agentID; 139// data["id"] = m_agentID;
140 data["is_display_name_default"] = true; 140// data["is_display_name_default"] = true;
141 141
142 //Send back data 142 //Send back data
143 Hashtable responsedata = new Hashtable(); 143 Hashtable responsedata = new Hashtable();
@@ -148,4 +148,4 @@ namespace OpenSim.Region.ClientStack.Linden
148 return responsedata; 148 return responsedata;
149 } 149 }
150 } 150 }
151} \ No newline at end of file 151}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
deleted file mode 100644
index f69a0bb..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ /dev/null
@@ -1,297 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Framework.Capabilities;
47using PermissionMask = OpenSim.Framework.PermissionMask;
48
49namespace OpenSim.Region.ClientStack.Linden
50{
51 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")]
52 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
53 {
54// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 private Scene m_scene;
57// private IAssetService m_assetService;
58 private bool m_dumpAssetsToFile = false;
59 private bool m_enabled = true;
60 private int m_levelUpload = 0;
61
62 #region Region Module interfaceBase Members
63
64
65 public Type ReplaceableInterface
66 {
67 get { return null; }
68 }
69
70 public void Initialise(IConfigSource source)
71 {
72 IConfig meshConfig = source.Configs["Mesh"];
73 if (meshConfig == null)
74 return;
75
76 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
77 m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
78 }
79
80 public void AddRegion(Scene pScene)
81 {
82 m_scene = pScene;
83 }
84
85 public void RemoveRegion(Scene scene)
86 {
87
88 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
89 m_scene = null;
90 }
91
92 public void RegionLoaded(Scene scene)
93 {
94
95// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
96 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
97 }
98
99 #endregion
100
101
102 #region Region Module interface
103
104
105
106 public void Close() { }
107
108 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
109
110
111 public void RegisterCaps(UUID agentID, Caps caps)
112 {
113 if(!m_enabled)
114 return;
115
116 UUID capID = UUID.Random();
117
118// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
119 caps.RegisterHandler(
120 "NewFileAgentInventoryVariablePrice",
121 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
122 "POST",
123 "/CAPS/" + capID.ToString(),
124 req => NewAgentInventoryRequest(req, agentID),
125 "NewFileAgentInventoryVariablePrice",
126 agentID.ToString()));
127 }
128
129 #endregion
130
131 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
132 {
133 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
134 // you need to be aware of this
135
136 //if (llsdRequest.asset_type == "texture" ||
137 // llsdRequest.asset_type == "animation" ||
138 // llsdRequest.asset_type == "sound")
139 // {
140 // check user level
141
142 ScenePresence avatar = null;
143 IClientAPI client = null;
144 m_scene.TryGetScenePresence(agentID, out avatar);
145
146 if (avatar != null)
147 {
148 client = avatar.ControllingClient;
149
150 if (avatar.UserLevel < m_levelUpload)
151 {
152 if (client != null)
153 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
154
155 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
156 errorResponse.rsvp = "";
157 errorResponse.state = "error";
158 return errorResponse;
159 }
160 }
161
162 // check funds
163 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
164
165 if (mm != null)
166 {
167 if (!mm.UploadCovered(agentID, mm.UploadCharge))
168 {
169 if (client != null)
170 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
171
172 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
173 errorResponse.rsvp = "";
174 errorResponse.state = "error";
175 return errorResponse;
176 }
177 }
178
179 // }
180
181 string assetName = llsdRequest.name;
182 string assetDes = llsdRequest.description;
183 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
184 UUID newAsset = UUID.Random();
185 UUID newInvItem = UUID.Random();
186 UUID parentFolder = llsdRequest.folder_id;
187 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
188
189 AssetUploader uploader =
190 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
191 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
192
193 MainServer.Instance.AddStreamHandler(
194 new BinaryStreamHandler(
195 "POST",
196 capsBase + uploaderPath,
197 uploader.uploaderCaps,
198 "NewFileAgentInventoryVariablePrice",
199 agentID.ToString()));
200
201 string protocol = "http://";
202
203 if (MainServer.Instance.UseSSL)
204 protocol = "https://";
205
206 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
207 uploaderPath;
208
209
210 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
211
212 uploadResponse.rsvp = uploaderURL;
213 uploadResponse.state = "upload";
214 uploadResponse.resource_cost = 0;
215 uploadResponse.upload_price = 0;
216
217 uploader.OnUpLoad += //UploadCompleteHandler;
218
219 delegate(
220 string passetName, string passetDescription, UUID passetID,
221 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
222 string passetType)
223 {
224 UploadCompleteHandler(passetName, passetDescription, passetID,
225 pinventoryItem, pparentFolder, pdata, pinventoryType,
226 passetType,agentID);
227 };
228
229 return uploadResponse;
230 }
231
232 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
233 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
234 string assetType,UUID AgentID)
235 {
236// m_log.DebugFormat(
237// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
238
239 sbyte assType = 0;
240 sbyte inType = 0;
241
242 if (inventoryType == "sound")
243 {
244 inType = 1;
245 assType = 1;
246 }
247 else if (inventoryType == "animation")
248 {
249 inType = 19;
250 assType = 20;
251 }
252 else if (inventoryType == "wearable")
253 {
254 inType = 18;
255 switch (assetType)
256 {
257 case "bodypart":
258 assType = 13;
259 break;
260 case "clothing":
261 assType = 5;
262 break;
263 }
264 }
265 else if (inventoryType == "mesh")
266 {
267 inType = (sbyte)InventoryType.Mesh;
268 assType = (sbyte)AssetType.Mesh;
269 }
270
271 AssetBase asset;
272 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
273 asset.Data = data;
274
275 if (m_scene.AssetService != null)
276 m_scene.AssetService.Store(asset);
277
278 InventoryItemBase item = new InventoryItemBase();
279 item.Owner = AgentID;
280 item.CreatorId = AgentID.ToString();
281 item.ID = inventoryItem;
282 item.AssetID = asset.FullID;
283 item.Description = assetDescription;
284 item.Name = assetName;
285 item.AssetType = assType;
286 item.InvType = inType;
287 item.Folder = parentFolder;
288 item.CurrentPermissions
289 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
290 item.BasePermissions = (uint)PermissionMask.All;
291 item.EveryOnePermissions = 0;
292 item.NextPermissions = (uint)PermissionMask.All;
293 item.CreationDate = Util.UnixTimeSinceEpoch();
294 m_scene.AddInventoryItem(item);
295 }
296 }
297}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index a133a69..5196368 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -64,6 +64,8 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Commands m_commands = new Commands(); 64 private Commands m_commands = new Commands();
65 public ICommands Commands { get { return m_commands; } } 65 public ICommands Commands { get { return m_commands; } }
66 66
67 public event ConsoleMessage OnConsoleMessage;
68
67 public void Initialise(IConfigSource source) 69 public void Initialise(IConfigSource source)
68 { 70 {
69 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); 71 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
@@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 104
103 public void RegisterCaps(UUID agentID, Caps caps) 105 public void RegisterCaps(UUID agentID, Caps caps)
104 { 106 {
105 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) 107 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
106 return; 108 return;
107 109
108 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
@@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden
118 OSD osd = OSD.FromString(message); 120 OSD osd = OSD.FromString(message);
119 121
120 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); 122 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
123
124 ConsoleMessage handlerConsoleMessage = OnConsoleMessage;
125
126 if (handlerConsoleMessage != null)
127 handlerConsoleMessage( agentID, message);
121 } 128 }
122 129
123 public bool RunCommand(string command, UUID invokerID) 130 public bool RunCommand(string command, UUID invokerID)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 79a935d..674b451 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
@@ -65,6 +66,8 @@ namespace OpenSim.Region.ClientStack.Linden
65 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
66 private string m_URL; 67 private string m_URL;
67 68
69 private IBakedTextureModule m_BakedTextureModule;
70
68 public void Initialise(IConfigSource source) 71 public void Initialise(IConfigSource source)
69 { 72 {
70 IConfig config = source.Configs["ClientStack.LindenCaps"]; 73 IConfig config = source.Configs["ClientStack.LindenCaps"];
@@ -76,26 +79,203 @@ namespace OpenSim.Region.ClientStack.Linden
76 IConfig appearanceConfig = source.Configs["Appearance"]; 79 IConfig appearanceConfig = source.Configs["Appearance"];
77 if (appearanceConfig != null) 80 if (appearanceConfig != null)
78 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 81 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
82
83
79 } 84 }
80 85
81 public void AddRegion(Scene s) 86 public void AddRegion(Scene s)
82 { 87 {
83 m_scene = s; 88 m_scene = s;
89
84 } 90 }
85 91
86 public void RemoveRegion(Scene s) 92 public void RemoveRegion(Scene s)
87 { 93 {
94 s.EventManager.OnRegisterCaps -= RegisterCaps;
95 s.EventManager.OnNewPresence -= RegisterNewPresence;
96 s.EventManager.OnRemovePresence -= DeRegisterPresence;
97 m_BakedTextureModule = null;
98 m_scene = null;
88 } 99 }
89 100
101
102
90 public void RegionLoaded(Scene s) 103 public void RegionLoaded(Scene s)
91 { 104 {
92 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 105 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
106 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
107 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
108
109 }
110
111 private void DeRegisterPresence(UUID agentId)
112 {
113 ScenePresence presence = null;
114 if (m_scene.TryGetScenePresence(agentId, out presence))
115 {
116 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
117 }
118
119 }
120
121 private void RegisterNewPresence(ScenePresence presence)
122 {
123 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
124
125 }
126
127 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
128 {
129 int maxCacheitemsLoop = cacheItems.Length;
130 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
131 {
132 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
133 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
134 }
135
136 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
137 if (cacheItems.Length > 0)
138 {
139 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
140 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
141 {
142 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
143 cacheItems[iter].TextureID);
144 }
145
146 ScenePresence p = null;
147 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
148 {
149
150 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
151 if (existingitems == null)
152 {
153 if (m_BakedTextureModule != null)
154 {
155 WearableCacheItem[] savedcache = null;
156 try
157 {
158 if (p.Appearance.WearableCacheItemsDirty)
159 {
160 savedcache = m_BakedTextureModule.Get(p.UUID);
161 p.Appearance.WearableCacheItems = savedcache;
162 p.Appearance.WearableCacheItemsDirty = false;
163 }
164
165 }
166 /*
167 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
168 * it jumps to the General Packet Exception Handler if you don't catch Exception!
169 *
170 catch (System.Net.Sockets.SocketException)
171 {
172 cacheItems = null;
173 }
174 catch (WebException)
175 {
176 cacheItems = null;
177 }
178 catch (InvalidOperationException)
179 {
180 cacheItems = null;
181 } */
182 catch (Exception)
183 {
184 // The service logs a sufficient error message.
185 }
186
187
188 if (savedcache != null)
189 existingitems = savedcache;
190 }
191 }
192 // Existing items null means it's a fully new appearance
193 if (existingitems == null)
194 {
195
196 for (int i = 0; i < maxCacheitemsLoop; i++)
197 {
198 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
199 {
200 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
201 if (face == null)
202 {
203 textureEntry.CreateFace(cacheItems[i].TextureIndex);
204 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
205 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
206 continue;
207 }
208 cacheItems[i].TextureID =face.TextureID;
209 if (m_scene.AssetService != null)
210 cacheItems[i].TextureAsset =
211 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
212 }
213 else
214 {
215 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);
216 }
217
218
219 }
220 }
221 else
222
223
224 {
225 // for each uploaded baked texture
226 for (int i = 0; i < maxCacheitemsLoop; i++)
227 {
228 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
229 {
230 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
231 if (face == null)
232 {
233 textureEntry.CreateFace(cacheItems[i].TextureIndex);
234 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
235 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
236 continue;
237 }
238 cacheItems[i].TextureID =
239 face.TextureID;
240 }
241 else
242 {
243 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);
244 }
245 }
246
247 for (int i = 0; i < maxCacheitemsLoop; i++)
248 {
249 if (cacheItems[i].TextureAsset == null)
250 {
251 cacheItems[i].TextureAsset =
252 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
253 }
254 }
255 }
256
257
258
259 p.Appearance.WearableCacheItems = cacheItems;
260
261
262
263 if (m_BakedTextureModule != null)
264 {
265 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
266 p.Appearance.WearableCacheItemsDirty = true;
267
268 }
269 }
270 }
93 } 271 }
94 272
95 public void PostInitialise() 273 public void PostInitialise()
96 { 274 {
97 } 275 }
98 276
277
278
99 public void Close() { } 279 public void Close() { }
100 280
101 public string Name { get { return "UploadBakedTextureModule"; } } 281 public string Name { get { return "UploadBakedTextureModule"; } }
@@ -107,6 +287,9 @@ namespace OpenSim.Region.ClientStack.Linden
107 287
108 public void RegisterCaps(UUID agentID, Caps caps) 288 public void RegisterCaps(UUID agentID, Caps caps)
109 { 289 {
290 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
291 caps, m_scene.AssetService, m_persistBakedTextures);
292
110 UUID capID = UUID.Random(); 293 UUID capID = UUID.Random();
111 294
112 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 295 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
@@ -117,8 +300,7 @@ namespace OpenSim.Region.ClientStack.Linden
117 new RestStreamHandler( 300 new RestStreamHandler(
118 "POST", 301 "POST",
119 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, 302 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
120 new UploadBakedTextureHandler( 303 avatarhandler.UploadBakedTexture,
121 caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
122 "UploadBakedTexture", 304 "UploadBakedTexture",
123 agentID.ToString())); 305 agentID.ToString()));
124 306
@@ -130,4 +312,4 @@ namespace OpenSim.Region.ClientStack.Linden
130 312
131 } 313 }
132 } 314 }
133} \ No newline at end of file 315}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index b90df17..27b09a6 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -34,9 +34,7 @@ using log4net;
34using Nini.Config; 34using Nini.Config;
35using Mono.Addins; 35using Mono.Addins;
36using OpenMetaverse; 36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework; 37using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
40using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
@@ -45,6 +43,9 @@ using OpenSim.Framework.Capabilities;
45using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps; 44using Caps = OpenSim.Framework.Capabilities.Caps;
47using OpenSim.Capabilities.Handlers; 45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47using OpenMetaverse;
48using OpenMetaverse.StructuredData;
48 49
49namespace OpenSim.Region.ClientStack.Linden 50namespace OpenSim.Region.ClientStack.Linden
50{ 51{
@@ -63,7 +64,7 @@ namespace OpenSim.Region.ClientStack.Linden
63 public List<UUID> folders; 64 public List<UUID> folders;
64 } 65 }
65 66
66// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 68
68 private Scene m_scene; 69 private Scene m_scene;
69 70
@@ -251,7 +252,8 @@ namespace OpenSim.Region.ClientStack.Linden
251 { 252 {
252 if (!reqinfo.folders.Contains(folderID)) 253 if (!reqinfo.folders.Contains(folderID))
253 { 254 {
254 //TODO: Port COF handling from Avination 255 if (sp.COF != UUID.Zero && sp.COF == folderID)
256 highPriority = true;
255 reqinfo.folders.Add(folderID); 257 reqinfo.folders.Add(folderID);
256 } 258 }
257 } 259 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index 4d0568d..15d6f7f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 m_stopPacket = TexturePacketCount(); 234 m_stopPacket = TexturePacketCount();
235 } 235 }
236 236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
237 m_currentPacket = StartPacket; 240 m_currentPacket = StartPacket;
238 } 241 }
239 } 242 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 79c80a7..dfad485 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -101,6 +101,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
101 public event AvatarPickerRequest OnAvatarPickerRequest; 101 public event AvatarPickerRequest OnAvatarPickerRequest;
102 public event StartAnim OnStartAnim; 102 public event StartAnim OnStartAnim;
103 public event StopAnim OnStopAnim; 103 public event StopAnim OnStopAnim;
104 public event ChangeAnim OnChangeAnim;
104 public event Action<IClientAPI> OnRequestAvatarsData; 105 public event Action<IClientAPI> OnRequestAvatarsData;
105 public event LinkObjects OnLinkObjects; 106 public event LinkObjects OnLinkObjects;
106 public event DelinkObjects OnDelinkObjects; 107 public event DelinkObjects OnDelinkObjects;
@@ -128,6 +129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; 129 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
129 public event UpdatePrimFlags OnUpdatePrimFlags; 130 public event UpdatePrimFlags OnUpdatePrimFlags;
130 public event UpdatePrimTexture OnUpdatePrimTexture; 131 public event UpdatePrimTexture OnUpdatePrimTexture;
132 public event ClientChangeObject onClientChangeObject;
131 public event UpdateVector OnUpdatePrimGroupPosition; 133 public event UpdateVector OnUpdatePrimGroupPosition;
132 public event UpdateVector OnUpdatePrimSinglePosition; 134 public event UpdateVector OnUpdatePrimSinglePosition;
133 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 135 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
@@ -161,6 +163,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 public event RequestTaskInventory OnRequestTaskInventory; 163 public event RequestTaskInventory OnRequestTaskInventory;
162 public event UpdateInventoryItem OnUpdateInventoryItem; 164 public event UpdateInventoryItem OnUpdateInventoryItem;
163 public event CopyInventoryItem OnCopyInventoryItem; 165 public event CopyInventoryItem OnCopyInventoryItem;
166 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
164 public event MoveInventoryItem OnMoveInventoryItem; 167 public event MoveInventoryItem OnMoveInventoryItem;
165 public event RemoveInventoryItem OnRemoveInventoryItem; 168 public event RemoveInventoryItem OnRemoveInventoryItem;
166 public event RemoveInventoryFolder OnRemoveInventoryFolder; 169 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -259,7 +262,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
259 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 262 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
260 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 263 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
261 public event ClassifiedDelete OnClassifiedDelete; 264 public event ClassifiedDelete OnClassifiedDelete;
262 public event ClassifiedDelete OnClassifiedGodDelete; 265 public event ClassifiedGodDelete OnClassifiedGodDelete;
263 public event EventNotificationAddRequest OnEventNotificationAddRequest; 266 public event EventNotificationAddRequest OnEventNotificationAddRequest;
264 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 267 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
265 public event EventGodDelete OnEventGodDelete; 268 public event EventGodDelete OnEventGodDelete;
@@ -290,10 +293,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
290 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 293 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
291 public event SimWideDeletesDelegate OnSimWideDeletes; 294 public event SimWideDeletesDelegate OnSimWideDeletes;
292 public event SendPostcard OnSendPostcard; 295 public event SendPostcard OnSendPostcard;
296 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
293 public event MuteListEntryUpdate OnUpdateMuteListEntry; 297 public event MuteListEntryUpdate OnUpdateMuteListEntry;
294 public event MuteListEntryRemove OnRemoveMuteListEntry; 298 public event MuteListEntryRemove OnRemoveMuteListEntry;
295 public event GodlikeMessage onGodlikeMessage; 299 public event GodlikeMessage onGodlikeMessage;
296 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 300 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
301 public event GenericCall2 OnUpdateThrottles;
297 302
298 #endregion Events 303 #endregion Events
299 304
@@ -322,11 +327,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
322 private readonly byte[] m_channelVersion = Utils.EmptyBytes; 327 private readonly byte[] m_channelVersion = Utils.EmptyBytes;
323 private readonly IGroupsModule m_GroupsModule; 328 private readonly IGroupsModule m_GroupsModule;
324 329
330 private int m_cachedTextureSerial;
325 private PriorityQueue m_entityUpdates; 331 private PriorityQueue m_entityUpdates;
326 private PriorityQueue m_entityProps; 332 private PriorityQueue m_entityProps;
327 private Prioritizer m_prioritizer; 333 private Prioritizer m_prioritizer;
328 private bool m_disableFacelights = false; 334 private bool m_disableFacelights = false;
329 335
336 private bool m_VelocityInterpolate = false;
337 private const uint MaxTransferBytesPerPacket = 600;
338
339
330 /// <value> 340 /// <value>
331 /// List used in construction of data blocks for an object update packet. This is to stop us having to 341 /// List used in construction of data blocks for an object update packet. This is to stop us having to
332 /// continually recreate it. 342 /// continually recreate it.
@@ -338,13 +348,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
338 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 348 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
339 /// ownerless phantom. 349 /// ownerless phantom.
340 /// 350 ///
341 /// All manipulation of this set has to occur under a lock 351 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
342 /// 352 ///
343 /// </value> 353 /// </value>
344 protected HashSet<uint> m_killRecord; 354// protected HashSet<uint> m_killRecord;
345 355
346// protected HashSet<uint> m_attachmentsSent; 356// protected HashSet<uint> m_attachmentsSent;
347 357
358 private bool m_deliverPackets = true;
348 private int m_animationSequenceNumber = 1; 359 private int m_animationSequenceNumber = 1;
349 private bool m_SendLogoutPacketWhenClosing = true; 360 private bool m_SendLogoutPacketWhenClosing = true;
350 361
@@ -391,6 +402,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
391 get { return m_startpos; } 402 get { return m_startpos; }
392 set { m_startpos = value; } 403 set { m_startpos = value; }
393 } 404 }
405 public bool DeliverPackets
406 {
407 get { return m_deliverPackets; }
408 set {
409 m_deliverPackets = value;
410 m_udpClient.m_deliverPackets = value;
411 }
412 }
394 public UUID AgentId { get { return m_agentId; } } 413 public UUID AgentId { get { return m_agentId; } }
395 public ISceneAgent SceneAgent { get; set; } 414 public ISceneAgent SceneAgent { get; set; }
396 public UUID ActiveGroupId { get { return m_activeGroupID; } } 415 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -441,6 +460,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
441 } 460 }
442 461
443 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 462 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
463
444 464
445 #endregion Properties 465 #endregion Properties
446 466
@@ -467,7 +487,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
467 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 487 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
468 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 488 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
469 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 489 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
470 m_killRecord = new HashSet<uint>(); 490// m_killRecord = new HashSet<uint>();
471// m_attachmentsSent = new HashSet<uint>(); 491// m_attachmentsSent = new HashSet<uint>();
472 492
473 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 493 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -496,12 +516,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
496 516
497 #region Client Methods 517 #region Client Methods
498 518
519
520 /// <summary>
521 /// Close down the client view
522 /// </summary>
499 public void Close() 523 public void Close()
500 { 524 {
501 Close(false); 525 Close(true, false);
502 } 526 }
503 527
504 public void Close(bool force) 528 public void Close(bool sendStop, bool force)
505 { 529 {
506 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 530 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
507 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 531 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -513,7 +537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
513 return; 537 return;
514 538
515 IsActive = false; 539 IsActive = false;
516 CloseWithoutChecks(); 540 CloseWithoutChecks(sendStop);
517 } 541 }
518 } 542 }
519 543
@@ -526,12 +550,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
526 /// 550 ///
527 /// Callers must lock ClosingSyncLock before calling. 551 /// Callers must lock ClosingSyncLock before calling.
528 /// </remarks> 552 /// </remarks>
529 public void CloseWithoutChecks() 553 public void CloseWithoutChecks(bool sendStop)
530 { 554 {
531 m_log.DebugFormat( 555 m_log.DebugFormat(
532 "[CLIENT]: Close has been called for {0} attached to scene {1}", 556 "[CLIENT]: Close has been called for {0} attached to scene {1}",
533 Name, m_scene.RegionInfo.RegionName); 557 Name, m_scene.RegionInfo.RegionName);
534 558
559 if (sendStop)
560 {
561 // Send the STOP packet
562 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
563 OutPacket(disable, ThrottleOutPacketType.Unknown);
564 }
565
535 // Shutdown the image manager 566 // Shutdown the image manager
536 ImageManager.Close(); 567 ImageManager.Close();
537 568
@@ -554,6 +585,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
554 // Disable UDP handling for this client 585 // Disable UDP handling for this client
555 m_udpClient.Shutdown(); 586 m_udpClient.Shutdown();
556 587
588
557 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 589 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
558 //GC.Collect(); 590 //GC.Collect();
559 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 591 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -809,7 +841,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
809 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; 841 handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags;
810 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported 842 handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported
811 843
812 OutPacket(handshake, ThrottleOutPacketType.Task); 844 OutPacket(handshake, ThrottleOutPacketType.Unknown);
813 } 845 }
814 846
815 847
@@ -850,7 +882,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
850 reply.ChatData.OwnerID = ownerID; 882 reply.ChatData.OwnerID = ownerID;
851 reply.ChatData.SourceID = fromAgentID; 883 reply.ChatData.SourceID = fromAgentID;
852 884
853 OutPacket(reply, ThrottleOutPacketType.Task); 885 OutPacket(reply, ThrottleOutPacketType.Unknown);
854 } 886 }
855 887
856 /// <summary> 888 /// <summary>
@@ -883,32 +915,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
883 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 915 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
884 msg.MessageBlock.BinaryBucket = im.binaryBucket; 916 msg.MessageBlock.BinaryBucket = im.binaryBucket;
885 917
886 if (im.message.StartsWith("[grouptest]")) 918 OutPacket(msg, ThrottleOutPacketType.Task);
887 { // this block is test code for implementing group IM - delete when group IM is finished
888 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
889 if (eq != null)
890 {
891 im.dialog = 17;
892
893 //eq.ChatterboxInvitation(
894 // new UUID("00000000-68f9-1111-024e-222222111123"),
895 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
896 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
897
898 eq.ChatterboxInvitation(
899 new UUID("00000000-68f9-1111-024e-222222111123"),
900 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
901 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
902
903 eq.ChatterBoxSessionAgentListUpdates(
904 new UUID("00000000-68f9-1111-024e-222222111123"),
905 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
906 }
907
908 Console.WriteLine("SendInstantMessage: " + msg);
909 }
910 else
911 OutPacket(msg, ThrottleOutPacketType.Task);
912 } 919 }
913 } 920 }
914 921
@@ -1146,6 +1153,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 public virtual void SendLayerData(float[] map) 1153 public virtual void SendLayerData(float[] map)
1147 { 1154 {
1148 Util.FireAndForget(DoSendLayerData, map); 1155 Util.FireAndForget(DoSendLayerData, map);
1156
1157 // Send it sync, and async. It's not that much data
1158 // and it improves user experience just so much!
1159 DoSendLayerData(map);
1149 } 1160 }
1150 1161
1151 /// <summary> 1162 /// <summary>
@@ -1158,16 +1169,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1158 1169
1159 try 1170 try
1160 { 1171 {
1161 //for (int y = 0; y < 16; y++) 1172 for (int y = 0; y < 16; y++)
1162 //{ 1173 {
1163 // for (int x = 0; x < 16; x++) 1174 for (int x = 0; x < 16; x+=4)
1164 // { 1175 {
1165 // SendLayerData(x, y, map); 1176 SendLayerPacket(x, y, map);
1166 // } 1177 }
1167 //} 1178 }
1168
1169 // Send LayerData in a spiral pattern. Fun!
1170 SendLayerTopRight(map, 0, 0, 15, 15);
1171 } 1179 }
1172 catch (Exception e) 1180 catch (Exception e)
1173 { 1181 {
@@ -1175,51 +1183,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1175 } 1183 }
1176 } 1184 }
1177 1185
1178 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1179 {
1180 // Row
1181 for (int i = x1; i <= x2; i++)
1182 SendLayerData(i, y1, map);
1183
1184 // Column
1185 for (int j = y1 + 1; j <= y2; j++)
1186 SendLayerData(x2, j, map);
1187
1188 if (x2 - x1 > 0)
1189 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1190 }
1191
1192 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1193 {
1194 // Row in reverse
1195 for (int i = x2; i >= x1; i--)
1196 SendLayerData(i, y2, map);
1197
1198 // Column in reverse
1199 for (int j = y2 - 1; j >= y1; j--)
1200 SendLayerData(x1, j, map);
1201
1202 if (x2 - x1 > 0)
1203 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1204 }
1205
1206 /// <summary> 1186 /// <summary>
1207 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1187 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1208 /// </summary> 1188 /// </summary>
1209 /// <param name="map">heightmap</param> 1189 /// <param name="map">heightmap</param>
1210 /// <param name="px">X coordinate for patches 0..12</param> 1190 /// <param name="px">X coordinate for patches 0..12</param>
1211 /// <param name="py">Y coordinate for patches 0..15</param> 1191 /// <param name="py">Y coordinate for patches 0..15</param>
1212 // private void SendLayerPacket(float[] map, int y, int x) 1192 private void SendLayerPacket(int x, int y, float[] map)
1213 // { 1193 {
1214 // int[] patches = new int[4]; 1194 int[] patches = new int[4];
1215 // patches[0] = x + 0 + y * 16; 1195 patches[0] = x + 0 + y * 16;
1216 // patches[1] = x + 1 + y * 16; 1196 patches[1] = x + 1 + y * 16;
1217 // patches[2] = x + 2 + y * 16; 1197 patches[2] = x + 2 + y * 16;
1218 // patches[3] = x + 3 + y * 16; 1198 patches[3] = x + 3 + y * 16;
1219 1199
1220 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1200 float[] heightmap = (map.Length == 65536) ?
1221 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1201 map :
1222 // } 1202 LLHeightFieldMoronize(map);
1203
1204 try
1205 {
1206 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1207 OutPacket(layerpack, ThrottleOutPacketType.Land);
1208 }
1209 catch
1210 {
1211 for (int px = x ; px < x + 4 ; px++)
1212 SendLayerData(px, y, map);
1213 }
1214 }
1223 1215
1224 /// <summary> 1216 /// <summary>
1225 /// Sends a specified patch to a client 1217 /// Sends a specified patch to a client
@@ -1239,7 +1231,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1239 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1231 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1240 layerpack.Header.Reliable = true; 1232 layerpack.Header.Reliable = true;
1241 1233
1242 OutPacket(layerpack, ThrottleOutPacketType.Land); 1234 OutPacket(layerpack, ThrottleOutPacketType.Task);
1243 } 1235 }
1244 catch (Exception e) 1236 catch (Exception e)
1245 { 1237 {
@@ -1609,7 +1601,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1609 1601
1610 public void SendKillObject(List<uint> localIDs) 1602 public void SendKillObject(List<uint> localIDs)
1611 { 1603 {
1612// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1604// foreach (uint id in localIDs)
1605// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1613 1606
1614 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1607 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1615 // TODO: don't create new blocks if recycling an old packet 1608 // TODO: don't create new blocks if recycling an old packet
@@ -1631,17 +1624,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1631 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1624 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1632 // condition where a kill can be processed before an out-of-date update for the same object. 1625 // condition where a kill can be processed before an out-of-date update for the same object.
1633 // ProcessEntityUpdates() also takes the m_killRecord lock. 1626 // ProcessEntityUpdates() also takes the m_killRecord lock.
1634 lock (m_killRecord) 1627// lock (m_killRecord)
1635 { 1628// {
1636 foreach (uint localID in localIDs) 1629// foreach (uint localID in localIDs)
1637 m_killRecord.Add(localID); 1630// m_killRecord.Add(localID);
1638 1631
1639 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1632 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1640 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1633 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1641 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1634 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1642 // scene objects in a viewer until that viewer is relogged in. 1635 // scene objects in a viewer until that viewer is relogged in.
1643 OutPacket(kill, ThrottleOutPacketType.Task); 1636 OutPacket(kill, ThrottleOutPacketType.Task);
1644 } 1637// }
1645 } 1638 }
1646 } 1639 }
1647 1640
@@ -1763,7 +1756,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1763 newBlock.CreationDate = item.CreationDate; 1756 newBlock.CreationDate = item.CreationDate;
1764 newBlock.SalePrice = item.SalePrice; 1757 newBlock.SalePrice = item.SalePrice;
1765 newBlock.SaleType = item.SaleType; 1758 newBlock.SaleType = item.SaleType;
1766 newBlock.Flags = item.Flags; 1759 newBlock.Flags = item.Flags & 0xff;
1767 1760
1768 newBlock.CRC = 1761 newBlock.CRC =
1769 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, 1762 Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType,
@@ -2017,7 +2010,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2017 itemBlock.GroupID = item.GroupID; 2010 itemBlock.GroupID = item.GroupID;
2018 itemBlock.GroupOwned = item.GroupOwned; 2011 itemBlock.GroupOwned = item.GroupOwned;
2019 itemBlock.GroupMask = item.GroupPermissions; 2012 itemBlock.GroupMask = item.GroupPermissions;
2020 itemBlock.Flags = item.Flags; 2013 itemBlock.Flags = item.Flags & 0xff;
2021 itemBlock.SalePrice = item.SalePrice; 2014 itemBlock.SalePrice = item.SalePrice;
2022 itemBlock.SaleType = item.SaleType; 2015 itemBlock.SaleType = item.SaleType;
2023 itemBlock.CreationDate = item.CreationDate; 2016 itemBlock.CreationDate = item.CreationDate;
@@ -2084,7 +2077,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2084 bulkUpdate.ItemData[0].GroupID = item.GroupID; 2077 bulkUpdate.ItemData[0].GroupID = item.GroupID;
2085 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned; 2078 bulkUpdate.ItemData[0].GroupOwned = item.GroupOwned;
2086 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions; 2079 bulkUpdate.ItemData[0].GroupMask = item.GroupPermissions;
2087 bulkUpdate.ItemData[0].Flags = item.Flags; 2080 bulkUpdate.ItemData[0].Flags = item.Flags & 0xff;
2088 bulkUpdate.ItemData[0].SalePrice = item.SalePrice; 2081 bulkUpdate.ItemData[0].SalePrice = item.SalePrice;
2089 bulkUpdate.ItemData[0].SaleType = item.SaleType; 2082 bulkUpdate.ItemData[0].SaleType = item.SaleType;
2090 2083
@@ -2100,9 +2093,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2100 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2093 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2101 } 2094 }
2102 2095
2103 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2104 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2096 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2105 { 2097 {
2098 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2099 }
2100
2101 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2102 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2103 {
2106 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff; 2104 const uint FULL_MASK_PERMISSIONS = (uint)0x7fffffff;
2107 2105
2108 UpdateCreateInventoryItemPacket InventoryReply 2106 UpdateCreateInventoryItemPacket InventoryReply
@@ -2112,6 +2110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2112 // TODO: don't create new blocks if recycling an old packet 2110 // TODO: don't create new blocks if recycling an old packet
2113 InventoryReply.AgentData.AgentID = AgentId; 2111 InventoryReply.AgentData.AgentID = AgentId;
2114 InventoryReply.AgentData.SimApproved = true; 2112 InventoryReply.AgentData.SimApproved = true;
2113 InventoryReply.AgentData.TransactionID = transactionID;
2115 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2114 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2116 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2115 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2117 InventoryReply.InventoryData[0].ItemID = Item.ID; 2116 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2132,7 +2131,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2132 InventoryReply.InventoryData[0].GroupID = Item.GroupID; 2131 InventoryReply.InventoryData[0].GroupID = Item.GroupID;
2133 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned; 2132 InventoryReply.InventoryData[0].GroupOwned = Item.GroupOwned;
2134 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions; 2133 InventoryReply.InventoryData[0].GroupMask = Item.GroupPermissions;
2135 InventoryReply.InventoryData[0].Flags = Item.Flags; 2134 InventoryReply.InventoryData[0].Flags = Item.Flags & 0xff;
2136 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice; 2135 InventoryReply.InventoryData[0].SalePrice = Item.SalePrice;
2137 InventoryReply.InventoryData[0].SaleType = Item.SaleType; 2136 InventoryReply.InventoryData[0].SaleType = Item.SaleType;
2138 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate; 2137 InventoryReply.InventoryData[0].CreationDate = Item.CreationDate;
@@ -2181,16 +2180,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2181 replytask.InventoryData.TaskID = taskID; 2180 replytask.InventoryData.TaskID = taskID;
2182 replytask.InventoryData.Serial = serial; 2181 replytask.InventoryData.Serial = serial;
2183 replytask.InventoryData.Filename = fileName; 2182 replytask.InventoryData.Filename = fileName;
2184 OutPacket(replytask, ThrottleOutPacketType.Asset); 2183 OutPacket(replytask, ThrottleOutPacketType.Task);
2185 } 2184 }
2186 2185
2187 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2186 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2188 { 2187 {
2188 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2189 if (isTaskInventory)
2190 type = ThrottleOutPacketType.Task;
2191
2189 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2192 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2190 sendXfer.XferID.ID = xferID; 2193 sendXfer.XferID.ID = xferID;
2191 sendXfer.XferID.Packet = packet; 2194 sendXfer.XferID.Packet = packet;
2192 sendXfer.DataPacket.Data = data; 2195 sendXfer.DataPacket.Data = data;
2193 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2196 OutPacket(sendXfer, type);
2194 } 2197 }
2195 2198
2196 public void SendAbortXferPacket(ulong xferID) 2199 public void SendAbortXferPacket(ulong xferID)
@@ -2377,6 +2380,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2377 OutPacket(sound, ThrottleOutPacketType.Task); 2380 OutPacket(sound, ThrottleOutPacketType.Task);
2378 } 2381 }
2379 2382
2383 public void SendTransferAbort(TransferRequestPacket transferRequest)
2384 {
2385 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2386 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2387 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2388 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2389 OutPacket(abort, ThrottleOutPacketType.Task);
2390 }
2391
2380 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2392 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2381 { 2393 {
2382 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2394 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2685,6 +2697,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2685 float friction = part.Friction; 2697 float friction = part.Friction;
2686 float bounce = part.Restitution; 2698 float bounce = part.Restitution;
2687 float gravmod = part.GravityModifier; 2699 float gravmod = part.GravityModifier;
2700
2688 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2701 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2689 } 2702 }
2690 } 2703 }
@@ -2755,8 +2768,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2755 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2768 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2756 return; 2769 return;
2757 } 2770 }
2771 int WearableOut = 0;
2772 bool isWearable = false;
2773
2774 if (req.AssetInf != null)
2775 isWearable =
2776 ((AssetType) req.AssetInf.Type ==
2777 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2758 2778
2759 //m_log.Debug("sending asset " + req.RequestAssetID); 2779
2780 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2781
2782
2783 //if (isWearable)
2784 // m_log.Debug((AssetType)req.AssetInf.Type);
2785
2760 TransferInfoPacket Transfer = new TransferInfoPacket(); 2786 TransferInfoPacket Transfer = new TransferInfoPacket();
2761 Transfer.TransferInfo.ChannelType = 2; 2787 Transfer.TransferInfo.ChannelType = 2;
2762 Transfer.TransferInfo.Status = 0; 2788 Transfer.TransferInfo.Status = 0;
@@ -2778,7 +2804,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2778 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2804 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2779 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2805 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2780 Transfer.Header.Zerocoded = true; 2806 Transfer.Header.Zerocoded = true;
2781 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2807 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2782 2808
2783 if (req.NumPackets == 1) 2809 if (req.NumPackets == 1)
2784 { 2810 {
@@ -2789,12 +2815,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2789 TransferPacket.TransferData.Data = req.AssetInf.Data; 2815 TransferPacket.TransferData.Data = req.AssetInf.Data;
2790 TransferPacket.TransferData.Status = 1; 2816 TransferPacket.TransferData.Status = 1;
2791 TransferPacket.Header.Zerocoded = true; 2817 TransferPacket.Header.Zerocoded = true;
2792 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2818 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2793 } 2819 }
2794 else 2820 else
2795 { 2821 {
2796 int processedLength = 0; 2822 int processedLength = 0;
2797 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2823// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2824
2825 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2798 int packetNumber = 0; 2826 int packetNumber = 0;
2799 2827
2800 while (processedLength < req.AssetInf.Data.Length) 2828 while (processedLength < req.AssetInf.Data.Length)
@@ -2820,7 +2848,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2820 TransferPacket.TransferData.Status = 1; 2848 TransferPacket.TransferData.Status = 1;
2821 } 2849 }
2822 TransferPacket.Header.Zerocoded = true; 2850 TransferPacket.Header.Zerocoded = true;
2823 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2851 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2824 2852
2825 processedLength += chunkSize; 2853 processedLength += chunkSize;
2826 packetNumber++; 2854 packetNumber++;
@@ -2865,7 +2893,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2865 reply.Data.ParcelID = parcelID; 2893 reply.Data.ParcelID = parcelID;
2866 reply.Data.OwnerID = land.OwnerID; 2894 reply.Data.OwnerID = land.OwnerID;
2867 reply.Data.Name = Utils.StringToBytes(land.Name); 2895 reply.Data.Name = Utils.StringToBytes(land.Name);
2868 reply.Data.Desc = Utils.StringToBytes(land.Description); 2896 if (land != null && land.Description != null && land.Description != String.Empty)
2897 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2898 else
2899 reply.Data.Desc = new Byte[0];
2869 reply.Data.ActualArea = land.Area; 2900 reply.Data.ActualArea = land.Area;
2870 reply.Data.BillableArea = land.Area; // TODO: what is this? 2901 reply.Data.BillableArea = land.Area; // TODO: what is this?
2871 2902
@@ -3572,24 +3603,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3572 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3603 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3573 AgentWearablesUpdatePacket.WearableDataBlock awb; 3604 AgentWearablesUpdatePacket.WearableDataBlock awb;
3574 int idx = 0; 3605 int idx = 0;
3575 for (int i = 0; i < wearables.Length; i++) 3606
3576 { 3607 for (int i = 0; i < wearables.Length; i++)
3577 for (int j = 0; j < wearables[i].Count; j++) 3608 {
3578 { 3609 for (int j = 0; j < wearables[i].Count; j++)
3579 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3610 {
3580 awb.WearableType = (byte)i; 3611 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3581 awb.AssetID = wearables[i][j].AssetID; 3612 awb.WearableType = (byte) i;
3582 awb.ItemID = wearables[i][j].ItemID; 3613 awb.AssetID = wearables[i][j].AssetID;
3583 aw.WearableData[idx] = awb; 3614 awb.ItemID = wearables[i][j].ItemID;
3584 idx++; 3615 aw.WearableData[idx] = awb;
3585 3616 idx++;
3586// m_log.DebugFormat( 3617
3587// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3618 // m_log.DebugFormat(
3588// awb.ItemID, awb.AssetID, i, Name); 3619 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3589 } 3620 // awb.ItemID, awb.AssetID, i, Name);
3590 } 3621 }
3622 }
3591 3623
3592 OutPacket(aw, ThrottleOutPacketType.Task); 3624 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3593 } 3625 }
3594 3626
3595 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3627 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3600,7 +3632,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3600 3632
3601 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3633 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3602 // TODO: don't create new blocks if recycling an old packet 3634 // TODO: don't create new blocks if recycling an old packet
3603 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3635 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3604 avp.ObjectData.TextureEntry = textureEntry; 3636 avp.ObjectData.TextureEntry = textureEntry;
3605 3637
3606 AvatarAppearancePacket.VisualParamBlock avblock = null; 3638 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3731,7 +3763,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3731 /// </summary> 3763 /// </summary>
3732 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3764 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3733 { 3765 {
3734 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3766 if (entity is SceneObjectPart)
3767 {
3768 SceneObjectPart e = (SceneObjectPart)entity;
3769 SceneObjectGroup g = e.ParentGroup;
3770 if (g.RootPart.Shape.State > 30) // HUD
3771 if (g.OwnerID != AgentId)
3772 return; // Don't send updates for other people's HUDs
3773 }
3774
3735 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3775 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3736 3776
3737 lock (m_entityUpdates.SyncRoot) 3777 lock (m_entityUpdates.SyncRoot)
@@ -3798,27 +3838,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3798 3838
3799 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3839 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3800 // condition where a kill can be processed before an out-of-date update for the same object. 3840 // condition where a kill can be processed before an out-of-date update for the same object.
3801 lock (m_killRecord) 3841 float avgTimeDilation = 1.0f;
3842 IEntityUpdate iupdate;
3843 Int32 timeinqueue; // this is just debugging code & can be dropped later
3844
3845 while (updatesThisCall < maxUpdates)
3802 { 3846 {
3803 float avgTimeDilation = 1.0f; 3847 lock (m_entityUpdates.SyncRoot)
3804 IEntityUpdate iupdate; 3848 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3805 Int32 timeinqueue; // this is just debugging code & can be dropped later 3849 break;
3806 3850
3807 while (updatesThisCall < maxUpdates) 3851 EntityUpdate update = (EntityUpdate)iupdate;
3852
3853 avgTimeDilation += update.TimeDilation;
3854 avgTimeDilation *= 0.5f;
3855
3856 if (update.Entity is SceneObjectPart)
3808 { 3857 {
3809 lock (m_entityUpdates.SyncRoot) 3858 SceneObjectPart part = (SceneObjectPart)update.Entity;
3810 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3811 break;
3812 3859
3813 EntityUpdate update = (EntityUpdate)iupdate; 3860 if (part.ParentGroup.IsDeleted)
3814 3861 continue;
3815 avgTimeDilation += update.TimeDilation;
3816 avgTimeDilation *= 0.5f;
3817 3862
3818 if (update.Entity is SceneObjectPart) 3863 if (part.ParentGroup.IsAttachment)
3864 { // Someone else's HUD, why are we getting these?
3865 if (part.ParentGroup.OwnerID != AgentId &&
3866 part.ParentGroup.RootPart.Shape.State > 30)
3867 continue;
3868 ScenePresence sp;
3869 // Owner is not in the sim, don't update it to
3870 // anyone
3871 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3872 continue;
3873
3874 List<SceneObjectGroup> atts = sp.GetAttachments();
3875 bool found = false;
3876 foreach (SceneObjectGroup att in atts)
3877 {
3878 if (att == part.ParentGroup)
3879 {
3880 found = true;
3881 break;
3882 }
3883 }
3884
3885 // It's an attachment of a valid avatar, but
3886 // doesn't seem to be attached, skip
3887 if (!found)
3888 continue;
3889
3890 // On vehicle crossing, the attachments are received
3891 // while the avatar is still a child. Don't send
3892 // updates here because the LocalId has not yet
3893 // been updated and the viewer will derender the
3894 // attachments until the avatar becomes root.
3895 if (sp.IsChildAgent)
3896 continue;
3897
3898 // If the object is an attachment we don't want it to be in the kill
3899 // record. Else attaching from inworld and subsequently dropping
3900 // it will no longer work.
3901// lock (m_killRecord)
3902// {
3903// m_killRecord.Remove(part.LocalId);
3904// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3905// }
3906 }
3907 else
3819 { 3908 {
3820 SceneObjectPart part = (SceneObjectPart)update.Entity;
3821
3822 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3909 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3823 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3910 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3824 // safety measure. 3911 // safety measure.
@@ -3829,21 +3916,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3829 // 3916 //
3830 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3917 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3831 // after the root prim has been deleted. 3918 // after the root prim has been deleted.
3832 if (m_killRecord.Contains(part.LocalId)) 3919 //
3833 { 3920 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3834 // m_log.WarnFormat( 3921// lock (m_killRecord)
3835 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3922// {
3836 // part.LocalId, Name); 3923// if (m_killRecord.Contains(part.LocalId))
3837 continue; 3924// continue;
3838 } 3925// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3839 3926// continue;
3840 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3927// }
3928 }
3929
3930 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3931 {
3932 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3933 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3841 { 3934 {
3842 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3935 part.Shape.LightEntry = false;
3843 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3844 {
3845 part.Shape.LightEntry = false;
3846 }
3847 } 3936 }
3848 3937
3849 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 3938 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
@@ -3854,224 +3943,166 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3854 part.Shape.ProfileHollow = 27500; 3943 part.Shape.ProfileHollow = 27500;
3855 } 3944 }
3856 } 3945 }
3857 3946
3858 #region UpdateFlags to packet type conversion 3947 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3859
3860 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3861
3862 bool canUseCompressed = true;
3863 bool canUseImproved = true;
3864
3865 // Compressed object updates only make sense for LL primitives
3866 if (!(update.Entity is SceneObjectPart))
3867 { 3948 {
3868 canUseCompressed = false; 3949 // Ensure that mesh has at least 8 valid faces
3950 part.Shape.ProfileBegin = 12500;
3951 part.Shape.ProfileEnd = 0;
3952 part.Shape.ProfileHollow = 27500;
3869 } 3953 }
3870 3954 }
3871 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3955
3956 ++updatesThisCall;
3957
3958 #region UpdateFlags to packet type conversion
3959
3960 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3961
3962 bool canUseCompressed = true;
3963 bool canUseImproved = true;
3964
3965 // Compressed object updates only make sense for LL primitives
3966 if (!(update.Entity is SceneObjectPart))
3967 {
3968 canUseCompressed = false;
3969 }
3970
3971 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3972 {
3973 canUseCompressed = false;
3974 canUseImproved = false;
3975 }
3976 else
3977 {
3978 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3979 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3980 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3981 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3872 { 3982 {
3873 canUseCompressed = false; 3983 canUseCompressed = false;
3874 canUseImproved = false;
3875 } 3984 }
3876 else 3985
3986 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3987 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3988 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3989 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3990 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3991 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3992 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3993 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3994 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3995 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3996 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3997 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3998 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3999 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3877 { 4000 {
3878 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 4001 canUseImproved = false;
3879 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3880 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3881 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3882 {
3883 canUseCompressed = false;
3884 }
3885
3886 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3887 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3888 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3889 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3890 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3891 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3892 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3893 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3894 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3895 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3896 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3897 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3898 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3899 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3900 {
3901 canUseImproved = false;
3902 }
3903 } 4002 }
4003 }
3904 4004
3905 #endregion UpdateFlags to packet type conversion 4005 #endregion UpdateFlags to packet type conversion
3906
3907 #region Block Construction
3908
3909 // TODO: Remove this once we can build compressed updates
3910 canUseCompressed = false;
3911
3912 if (!canUseImproved && !canUseCompressed)
3913 {
3914 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3915 4006
3916 if (update.Entity is ScenePresence) 4007 #region Block Construction
3917 {
3918 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3919 }
3920 else
3921 {
3922 SceneObjectPart part = (SceneObjectPart)update.Entity;
3923 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3924
3925 // If the part has become a private hud since the update was scheduled then we do not
3926 // want to send it to other avatars.
3927 if (part.ParentGroup.IsAttachment
3928 && part.ParentGroup.HasPrivateAttachmentPoint
3929 && part.ParentGroup.AttachedAvatar != AgentId)
3930 continue;
3931
3932 // If the part has since been deleted, then drop the update. In the case of attachments,
3933 // this is to avoid spurious updates to other viewers since post-processing of attachments
3934 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3935 // of the test above).
3936 //
3937 // Actual deletions (kills) happen in another method.
3938 if (part.ParentGroup.IsDeleted)
3939 continue;
3940 }
3941 4008
3942 objectUpdateBlocks.Value.Add(updateBlock); 4009 // TODO: Remove this once we can build compressed updates
3943 objectUpdates.Value.Add(update); 4010 canUseCompressed = false;
3944 }
3945 else if (!canUseImproved)
3946 {
3947 SceneObjectPart part = (SceneObjectPart)update.Entity;
3948 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
3949 = CreateCompressedUpdateBlock(part, updateFlags);
3950
3951 // If the part has since been deleted, then drop the update. In the case of attachments,
3952 // this is to avoid spurious updates to other viewers since post-processing of attachments
3953 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3954 // of the test above).
3955 //
3956 // Actual deletions (kills) happen in another method.
3957 if (part.ParentGroup.IsDeleted)
3958 continue;
3959 4011
3960 compressedUpdateBlocks.Value.Add(compressedBlock); 4012 if (!canUseImproved && !canUseCompressed)
3961 compressedUpdates.Value.Add(update); 4013 {
4014 if (update.Entity is ScenePresence)
4015 {
4016 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3962 } 4017 }
3963 else 4018 else
3964 { 4019 {
3965 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 4020 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3966 {
3967 // Self updates go into a special list
3968 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3969 terseAgentUpdates.Value.Add(update);
3970 }
3971 else
3972 {
3973 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
3974 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
3975
3976 // Everything else goes here
3977 if (update.Entity is SceneObjectPart)
3978 {
3979 SceneObjectPart part = (SceneObjectPart)update.Entity;
3980
3981 // If the part has become a private hud since the update was scheduled then we do not
3982 // want to send it to other avatars.
3983 if (part.ParentGroup.IsAttachment
3984 && part.ParentGroup.HasPrivateAttachmentPoint
3985 && part.ParentGroup.AttachedAvatar != AgentId)
3986 continue;
3987
3988 // If the part has since been deleted, then drop the update. In the case of attachments,
3989 // this is to avoid spurious updates to other viewers since post-processing of attachments
3990 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3991 // of the test above).
3992 //
3993 // Actual deletions (kills) happen in another method.
3994 if (part.ParentGroup.IsDeleted)
3995 continue;
3996 }
3997
3998 terseUpdateBlocks.Value.Add(terseUpdateBlock);
3999 terseUpdates.Value.Add(update);
4000 }
4001 } 4021 }
4002
4003 ++updatesThisCall;
4004
4005 #endregion Block Construction
4006 } 4022 }
4007 4023 else if (!canUseImproved)
4008 #region Packet Sending 4024 {
4009 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 4025 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
4010 4026 }
4011 if (terseAgentUpdateBlocks.IsValueCreated) 4027 else
4012 { 4028 {
4013 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 4029 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
4030 // Self updates go into a special list
4031 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4032 else
4033 // Everything else goes here
4034 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
4035 }
4014 4036
4015 ImprovedTerseObjectUpdatePacket packet 4037 #endregion Block Construction
4016 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 4038 }
4017 4039
4018 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4040 #region Packet Sending
4019 packet.RegionData.TimeDilation = timeDilation; 4041
4020 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4042 const float TIME_DILATION = 1.0f;
4043 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4044
4045 if (terseAgentUpdateBlocks.IsValueCreated)
4046 {
4047 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
4021 4048
4022 for (int i = 0; i < blocks.Count; i++) 4049 ImprovedTerseObjectUpdatePacket packet
4023 packet.ObjectData[i] = blocks[i]; 4050 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
4024 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4051 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4025 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4052 packet.RegionData.TimeDilation = timeDilation;
4026 } 4053 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4027 4054
4028 if (objectUpdateBlocks.IsValueCreated) 4055 for (int i = 0; i < blocks.Count; i++)
4029 { 4056 packet.ObjectData[i] = blocks[i];
4030 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4031
4032 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4033 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4034 packet.RegionData.TimeDilation = timeDilation;
4035 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4036
4037 for (int i = 0; i < blocks.Count; i++)
4038 packet.ObjectData[i] = blocks[i];
4039 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4040 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4041 }
4042
4043 if (compressedUpdateBlocks.IsValueCreated)
4044 {
4045 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4046
4047 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4048 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4049 packet.RegionData.TimeDilation = timeDilation;
4050 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4051
4052 for (int i = 0; i < blocks.Count; i++)
4053 packet.ObjectData[i] = blocks[i];
4054 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4055 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4056 }
4057 4057
4058 if (terseUpdateBlocks.IsValueCreated) 4058 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4059 { 4059 }
4060 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4061
4062 ImprovedTerseObjectUpdatePacket packet
4063 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4064 PacketType.ImprovedTerseObjectUpdate);
4065 4060
4066 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4061 if (objectUpdateBlocks.IsValueCreated)
4067 packet.RegionData.TimeDilation = timeDilation; 4062 {
4068 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4063 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4069 4064
4070 for (int i = 0; i < blocks.Count; i++) 4065 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4071 packet.ObjectData[i] = blocks[i]; 4066 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4072 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4067 packet.RegionData.TimeDilation = timeDilation;
4073 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4068 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4074 } 4069
4070 for (int i = 0; i < blocks.Count; i++)
4071 packet.ObjectData[i] = blocks[i];
4072
4073 OutPacket(packet, ThrottleOutPacketType.Task, true);
4074 }
4075
4076 if (compressedUpdateBlocks.IsValueCreated)
4077 {
4078 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4079
4080 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4081 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4082 packet.RegionData.TimeDilation = timeDilation;
4083 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4084
4085 for (int i = 0; i < blocks.Count; i++)
4086 packet.ObjectData[i] = blocks[i];
4087
4088 OutPacket(packet, ThrottleOutPacketType.Task, true);
4089 }
4090
4091 if (terseUpdateBlocks.IsValueCreated)
4092 {
4093 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4094
4095 ImprovedTerseObjectUpdatePacket packet
4096 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4097 PacketType.ImprovedTerseObjectUpdate);
4098 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4099 packet.RegionData.TimeDilation = timeDilation;
4100 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4101
4102 for (int i = 0; i < blocks.Count; i++)
4103 packet.ObjectData[i] = blocks[i];
4104
4105 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4075 } 4106 }
4076 4107
4077 #endregion Packet Sending 4108 #endregion Packet Sending
@@ -4364,11 +4395,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4364 4395
4365 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4396 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4366 // of the object rather than the properties when the packet was created 4397 // of the object rather than the properties when the packet was created
4367 OutPacket(packet, ThrottleOutPacketType.Task, true, 4398 // HACK : Remove intelligent resending until it's fixed in core
4368 delegate(OutgoingPacket oPacket) 4399 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4369 { 4400 // delegate(OutgoingPacket oPacket)
4370 ResendPropertyUpdates(updates, oPacket); 4401 // {
4371 }); 4402 // ResendPropertyUpdates(updates, oPacket);
4403 // });
4404 OutPacket(packet, ThrottleOutPacketType.Task, true);
4372 4405
4373 // pbcnt += blocks.Count; 4406 // pbcnt += blocks.Count;
4374 // ppcnt++; 4407 // ppcnt++;
@@ -4394,11 +4427,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4394 // of the object rather than the properties when the packet was created 4427 // of the object rather than the properties when the packet was created
4395 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4428 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4396 updates.Add(familyUpdates.Value[i]); 4429 updates.Add(familyUpdates.Value[i]);
4397 OutPacket(packet, ThrottleOutPacketType.Task, true, 4430 // HACK : Remove intelligent resending until it's fixed in core
4398 delegate(OutgoingPacket oPacket) 4431 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4399 { 4432 // delegate(OutgoingPacket oPacket)
4400 ResendPropertyUpdates(updates, oPacket); 4433 // {
4401 }); 4434 // ResendPropertyUpdates(updates, oPacket);
4435 // });
4436 OutPacket(packet, ThrottleOutPacketType.Task, true);
4402 4437
4403 // fpcnt++; 4438 // fpcnt++;
4404 // fbcnt++; 4439 // fbcnt++;
@@ -4770,7 +4805,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4770 4805
4771 if (landData.SimwideArea > 0) 4806 if (landData.SimwideArea > 0)
4772 { 4807 {
4773 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4808 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4809 // Never report more than sim total capacity
4810 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4811 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4774 updateMessage.SimWideMaxPrims = simulatorCapacity; 4812 updateMessage.SimWideMaxPrims = simulatorCapacity;
4775 } 4813 }
4776 else 4814 else
@@ -4899,14 +4937,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4899 4937
4900 if (notifyCount > 0) 4938 if (notifyCount > 0)
4901 { 4939 {
4902 if (notifyCount > 32) 4940// if (notifyCount > 32)
4903 { 4941// {
4904 m_log.InfoFormat( 4942// m_log.InfoFormat(
4905 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4943// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4906 + " - a developer might want to investigate whether this is a hard limit", 32); 4944// + " - a developer might want to investigate whether this is a hard limit", 32);
4907 4945//
4908 notifyCount = 32; 4946// notifyCount = 32;
4909 } 4947// }
4910 4948
4911 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4949 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4912 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4950 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4961,9 +4999,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4961 { 4999 {
4962 ScenePresence presence = (ScenePresence)entity; 5000 ScenePresence presence = (ScenePresence)entity;
4963 5001
5002 position = presence.OffsetPosition;
5003 rotation = presence.Rotation;
5004
5005 if (presence.ParentID != 0)
5006 {
5007 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
5008 if (part != null && part != part.ParentGroup.RootPart)
5009 {
5010 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
5011 rotation = part.RotationOffset * presence.Rotation;
5012 }
5013 angularVelocity = Vector3.Zero;
5014 }
5015 else
5016 {
5017 angularVelocity = presence.AngularVelocity;
5018 rotation = presence.Rotation;
5019 }
5020
4964 attachPoint = 0; 5021 attachPoint = 0;
4965 collisionPlane = presence.CollisionPlane; 5022 collisionPlane = presence.CollisionPlane;
4966 position = presence.OffsetPosition;
4967 velocity = presence.Velocity; 5023 velocity = presence.Velocity;
4968 acceleration = Vector3.Zero; 5024 acceleration = Vector3.Zero;
4969 5025
@@ -4972,9 +5028,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4972 // may improve movement smoothness. 5028 // may improve movement smoothness.
4973// acceleration = new Vector3(1, 0, 0); 5029// acceleration = new Vector3(1, 0, 0);
4974 5030
4975 angularVelocity = presence.AngularVelocity;
4976 rotation = presence.Rotation;
4977
4978 if (sendTexture) 5031 if (sendTexture)
4979 textureEntry = presence.Appearance.Texture.GetBytes(); 5032 textureEntry = presence.Appearance.Texture.GetBytes();
4980 else 5033 else
@@ -5080,13 +5133,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5080 5133
5081 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5134 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5082 { 5135 {
5136 Vector3 offsetPosition = data.OffsetPosition;
5137 Quaternion rotation = data.Rotation;
5138 uint parentID = data.ParentID;
5139
5140 if (parentID != 0)
5141 {
5142 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5143 if (part != null && part != part.ParentGroup.RootPart)
5144 {
5145 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5146 rotation = part.RotationOffset * data.Rotation;
5147 parentID = part.ParentGroup.RootPart.LocalId;
5148 }
5149 }
5150
5083 byte[] objectData = new byte[76]; 5151 byte[] objectData = new byte[76];
5084 5152
5085 data.CollisionPlane.ToBytes(objectData, 0); 5153 data.CollisionPlane.ToBytes(objectData, 0);
5086 data.OffsetPosition.ToBytes(objectData, 16); 5154 offsetPosition.ToBytes(objectData, 16);
5155 Vector3 velocity = new Vector3(0, 0, 0);
5156 Vector3 acceleration = new Vector3(0, 0, 0);
5157 velocity.ToBytes(objectData, 28);
5158 acceleration.ToBytes(objectData, 40);
5087// data.Velocity.ToBytes(objectData, 28); 5159// data.Velocity.ToBytes(objectData, 28);
5088// data.Acceleration.ToBytes(objectData, 40); 5160// data.Acceleration.ToBytes(objectData, 40);
5089 data.Rotation.ToBytes(objectData, 52); 5161 rotation.ToBytes(objectData, 52);
5090 //data.AngularVelocity.ToBytes(objectData, 64); 5162 //data.AngularVelocity.ToBytes(objectData, 64);
5091 5163
5092 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5164 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5100,14 +5172,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5100 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5172 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5101 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5173 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5102 update.ObjectData = objectData; 5174 update.ObjectData = objectData;
5103 update.ParentID = data.ParentID; 5175 update.ParentID = parentID;
5104 update.PathCurve = 16; 5176 update.PathCurve = 16;
5105 update.PathScaleX = 100; 5177 update.PathScaleX = 100;
5106 update.PathScaleY = 100; 5178 update.PathScaleY = 100;
5107 update.PCode = (byte)PCode.Avatar; 5179 update.PCode = (byte)PCode.Avatar;
5108 update.ProfileCurve = 1; 5180 update.ProfileCurve = 1;
5109 update.PSBlock = Utils.EmptyBytes; 5181 update.PSBlock = Utils.EmptyBytes;
5110 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5182 update.Scale = data.Appearance.AvatarSize;
5183// update.Scale.Z -= 0.2f;
5184
5111 update.Text = Utils.EmptyBytes; 5185 update.Text = Utils.EmptyBytes;
5112 update.TextColor = new byte[4]; 5186 update.TextColor = new byte[4];
5113 5187
@@ -5118,10 +5192,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5118 update.TextureEntry = Utils.EmptyBytes; 5192 update.TextureEntry = Utils.EmptyBytes;
5119// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5193// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5120 5194
5195/* 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)
5121 update.UpdateFlags = (uint)( 5196 update.UpdateFlags = (uint)(
5122 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5197 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5123 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5198 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5124 PrimFlags.ObjectOwnerModify); 5199 PrimFlags.ObjectOwnerModify);
5200*/
5201 update.UpdateFlags = 0;
5125 5202
5126 return update; 5203 return update;
5127 } 5204 }
@@ -5292,8 +5369,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5292 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5369 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5293 // for each AgentUpdate packet. 5370 // for each AgentUpdate packet.
5294 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5371 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5295 5372
5296 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5373 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5374 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5375 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5297 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5376 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5298 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5377 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5299 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5378 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5445,6 +5524,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5445 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5524 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5446 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5525 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5447 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5526 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5527 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5448 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5528 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5449 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5529 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5450 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5530 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5511,6 +5591,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5511 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5591 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5512 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5592 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5513 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5593 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5594 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5514 5595
5515 AddGenericPacketHandler("autopilot", HandleAutopilot); 5596 AddGenericPacketHandler("autopilot", HandleAutopilot);
5516 } 5597 }
@@ -5549,6 +5630,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5549 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || 5630 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5550 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || 5631 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5551 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || 5632 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5633 (x.ControlFlags != 0) ||
5552 (x.Far != m_lastAgentUpdateArgs.Far) || 5634 (x.Far != m_lastAgentUpdateArgs.Far) ||
5553 (x.Flags != m_lastAgentUpdateArgs.Flags) || 5635 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5554 (x.State != m_lastAgentUpdateArgs.State) || 5636 (x.State != m_lastAgentUpdateArgs.State) ||
@@ -5808,6 +5890,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5808 return true; 5890 return true;
5809 } 5891 }
5810 5892
5893 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
5894 {
5895 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
5896 if (p.AgentData.SessionID != SessionId ||
5897 p.AgentData.AgentID != AgentId)
5898 return true;
5899
5900 m_VelocityInterpolate = false;
5901 return true;
5902 }
5903
5904 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
5905 {
5906 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
5907 if (p.AgentData.SessionID != SessionId ||
5908 p.AgentData.AgentID != AgentId)
5909 return true;
5910
5911 m_VelocityInterpolate = true;
5912 return true;
5913 }
5914
5915
5811 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 5916 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5812 { 5917 {
5813 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 5918 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6228,26 +6333,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6228 // Temporarily protect ourselves from the mantis #951 failure. 6333 // Temporarily protect ourselves from the mantis #951 failure.
6229 // However, we could do this for several other handlers where a failure isn't terminal 6334 // However, we could do this for several other handlers where a failure isn't terminal
6230 // for the client session anyway, in order to protect ourselves against bad code in plugins 6335 // for the client session anyway, in order to protect ourselves against bad code in plugins
6336 Vector3 avSize = appear.AgentData.Size;
6231 try 6337 try
6232 { 6338 {
6233 byte[] visualparams = new byte[appear.VisualParam.Length]; 6339 byte[] visualparams = new byte[appear.VisualParam.Length];
6234 for (int i = 0; i < appear.VisualParam.Length; i++) 6340 for (int i = 0; i < appear.VisualParam.Length; i++)
6235 visualparams[i] = appear.VisualParam[i].ParamValue; 6341 visualparams[i] = appear.VisualParam[i].ParamValue;
6236 6342 //var b = appear.WearableData[0];
6343
6237 Primitive.TextureEntry te = null; 6344 Primitive.TextureEntry te = null;
6238 if (appear.ObjectData.TextureEntry.Length > 1) 6345 if (appear.ObjectData.TextureEntry.Length > 1)
6239 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6346 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6347
6348 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6349 for (int i=0; i<appear.WearableData.Length;i++)
6350 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6240 6351
6241 List<CachedTextureRequestArg> hashes = new List<CachedTextureRequestArg>(); 6352
6242 for (int i = 0; i < appear.WearableData.Length; i++)
6243 {
6244 CachedTextureRequestArg arg = new CachedTextureRequestArg();
6245 arg.BakedTextureIndex = appear.WearableData[i].TextureIndex;
6246 arg.WearableHashID = appear.WearableData[i].CacheID;
6247 hashes.Add(arg);
6248 }
6249 6353
6250 handlerSetAppearance(sender, te, visualparams, hashes); 6354 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6251 } 6355 }
6252 catch (Exception e) 6356 catch (Exception e)
6253 { 6357 {
@@ -6456,6 +6560,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6456 { 6560 {
6457 handlerCompleteMovementToRegion(sender, true); 6561 handlerCompleteMovementToRegion(sender, true);
6458 } 6562 }
6563 else
6564 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6565
6459 handlerCompleteMovementToRegion = null; 6566 handlerCompleteMovementToRegion = null;
6460 6567
6461 return true; 6568 return true;
@@ -6473,7 +6580,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6473 return true; 6580 return true;
6474 } 6581 }
6475 #endregion 6582 #endregion
6476 6583/*
6477 StartAnim handlerStartAnim = null; 6584 StartAnim handlerStartAnim = null;
6478 StopAnim handlerStopAnim = null; 6585 StopAnim handlerStopAnim = null;
6479 6586
@@ -6497,6 +6604,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6497 } 6604 }
6498 } 6605 }
6499 return true; 6606 return true;
6607*/
6608 ChangeAnim handlerChangeAnim = null;
6609
6610 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6611 {
6612 handlerChangeAnim = OnChangeAnim;
6613 if (handlerChangeAnim != null)
6614 {
6615 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6616 }
6617 }
6618
6619 handlerChangeAnim = OnChangeAnim;
6620 if (handlerChangeAnim != null)
6621 {
6622 handlerChangeAnim(UUID.Zero, false, true);
6623 }
6624
6625 return true;
6500 } 6626 }
6501 6627
6502 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6628 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6722,6 +6848,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6722 #endregion 6848 #endregion
6723 6849
6724 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6850 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6851 GenericCall2 handler = OnUpdateThrottles;
6852 if (handler != null)
6853 {
6854 handler();
6855 }
6725 return true; 6856 return true;
6726 } 6857 }
6727 6858
@@ -7146,7 +7277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7146 physdata.Bounce = phsblock.Restitution; 7277 physdata.Bounce = phsblock.Restitution;
7147 physdata.Density = phsblock.Density; 7278 physdata.Density = phsblock.Density;
7148 physdata.Friction = phsblock.Friction; 7279 physdata.Friction = phsblock.Friction;
7149 physdata.GravitationModifier = phsblock.GravityMultiplier; 7280 physdata.GravitationModifier = phsblock.GravityMultiplier;
7150 } 7281 }
7151 7282
7152 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7283 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7732,6 +7863,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7732 // surrounding scene 7863 // surrounding scene
7733 if ((ImageType)block.Type == ImageType.Baked) 7864 if ((ImageType)block.Type == ImageType.Baked)
7734 args.Priority *= 2.0f; 7865 args.Priority *= 2.0f;
7866 int wearableout = 0;
7735 7867
7736 ImageManager.EnqueueReq(args); 7868 ImageManager.EnqueueReq(args);
7737 } 7869 }
@@ -8766,16 +8898,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8766 8898
8767 #region Parcel related packets 8899 #region Parcel related packets
8768 8900
8901 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
8902 // to be done with minimal resources as possible
8903 // variables temporary here while in test
8904
8905 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
8906 bool RegionHandleRequestsInService = false;
8907
8769 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 8908 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8770 { 8909 {
8771 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 8910 UUID currentUUID;
8772 8911
8773 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 8912 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8774 if (handlerRegionHandleRequest != null) 8913
8914 if (handlerRegionHandleRequest == null)
8915 return true;
8916
8917 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
8918
8919 lock (RegionHandleRequests)
8775 { 8920 {
8776 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 8921 if (RegionHandleRequestsInService)
8922 {
8923 // we are already busy doing a previus request
8924 // so enqueue it
8925 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
8926 return true;
8927 }
8928
8929 // else do it
8930 currentUUID = rhrPack.RequestBlock.RegionID;
8931 RegionHandleRequestsInService = true;
8777 } 8932 }
8778 return true; 8933
8934 while (true)
8935 {
8936 handlerRegionHandleRequest(this, currentUUID);
8937
8938 lock (RegionHandleRequests)
8939 {
8940 // exit condition, nothing to do or closed
8941 // current code seems to assume we may loose the handler at anytime,
8942 // so keep checking it
8943 handlerRegionHandleRequest = OnRegionHandleRequest;
8944
8945 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
8946 {
8947 RegionHandleRequests.Clear();
8948 RegionHandleRequestsInService = false;
8949 return true;
8950 }
8951 currentUUID = RegionHandleRequests.Dequeue();
8952 }
8953 }
8954
8955 return true; // actually unreached
8779 } 8956 }
8780 8957
8781 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 8958 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -10031,7 +10208,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10031 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10208 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
10032 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10209 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
10033 UpdateMuteListEntry.MuteData.MuteType, 10210 UpdateMuteListEntry.MuteData.MuteType,
10034 UpdateMuteListEntry.AgentData.AgentID); 10211 UpdateMuteListEntry.MuteData.MuteFlags);
10035 return true; 10212 return true;
10036 } 10213 }
10037 return false; 10214 return false;
@@ -10046,8 +10223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10046 { 10223 {
10047 handlerRemoveMuteListEntry(this, 10224 handlerRemoveMuteListEntry(this,
10048 RemoveMuteListEntry.MuteData.MuteID, 10225 RemoveMuteListEntry.MuteData.MuteID,
10049 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10226 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
10050 RemoveMuteListEntry.AgentData.AgentID);
10051 return true; 10227 return true;
10052 } 10228 }
10053 return false; 10229 return false;
@@ -10091,10 +10267,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10091 return false; 10267 return false;
10092 } 10268 }
10093 10269
10270 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10271 {
10272 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10273 (ChangeInventoryItemFlagsPacket)packet;
10274 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10275 if (handlerChangeInventoryItemFlags != null)
10276 {
10277 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10278 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10279 return true;
10280 }
10281 return false;
10282 }
10283
10094 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10284 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10095 { 10285 {
10096 return true; 10286 return true;
10097 } 10287 }
10288
10289 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10290 {
10291 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10292
10293 #region Packet Session and User Check
10294 if (m_checkPackets)
10295 {
10296 if (packet.AgentData.SessionID != SessionId ||
10297 packet.AgentData.AgentID != AgentId)
10298 return true;
10299 }
10300 #endregion
10301 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10302 List<InventoryItemBase> items = new List<InventoryItemBase>();
10303 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10304 {
10305 InventoryItemBase b = new InventoryItemBase();
10306 b.ID = n.OldItemID;
10307 b.Folder = n.OldFolderID;
10308 items.Add(b);
10309 }
10310
10311 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10312 if (handlerMoveItemsAndLeaveCopy != null)
10313 {
10314 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10315 }
10316
10317 return true;
10318 }
10098 10319
10099 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10320 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10100 { 10321 {
@@ -10521,6 +10742,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10521 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10742 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10522 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10743 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10523 10744
10745 Scene scene = (Scene)m_scene;
10746 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10747 {
10748 ScenePresence p;
10749 if (scene.TryGetScenePresence(sender.AgentId, out p))
10750 {
10751 if (p.GodLevel >= 200)
10752 {
10753 groupProfileReply.GroupData.OpenEnrollment = true;
10754 groupProfileReply.GroupData.MembershipFee = 0;
10755 }
10756 }
10757 }
10758
10524 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10759 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10525 } 10760 }
10526 return true; 10761 return true;
@@ -11094,11 +11329,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11094 11329
11095 StartLure handlerStartLure = OnStartLure; 11330 StartLure handlerStartLure = OnStartLure;
11096 if (handlerStartLure != null) 11331 if (handlerStartLure != null)
11097 handlerStartLure(startLureRequest.Info.LureType, 11332 {
11098 Utils.BytesToString( 11333 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11099 startLureRequest.Info.Message), 11334 {
11100 startLureRequest.TargetData[0].TargetID, 11335 handlerStartLure(startLureRequest.Info.LureType,
11101 this); 11336 Utils.BytesToString(
11337 startLureRequest.Info.Message),
11338 startLureRequest.TargetData[i].TargetID,
11339 this);
11340 }
11341 }
11102 return true; 11342 return true;
11103 } 11343 }
11104 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11344 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11212,10 +11452,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11212 } 11452 }
11213 #endregion 11453 #endregion
11214 11454
11215 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11455 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11216 if (handlerClassifiedGodDelete != null) 11456 if (handlerClassifiedGodDelete != null)
11217 handlerClassifiedGodDelete( 11457 handlerClassifiedGodDelete(
11218 classifiedGodDelete.Data.ClassifiedID, 11458 classifiedGodDelete.Data.ClassifiedID,
11459 classifiedGodDelete.Data.QueryID,
11219 this); 11460 this);
11220 return true; 11461 return true;
11221 } 11462 }
@@ -11518,12 +11759,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11518 /// <param name="simclient"></param> 11759 /// <param name="simclient"></param>
11519 /// <param name="packet"></param> 11760 /// <param name="packet"></param>
11520 /// <returns></returns> 11761 /// <returns></returns>
11521 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) 11762 // TODO: Convert old handler to use new method
11763 /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11522 { 11764 {
11523 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; 11765 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11524 11766
11525 if (cachedtex.AgentData.SessionID != SessionId) 11767 if (cachedtex.AgentData.SessionID != SessionId)
11526 return false; 11768 return false;
11769
11527 11770
11528 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); 11771 List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
11529 11772
@@ -11536,23 +11779,173 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11536 requestArgs.Add(arg); 11779 requestArgs.Add(arg);
11537 } 11780 }
11538 11781
11539 try 11782 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
11783 if (handlerCachedTextureRequest != null)
11540 { 11784 {
11541 CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; 11785 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
11542 if (handlerCachedTextureRequest != null) 11786 }
11787
11788 return true;
11789 }*/
11790
11791 protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
11792 {
11793 //m_log.Debug("texture cached: " + packet.ToString());
11794 AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
11795 AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
11796
11797 if (cachedtex.AgentData.SessionID != SessionId)
11798 return false;
11799
11800
11801 // TODO: don't create new blocks if recycling an old packet
11802 cachedresp.AgentData.AgentID = AgentId;
11803 cachedresp.AgentData.SessionID = m_sessionId;
11804 cachedresp.AgentData.SerialNum = m_cachedTextureSerial;
11805 m_cachedTextureSerial++;
11806 cachedresp.WearableData =
11807 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11808
11809 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11810 // var item = fac.GetBakedTextureFaces(AgentId);
11811 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11812
11813 IAssetService cache = m_scene.AssetService;
11814 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11815 //bakedTextureModule = null;
11816 int maxWearablesLoop = cachedtex.WearableData.Length;
11817 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11818 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11819
11820 if (bakedTextureModule != null && cache != null)
11821 {
11822 // 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
11823
11824 WearableCacheItem[] cacheItems = null;
11825 ScenePresence p = m_scene.GetScenePresence(AgentId);
11826 if (p.Appearance != null)
11827 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11828 {
11829 try
11830 {
11831 cacheItems = bakedTextureModule.Get(AgentId);
11832 p.Appearance.WearableCacheItems = cacheItems;
11833 p.Appearance.WearableCacheItemsDirty = false;
11834 }
11835
11836 /*
11837 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11838 *
11839 catch (System.Net.Sockets.SocketException)
11840 {
11841 cacheItems = null;
11842 }
11843 catch (WebException)
11844 {
11845 cacheItems = null;
11846 }
11847 catch (InvalidOperationException)
11848 {
11849 cacheItems = null;
11850 } */
11851 catch (Exception)
11852 {
11853 cacheItems = null;
11854 }
11855
11856 }
11857 else if (p.Appearance.WearableCacheItems != null)
11858 {
11859 cacheItems = p.Appearance.WearableCacheItems;
11860 }
11861
11862 if (cache != null && cacheItems != null)
11543 { 11863 {
11544 handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); 11864 foreach (WearableCacheItem item in cacheItems)
11865 {
11866
11867 if (cache.GetCached(item.TextureID.ToString()) == null)
11868 {
11869 item.TextureAsset.Temporary = true;
11870 cache.Store(item.TextureAsset);
11871 }
11872
11873
11874 }
11875 }
11876
11877 if (cacheItems != null)
11878 {
11879
11880 for (int i = 0; i < maxWearablesLoop; i++)
11881 {
11882 WearableCacheItem item =
11883 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11884
11885 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11886 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
11887 cachedresp.WearableData[i].HostName = new byte[0];
11888 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11889 {
11890
11891 cachedresp.WearableData[i].TextureID = item.TextureID;
11892 }
11893 else
11894 {
11895 cachedresp.WearableData[i].TextureID = UUID.Zero;
11896 }
11897 }
11898 }
11899 else
11900 {
11901 for (int i = 0; i < maxWearablesLoop; i++)
11902 {
11903 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11904 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11905 cachedresp.WearableData[i].TextureID = UUID.Zero;
11906 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11907 cachedresp.WearableData[i].HostName = new byte[0];
11908 }
11545 } 11909 }
11546 } 11910 }
11547 catch (Exception e) 11911 else
11548 { 11912 {
11549 m_log.ErrorFormat("[CLIENT VIEW]: AgentTextureCached packet handler threw an exception, {0}", e); 11913 if (cache == null)
11550 return false; 11914 {
11915 for (int i = 0; i < maxWearablesLoop; i++)
11916 {
11917 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11918 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11919 cachedresp.WearableData[i].TextureID = UUID.Zero;
11920 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11921 cachedresp.WearableData[i].HostName = new byte[0];
11922 }
11923 }
11924 else
11925 {
11926 for (int i = 0; i < maxWearablesLoop; i++)
11927 {
11928 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11929 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11930
11931
11932
11933 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11934 cachedresp.WearableData[i].TextureID = UUID.Zero;
11935 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11936 else
11937 cachedresp.WearableData[i].TextureID = UUID.Zero;
11938 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11939 cachedresp.WearableData[i].HostName = new byte[0];
11940 }
11941 }
11551 } 11942 }
11552 11943 cachedresp.Header.Zerocoded = true;
11944 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11945
11553 return true; 11946 return true;
11554 } 11947 }
11555 11948
11556 /// <summary> 11949 /// <summary>
11557 /// Send a response back to a client when it asks the asset server (via the region server) if it has 11950 /// Send a response back to a client when it asks the asset server (via the region server) if it has
11558 /// its appearance texture cached. 11951 /// its appearance texture cached.
@@ -11616,209 +12009,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11616 } 12009 }
11617 else 12010 else
11618 { 12011 {
11619// m_log.DebugFormat( 12012 ClientChangeObject updatehandler = onClientChangeObject;
11620// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11621// i, block.Type, part.Name, part.LocalId);
11622 12013
11623// // Do this once since fetch parts creates a new array. 12014 if (updatehandler != null)
11624// SceneObjectPart[] parts = part.ParentGroup.Parts; 12015 {
11625// for (int j = 0; j < parts.Length; j++) 12016 ObjectChangeData udata = new ObjectChangeData();
11626// {
11627// part.StoreUndoState();
11628// parts[j].IgnoreUndoUpdate = true;
11629// }
11630 12017
11631 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 12018 /*ubit from ll JIRA:
12019 * 0x01 position
12020 * 0x02 rotation
12021 * 0x04 scale
12022
12023 * 0x08 LINK_SET
12024 * 0x10 UNIFORM for scale
12025 */
11632 12026
11633 switch (block.Type) 12027 // translate to internal changes
11634 { 12028 // not all cases .. just the ones older code did
11635 case 1:
11636 Vector3 pos1 = new Vector3(block.Data, 0);
11637 12029
11638 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12030 switch (block.Type)
11639 if (handlerUpdatePrimSinglePosition != null) 12031 {
11640 { 12032 case 1: //change position sp
11641 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12033 udata.position = new Vector3(block.Data, 0);
11642 handlerUpdatePrimSinglePosition(localId, pos1, this);
11643 }
11644 break;
11645 12034
11646 case 2: 12035 udata.change = ObjectChangeType.primP;
11647 Quaternion rot1 = new Quaternion(block.Data, 0, true); 12036 updatehandler(localId, udata, this);
12037 break;
11648 12038
11649 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 12039 case 2: // rotation sp
11650 if (handlerUpdatePrimSingleRotation != null) 12040 udata.rotation = new Quaternion(block.Data, 0, true);
11651 {
11652 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11653 handlerUpdatePrimSingleRotation(localId, rot1, this);
11654 }
11655 break;
11656 12041
11657 case 3: 12042 udata.change = ObjectChangeType.primR;
11658 Vector3 rotPos = new Vector3(block.Data, 0); 12043 updatehandler(localId, udata, this);
11659 Quaternion rot2 = new Quaternion(block.Data, 12, true); 12044 break;
11660 12045
11661 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 12046 case 3: // position plus rotation
11662 if (handlerUpdatePrimSingleRotationPosition != null) 12047 udata.position = new Vector3(block.Data, 0);
11663 { 12048 udata.rotation = new Quaternion(block.Data, 12, true);
11664 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11665 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11666 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11667 }
11668 break;
11669 12049
11670 case 4: 12050 udata.change = ObjectChangeType.primPR;
11671 case 20: 12051 updatehandler(localId, udata, this);
11672 Vector3 scale4 = new Vector3(block.Data, 0); 12052 break;
11673 12053
11674 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 12054 case 4: // scale sp
11675 if (handlerUpdatePrimScale != null) 12055 udata.scale = new Vector3(block.Data, 0);
11676 { 12056 udata.change = ObjectChangeType.primS;
11677 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11678 handlerUpdatePrimScale(localId, scale4, this);
11679 }
11680 break;
11681 12057
11682 case 5: 12058 updatehandler(localId, udata, this);
11683 Vector3 scale1 = new Vector3(block.Data, 12); 12059 break;
11684 Vector3 pos11 = new Vector3(block.Data, 0);
11685 12060
11686 handlerUpdatePrimScale = OnUpdatePrimScale; 12061 case 0x14: // uniform scale sp
11687 if (handlerUpdatePrimScale != null) 12062 udata.scale = new Vector3(block.Data, 0);
11688 {
11689 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11690 handlerUpdatePrimScale(localId, scale1, this);
11691 12063
11692 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12064 udata.change = ObjectChangeType.primUS;
11693 if (handlerUpdatePrimSinglePosition != null) 12065 updatehandler(localId, udata, this);
11694 { 12066 break;
11695 handlerUpdatePrimSinglePosition(localId, pos11, this);
11696 }
11697 }
11698 break;
11699 12067
11700 case 9: 12068 case 5: // scale and position sp
11701 Vector3 pos2 = new Vector3(block.Data, 0); 12069 udata.position = new Vector3(block.Data, 0);
12070 udata.scale = new Vector3(block.Data, 12);
11702 12071
11703 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 12072 udata.change = ObjectChangeType.primPS;
12073 updatehandler(localId, udata, this);
12074 break;
11704 12075
11705 if (handlerUpdateVector != null) 12076 case 0x15: //uniform scale and position
11706 { 12077 udata.position = new Vector3(block.Data, 0);
11707 handlerUpdateVector(localId, pos2, this); 12078 udata.scale = new Vector3(block.Data, 12);
11708 }
11709 break;
11710 12079
11711 case 10: 12080 udata.change = ObjectChangeType.primPUS;
11712 Quaternion rot3 = new Quaternion(block.Data, 0, true); 12081 updatehandler(localId, udata, this);
12082 break;
11713 12083
11714 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 12084 // now group related (bit 4)
11715 if (handlerUpdatePrimRotation != null) 12085 case 9: //( 8 + 1 )group position
11716 { 12086 udata.position = new Vector3(block.Data, 0);
11717 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11718 handlerUpdatePrimRotation(localId, rot3, this);
11719 }
11720 break;
11721 12087
11722 case 11: 12088 udata.change = ObjectChangeType.groupP;
11723 Vector3 pos3 = new Vector3(block.Data, 0); 12089 updatehandler(localId, udata, this);
11724 Quaternion rot4 = new Quaternion(block.Data, 12, true); 12090 break;
11725 12091
11726 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 12092 case 0x0A: // (8 + 2) group rotation
11727 if (handlerUpdatePrimGroupRotation != null) 12093 udata.rotation = new Quaternion(block.Data, 0, true);
11728 {
11729 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11730 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11731 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11732 }
11733 break;
11734 case 12:
11735 case 28:
11736 Vector3 scale7 = new Vector3(block.Data, 0);
11737 12094
11738 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12095 udata.change = ObjectChangeType.groupR;
11739 if (handlerUpdatePrimGroupScale != null) 12096 updatehandler(localId, udata, this);
11740 { 12097 break;
11741 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11742 handlerUpdatePrimGroupScale(localId, scale7, this);
11743 }
11744 break;
11745 12098
11746 case 13: 12099 case 0x0B: //( 8 + 2 + 1) group rotation and position
11747 Vector3 scale2 = new Vector3(block.Data, 12); 12100 udata.position = new Vector3(block.Data, 0);
11748 Vector3 pos4 = new Vector3(block.Data, 0); 12101 udata.rotation = new Quaternion(block.Data, 12, true);
11749 12102
11750 handlerUpdatePrimScale = OnUpdatePrimScale; 12103 udata.change = ObjectChangeType.groupPR;
11751 if (handlerUpdatePrimScale != null) 12104 updatehandler(localId, udata, this);
11752 { 12105 break;
11753 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11754 handlerUpdatePrimScale(localId, scale2, this);
11755 12106
11756 // Change the position based on scale (for bug number 246) 12107 case 0x0C: // (8 + 4) group scale
11757 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12108 // only afects root prim and only sent by viewer editor object tab scaling
11758 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 12109 // mouse edition only allows uniform scaling
11759 if (handlerUpdatePrimSinglePosition != null) 12110 // SL MAY CHANGE THIS in viewers
11760 {
11761 handlerUpdatePrimSinglePosition(localId, pos4, this);
11762 }
11763 }
11764 break;
11765 12111
11766 case 29: 12112 udata.scale = new Vector3(block.Data, 0);
11767 Vector3 scale5 = new Vector3(block.Data, 12);
11768 Vector3 pos5 = new Vector3(block.Data, 0);
11769 12113
11770 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 12114 udata.change = ObjectChangeType.groupS;
11771 if (handlerUpdatePrimGroupScale != null) 12115 updatehandler(localId, udata, this);
11772 {
11773 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11774 part.StoreUndoState(true);
11775 part.IgnoreUndoUpdate = true;
11776 handlerUpdatePrimGroupScale(localId, scale5, this);
11777 handlerUpdateVector = OnUpdatePrimGroupPosition;
11778 12116
11779 if (handlerUpdateVector != null) 12117 break;
11780 {
11781 handlerUpdateVector(localId, pos5, this);
11782 }
11783 12118
11784 part.IgnoreUndoUpdate = false; 12119 case 0x0D: //(8 + 4 + 1) group scale and position
11785 } 12120 // exception as above
11786 12121
11787 break; 12122 udata.position = new Vector3(block.Data, 0);
12123 udata.scale = new Vector3(block.Data, 12);
11788 12124
11789 case 21: 12125 udata.change = ObjectChangeType.groupPS;
11790 Vector3 scale6 = new Vector3(block.Data, 12); 12126 updatehandler(localId, udata, this);
11791 Vector3 pos6 = new Vector3(block.Data, 0); 12127 break;
11792 12128
11793 handlerUpdatePrimScale = OnUpdatePrimScale; 12129 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11794 if (handlerUpdatePrimScale != null) 12130 udata.scale = new Vector3(block.Data, 0);
11795 {
11796 part.StoreUndoState(false);
11797 part.IgnoreUndoUpdate = true;
11798 12131
11799 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12132 udata.change = ObjectChangeType.groupUS;
11800 handlerUpdatePrimScale(localId, scale6, this); 12133 updatehandler(localId, udata, this);
11801 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12134 break;
11802 if (handlerUpdatePrimSinglePosition != null)
11803 {
11804 handlerUpdatePrimSinglePosition(localId, pos6, this);
11805 }
11806 12135
11807 part.IgnoreUndoUpdate = false; 12136 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11808 } 12137 udata.position = new Vector3(block.Data, 0);
11809 break; 12138 udata.scale = new Vector3(block.Data, 12);
11810 12139
11811 default: 12140 udata.change = ObjectChangeType.groupPUS;
11812 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12141 updatehandler(localId, udata, this);
11813 break; 12142 break;
12143
12144 default:
12145 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12146 break;
12147 }
11814 } 12148 }
11815 12149
11816// for (int j = 0; j < parts.Length; j++)
11817// parts[j].IgnoreUndoUpdate = false;
11818 } 12150 }
11819 } 12151 }
11820 } 12152 }
11821
11822 return true; 12153 return true;
11823 } 12154 }
11824 12155
@@ -11879,9 +12210,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11879 public void SetChildAgentThrottle(byte[] throttles) 12210 public void SetChildAgentThrottle(byte[] throttles)
11880 { 12211 {
11881 m_udpClient.SetThrottles(throttles); 12212 m_udpClient.SetThrottles(throttles);
12213 GenericCall2 handler = OnUpdateThrottles;
12214 if (handler != null)
12215 {
12216 handler();
12217 }
11882 } 12218 }
11883 12219
11884 /// <summary> 12220 /// <summary>
12221 /// Sets the throttles from values supplied by the client
12222 /// </summary>
12223 /// <param name="throttles"></param>
12224 public void SetAgentThrottleSilent(int throttle, int setting)
12225 {
12226 m_udpClient.ForceThrottleSetting(throttle,setting);
12227 //m_udpClient.SetThrottles(throttles);
12228
12229 }
12230
12231
12232 /// <summary>
11885 /// Get the current throttles for this client as a packed byte array 12233 /// Get the current throttles for this client as a packed byte array
11886 /// </summary> 12234 /// </summary>
11887 /// <param name="multiplier">Unused</param> 12235 /// <param name="multiplier">Unused</param>
@@ -12263,7 +12611,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12263// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12611// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12264// requestID, taskID, (SourceType)sourceType, Name); 12612// requestID, taskID, (SourceType)sourceType, Name);
12265 12613
12614
12615 //Note, the bool returned from the below function is useless since it is always false.
12266 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12616 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12617
12267 } 12618 }
12268 12619
12269 /// <summary> 12620 /// <summary>
@@ -12329,7 +12680,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12329 /// <returns></returns> 12680 /// <returns></returns>
12330 private static int CalculateNumPackets(byte[] data) 12681 private static int CalculateNumPackets(byte[] data)
12331 { 12682 {
12332 const uint m_maxPacketSize = 600; 12683// const uint m_maxPacketSize = 600;
12684 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12333 int numPackets = 1; 12685 int numPackets = 1;
12334 12686
12335 if (data == null) 12687 if (data == null)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 7749446..f7ed14d 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 private ClientInfo m_info = new ClientInfo(); 163 private ClientInfo m_info = new ClientInfo();
163 164
@@ -203,7 +204,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
203 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 204 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
204 205
205 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 206 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
206 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 207 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
207 // Initialize the token buckets that control the throttling for each category 208 // Initialize the token buckets that control the throttling for each category
208 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); 209 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
209 } 210 }
@@ -428,11 +429,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
428 /// </returns> 429 /// </returns>
429 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) 430 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
430 { 431 {
432 return EnqueueOutgoing(packet, forceQueue, false);
433 }
434
435 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
436 {
431 int category = (int)packet.Category; 437 int category = (int)packet.Category;
432 438
433 if (category >= 0 && category < m_packetOutboxes.Length) 439 if (category >= 0 && category < m_packetOutboxes.Length)
434 { 440 {
435 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 441 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
442
443 if (m_deliverPackets == false)
444 {
445 queue.Enqueue(packet, highPriority);
446 return true;
447 }
448
436 TokenBucket bucket = m_throttleCategories[category]; 449 TokenBucket bucket = m_throttleCategories[category];
437 450
438 // Don't send this packet if there is already a packet waiting in the queue 451 // Don't send this packet if there is already a packet waiting in the queue
@@ -440,7 +453,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
440 // queued packets 453 // queued packets
441 if (queue.Count > 0) 454 if (queue.Count > 0)
442 { 455 {
443 queue.Enqueue(packet); 456 queue.Enqueue(packet, highPriority);
444 return true; 457 return true;
445 } 458 }
446 459
@@ -453,7 +466,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
453 else 466 else
454 { 467 {
455 // Force queue specified or not enough tokens in the bucket, queue this packet 468 // Force queue specified or not enough tokens in the bucket, queue this packet
456 queue.Enqueue(packet); 469 queue.Enqueue(packet, highPriority);
457 return true; 470 return true;
458 } 471 }
459 } 472 }
@@ -482,8 +495,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
482 /// <returns>True if any packets were sent, otherwise false</returns> 495 /// <returns>True if any packets were sent, otherwise false</returns>
483 public bool DequeueOutgoing() 496 public bool DequeueOutgoing()
484 { 497 {
485 OutgoingPacket packet; 498 if (m_deliverPackets == false) return false;
486 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 499
500 OutgoingPacket packet = null;
501 DoubleLocklessQueue<OutgoingPacket> queue;
487 TokenBucket bucket; 502 TokenBucket bucket;
488 bool packetSent = false; 503 bool packetSent = false;
489 ThrottleOutPacketTypeFlags emptyCategories = 0; 504 ThrottleOutPacketTypeFlags emptyCategories = 0;
@@ -514,32 +529,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
514 // No dequeued packet waiting to be sent, try to pull one off 529 // No dequeued packet waiting to be sent, try to pull one off
515 // this queue 530 // this queue
516 queue = m_packetOutboxes[i]; 531 queue = m_packetOutboxes[i];
517 if (queue.Dequeue(out packet)) 532 if (queue != null)
518 { 533 {
519 // A packet was pulled off the queue. See if we have 534 bool success = false;
520 // enough tokens in the bucket to send it out 535 try
521 if (bucket.RemoveTokens(packet.Buffer.DataLength))
522 { 536 {
523 // Send the packet 537 success = queue.Dequeue(out packet);
524 m_udpServer.SendPacketFinal(packet);
525 packetSent = true;
526 } 538 }
527 else 539 catch
528 { 540 {
529 // Save the dequeued packet for the next iteration 541 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
530 m_nextPackets[i] = packet;
531 } 542 }
532 543 if (success)
533 // If the queue is empty after this dequeue, fire the queue 544 {
534 // empty callback now so it has a chance to fill before we 545 // A packet was pulled off the queue. See if we have
535 // get back here 546 // enough tokens in the bucket to send it out
536 if (queue.Count == 0) 547 if (bucket.RemoveTokens(packet.Buffer.DataLength))
548 {
549 // Send the packet
550 m_udpServer.SendPacketFinal(packet);
551 packetSent = true;
552 }
553 else
554 {
555 // Save the dequeued packet for the next iteration
556 m_nextPackets[i] = packet;
557 }
558
559 // If the queue is empty after this dequeue, fire the queue
560 // empty callback now so it has a chance to fill before we
561 // get back here
562 if (queue.Count == 0)
563 emptyCategories |= CategoryToFlag(i);
564 }
565 else
566 {
567 // No packets in this queue. Fire the queue empty callback
568 // if it has not been called recently
537 emptyCategories |= CategoryToFlag(i); 569 emptyCategories |= CategoryToFlag(i);
570 }
538 } 571 }
539 else 572 else
540 { 573 {
541 // No packets in this queue. Fire the queue empty callback 574 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
542 // if it has not been called recently
543 emptyCategories |= CategoryToFlag(i); 575 emptyCategories |= CategoryToFlag(i);
544 } 576 }
545 } 577 }
@@ -648,6 +680,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
648 if (m_nextOnQueueEmpty == 0) 680 if (m_nextOnQueueEmpty == 0)
649 m_nextOnQueueEmpty = 1; 681 m_nextOnQueueEmpty = 1;
650 } 682 }
683 internal void ForceThrottleSetting(int throttle, int setting)
684 {
685 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ;
686 }
651 687
652 /// <summary> 688 /// <summary>
653 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a 689 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
@@ -692,4 +728,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
692 } 728 }
693 } 729 }
694 } 730 }
731
732 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
733 {
734 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
735
736 public override int Count
737 {
738 get
739 {
740 return base.Count + highQueue.Count;
741 }
742 }
743
744 public override bool Dequeue(out T item)
745 {
746 if (highQueue.Dequeue(out item))
747 return true;
748
749 return base.Dequeue(out item);
750 }
751
752 public void Enqueue(T item, bool highPriority)
753 {
754 if (highPriority)
755 highQueue.Enqueue(item);
756 else
757 Enqueue(item);
758 }
759 }
695} 760}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 85270a6..77b07ed 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -127,7 +127,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
127 /// <summary>Handlers for incoming packets</summary> 127 /// <summary>Handlers for incoming packets</summary>
128 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 128 //PacketEventDictionary packetEvents = new PacketEventDictionary();
129 /// <summary>Incoming packets that are awaiting handling</summary> 129 /// <summary>Incoming packets that are awaiting handling</summary>
130 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 130 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
131
132 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
131 133
132 /// <summary></summary> 134 /// <summary></summary>
133 //private UDPClientCollection m_clients = new UDPClientCollection(); 135 //private UDPClientCollection m_clients = new UDPClientCollection();
@@ -182,6 +184,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
182 /// <summary>Flag to signal when clients should send pings</summary> 184 /// <summary>Flag to signal when clients should send pings</summary>
183 protected bool m_sendPing; 185 protected bool m_sendPing;
184 186
187 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
185 private Pool<IncomingPacket> m_incomingPacketPool; 188 private Pool<IncomingPacket> m_incomingPacketPool;
186 189
187 /// <summary> 190 /// <summary>
@@ -875,6 +878,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
875 878
876 #region Queue or Send 879 #region Queue or Send
877 880
881 bool highPriority = false;
882
883 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
884 {
885 category = (ThrottleOutPacketType)((int)category & 127);
886 highPriority = true;
887 }
888
878 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 889 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
879 // If we were not provided a method for handling unacked, use the UDPServer default method 890 // If we were not provided a method for handling unacked, use the UDPServer default method
880 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 891 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
@@ -883,7 +894,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
883 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 894 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
884 // packet so that it isn't sent before a queued update packet. 895 // packet so that it isn't sent before a queued update packet.
885 bool requestQueue = type == PacketType.KillObject; 896 bool requestQueue = type == PacketType.KillObject;
886 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 897 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
887 SendPacketFinal(outgoingPacket); 898 SendPacketFinal(outgoingPacket);
888 899
889 #endregion Queue or Send 900 #endregion Queue or Send
@@ -1168,21 +1179,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1168 1179
1169 #region Packet to Client Mapping 1180 #region Packet to Client Mapping
1170 1181
1171 // UseCircuitCode handling 1182 // If there is already a client for this endpoint, don't process UseCircuitCode
1172 if (packet.Type == PacketType.UseCircuitCode) 1183 IClientAPI client = null;
1184 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1173 { 1185 {
1174 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1186 // UseCircuitCode handling
1175 // buffer. 1187 if (packet.Type == PacketType.UseCircuitCode)
1176 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1188 {
1189 // And if there is a UseCircuitCode pending, also drop it
1190 lock (m_pendingCache)
1191 {
1192 if (m_pendingCache.Contains(endPoint))
1193 return;
1177 1194
1178 Util.FireAndForget(HandleUseCircuitCode, array); 1195 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1196 }
1179 1197
1180 return; 1198 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1199 // buffer.
1200 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1201
1202 Util.FireAndForget(HandleUseCircuitCode, array);
1203
1204 return;
1205 }
1206 }
1207
1208 // If this is a pending connection, enqueue, don't process yet
1209 lock (m_pendingCache)
1210 {
1211 Queue<UDPPacketBuffer> queue;
1212 if (m_pendingCache.TryGetValue(endPoint, out queue))
1213 {
1214 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1215 queue.Enqueue(buffer);
1216 return;
1217 }
1181 } 1218 }
1182 1219
1183 // Determine which agent this packet came from 1220 // Determine which agent this packet came from
1184 IClientAPI client; 1221 if (client == null || !(client is LLClientView))
1185 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1186 { 1222 {
1187 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1223 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1188 return; 1224 return;
@@ -1191,7 +1227,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1191 udpClient = ((LLClientView)client).UDPClient; 1227 udpClient = ((LLClientView)client).UDPClient;
1192 1228
1193 if (!udpClient.IsConnected) 1229 if (!udpClient.IsConnected)
1230 {
1231 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1194 return; 1232 return;
1233 }
1195 1234
1196 #endregion Packet to Client Mapping 1235 #endregion Packet to Client Mapping
1197 1236
@@ -1321,7 +1360,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1321 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1360 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1322 } 1361 }
1323 1362
1324 packetInbox.Enqueue(incomingPacket); 1363 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1364 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1365 packetInbox.EnqueueHigh(incomingPacket);
1366 else
1367 packetInbox.EnqueueLow(incomingPacket);
1325 } 1368 }
1326 1369
1327 #region BinaryStats 1370 #region BinaryStats
@@ -1473,6 +1516,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1473 if (!tp) 1516 if (!tp)
1474 client.SceneAgent.SendInitialDataToMe(); 1517 client.SceneAgent.SendInitialDataToMe();
1475 } 1518 }
1519
1520 // Now we know we can handle more data
1521 Thread.Sleep(200);
1522
1523 // Obtain the queue and remove it from the cache
1524 Queue<UDPPacketBuffer> queue = null;
1525
1526 lock (m_pendingCache)
1527 {
1528 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1529 {
1530 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1531 return;
1532 }
1533 m_pendingCache.Remove(endPoint);
1534 }
1535
1536 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1537
1538 // Reinject queued packets
1539 while(queue.Count > 0)
1540 {
1541 UDPPacketBuffer buf = queue.Dequeue();
1542 PacketReceived(buf);
1543 }
1544 queue = null;
1476 } 1545 }
1477 else 1546 else
1478 { 1547 {
@@ -1480,6 +1549,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1480 m_log.WarnFormat( 1549 m_log.WarnFormat(
1481 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1550 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1482 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1551 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1552 lock (m_pendingCache)
1553 m_pendingCache.Remove(endPoint);
1483 } 1554 }
1484 1555
1485 // m_log.DebugFormat( 1556 // m_log.DebugFormat(
@@ -1599,7 +1670,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1599 if (!client.SceneAgent.IsChildAgent) 1670 if (!client.SceneAgent.IsChildAgent)
1600 client.Kick("Simulator logged you out due to connection timeout"); 1671 client.Kick("Simulator logged you out due to connection timeout");
1601 1672
1602 client.CloseWithoutChecks(); 1673 client.CloseWithoutChecks(true);
1603 } 1674 }
1604 } 1675 }
1605 1676
@@ -1611,6 +1682,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1611 1682
1612 while (IsRunningInbound) 1683 while (IsRunningInbound)
1613 { 1684 {
1685 m_scene.ThreadAlive(1);
1614 try 1686 try
1615 { 1687 {
1616 IncomingPacket incomingPacket = null; 1688 IncomingPacket incomingPacket = null;
@@ -1660,6 +1732,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1660 1732
1661 while (base.IsRunningOutbound) 1733 while (base.IsRunningOutbound)
1662 { 1734 {
1735 m_scene.ThreadAlive(2);
1663 try 1736 try
1664 { 1737 {
1665 m_packetSent = false; 1738 m_packetSent = false;
@@ -1890,8 +1963,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1890 Packet packet = incomingPacket.Packet; 1963 Packet packet = incomingPacket.Packet;
1891 LLClientView client = incomingPacket.Client; 1964 LLClientView client = incomingPacket.Client;
1892 1965
1893 if (client.IsActive) 1966// if (client.IsActive)
1894 { 1967// {
1895 m_currentIncomingClient = client; 1968 m_currentIncomingClient = client;
1896 1969
1897 try 1970 try
@@ -1918,13 +1991,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1918 { 1991 {
1919 m_currentIncomingClient = null; 1992 m_currentIncomingClient = null;
1920 } 1993 }
1921 } 1994// }
1922 else 1995// else
1923 { 1996// {
1924 m_log.DebugFormat( 1997// m_log.DebugFormat(
1925 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1998// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1926 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1999// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1927 } 2000// }
1928 2001
1929 IncomingPacketsProcessed++; 2002 IncomingPacketsProcessed++;
1930 } 2003 }
@@ -1936,8 +2009,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1936 if (!client.IsLoggingOut) 2009 if (!client.IsLoggingOut)
1937 { 2010 {
1938 client.IsLoggingOut = true; 2011 client.IsLoggingOut = true;
1939 client.Close(); 2012 client.Close(false, false);
1940 } 2013 }
1941 } 2014 }
1942 } 2015 }
1943} \ No newline at end of file 2016}
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,