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.cs894
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs8
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs11
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs448
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs382
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs18
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs296
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs196
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs267
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1455
-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, 3715 insertions, 1183 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 20df8a6..eadca9b 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;
@@ -53,14 +54,16 @@ using OSDMap = OpenMetaverse.StructuredData.OSDMap;
53namespace OpenSim.Region.ClientStack.Linden 54namespace OpenSim.Region.ClientStack.Linden
54{ 55{
55 public delegate void UpLoadedAsset( 56 public delegate void UpLoadedAsset(
56 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, 57 string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder,
57 byte[] data, string inventoryType, string assetType); 58 byte[] data, string inventoryType, string assetType,
59 int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
60 bool IsAtestUpload, ref string error);
58 61
59 public delegate UUID UpdateItem(UUID itemID, byte[] data); 62 public delegate UUID UpdateItem(UUID itemID, byte[] data);
60 63
61 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 64 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
62 65
63 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 66 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
64 67
65 public delegate void NewAsset(AssetBase asset); 68 public delegate void NewAsset(AssetBase asset);
66 69
@@ -86,6 +89,7 @@ namespace OpenSim.Region.ClientStack.Linden
86 89
87 private Scene m_Scene; 90 private Scene m_Scene;
88 private Caps m_HostCapsObj; 91 private Caps m_HostCapsObj;
92 private ModelCost m_ModelCost;
89 93
90 private static readonly string m_requestPath = "0000/"; 94 private static readonly string m_requestPath = "0000/";
91 // private static readonly string m_mapLayerPath = "0001/"; 95 // private static readonly string m_mapLayerPath = "0001/";
@@ -97,7 +101,8 @@ namespace OpenSim.Region.ClientStack.Linden
97 private static readonly string m_copyFromNotecardPath = "0007/"; 101 private static readonly string m_copyFromNotecardPath = "0007/";
98 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. 102 // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule.
99 private static readonly string m_getObjectPhysicsDataPath = "0101/"; 103 private static readonly string m_getObjectPhysicsDataPath = "0101/";
100 /* 0102 - 0103 RESERVED */ 104 private static readonly string m_getObjectCostPath = "0102/";
105 private static readonly string m_ResourceCostSelectedPath = "0103/";
101 private static readonly string m_UpdateAgentInformationPath = "0500/"; 106 private static readonly string m_UpdateAgentInformationPath = "0500/";
102 107
103 // These are callbacks which will be setup by the scene so that we can update scene data when we 108 // These are callbacks which will be setup by the scene so that we can update scene data when we
@@ -113,12 +118,50 @@ namespace OpenSim.Region.ClientStack.Linden
113 private IAssetService m_assetService; 118 private IAssetService m_assetService;
114 private bool m_dumpAssetsToFile = false; 119 private bool m_dumpAssetsToFile = false;
115 private string m_regionName; 120 private string m_regionName;
121
116 private int m_levelUpload = 0; 122 private int m_levelUpload = 0;
117 123
124 private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack
125 private bool m_ForceFreeTestUpload = false; // forces all uploads to be test
126
127 private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory
128 // may not be visible till relog
129
130 private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!!
131 private UUID m_testAssetsCreatorID = UUID.Zero;
132
133 private float m_PrimScaleMin = 0.001f;
134
135 private enum FileAgentInventoryState : int
136 {
137 idle = 0,
138 processRequest = 1,
139 waitUpload = 2,
140 processUpload = 3
141 }
142 private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle;
143
118 public BunchOfCaps(Scene scene, Caps caps) 144 public BunchOfCaps(Scene scene, Caps caps)
119 { 145 {
120 m_Scene = scene; 146 m_Scene = scene;
121 m_HostCapsObj = caps; 147 m_HostCapsObj = caps;
148
149 // create a model upload cost provider
150 m_ModelCost = new ModelCost();
151 // tell it about scene object limits
152 m_ModelCost.NonPhysicalPrimScaleMax = m_Scene.m_maxNonphys;
153 m_ModelCost.PhysicalPrimScaleMax = m_Scene.m_maxPhys;
154
155// m_ModelCost.ObjectLinkedPartsMax = ??
156// m_ModelCost.PrimScaleMin = ??
157
158 m_PrimScaleMin = m_ModelCost.PrimScaleMin;
159 float modelTextureUploadFactor = m_ModelCost.ModelTextureCostFactor;
160 float modelUploadFactor = m_ModelCost.ModelMeshCostFactor;
161 float modelMinUploadCostFactor = m_ModelCost.ModelMinCostFactor;
162 float modelPrimCreationCost = m_ModelCost.primCreationCost;
163 float modelMeshByteCost = m_ModelCost.bytecost;
164
122 IConfigSource config = m_Scene.Config; 165 IConfigSource config = m_Scene.Config;
123 if (config != null) 166 if (config != null)
124 { 167 {
@@ -133,6 +176,37 @@ namespace OpenSim.Region.ClientStack.Linden
133 { 176 {
134 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 177 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
135 } 178 }
179 // economy for model upload
180 IConfig EconomyConfig = config.Configs["Economy"];
181 if (EconomyConfig != null)
182 {
183 modelUploadFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", modelUploadFactor);
184 modelTextureUploadFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", modelTextureUploadFactor);
185 modelMinUploadCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", modelMinUploadCostFactor);
186 // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost
187 modelPrimCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", modelPrimCreationCost);
188 modelMeshByteCost = EconomyConfig.GetFloat("ModelMeshByteCost", modelMeshByteCost);
189
190 m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory);
191
192 m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms);
193 m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload);
194 m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload);
195 string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", "");
196 if (testcreator != "")
197 {
198 UUID id;
199 UUID.TryParse(testcreator, out id);
200 if (id != null)
201 m_testAssetsCreatorID = id;
202 }
203
204 m_ModelCost.ModelMeshCostFactor = modelUploadFactor;
205 m_ModelCost.ModelTextureCostFactor = modelTextureUploadFactor;
206 m_ModelCost.ModelMinCostFactor = modelMinUploadCostFactor;
207 m_ModelCost.primCreationCost = modelPrimCreationCost;
208 m_ModelCost.bytecost = modelMeshByteCost;
209 }
136 } 210 }
137 211
138 m_assetService = m_Scene.AssetService; 212 m_assetService = m_Scene.AssetService;
@@ -144,6 +218,8 @@ namespace OpenSim.Region.ClientStack.Linden
144 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 218 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
145 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 219 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
146 GetClient = m_Scene.SceneGraph.GetControllingClient; 220 GetClient = m_Scene.SceneGraph.GetControllingClient;
221
222 m_FileAgentInventoryState = FileAgentInventoryState.idle;
147 } 223 }
148 224
149 /// <summary> 225 /// <summary>
@@ -189,7 +265,6 @@ namespace OpenSim.Region.ClientStack.Linden
189 { 265 {
190 try 266 try
191 { 267 {
192 // I don't think this one works...
193 m_HostCapsObj.RegisterHandler( 268 m_HostCapsObj.RegisterHandler(
194 "NewFileAgentInventory", 269 "NewFileAgentInventory",
195 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 270 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -208,6 +283,10 @@ namespace OpenSim.Region.ClientStack.Linden
208 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 283 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
209 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); 284 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
210 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); 285 m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
286 IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
287 m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
288 IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
289 m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
211 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 290 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
212 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 291 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
213 292
@@ -263,6 +342,9 @@ namespace OpenSim.Region.ClientStack.Linden
263 m_log.DebugFormat( 342 m_log.DebugFormat(
264 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); 343 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
265 344
345 if (!m_HostCapsObj.WaitForActivation())
346 return string.Empty;
347
266 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 348 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
267 { 349 {
268 m_log.WarnFormat( 350 m_log.WarnFormat(
@@ -392,62 +474,176 @@ namespace OpenSim.Region.ClientStack.Linden
392 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 474 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
393 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 475 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
394 476
477 // start by getting the client
478 IClientAPI client = null;
479 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
480
481 // check current state so we only have one service at a time
482 lock (m_ModelCost)
483 {
484 switch (m_FileAgentInventoryState)
485 {
486 case FileAgentInventoryState.processRequest:
487 case FileAgentInventoryState.processUpload:
488 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
489 resperror.message = "Uploader busy processing previus request";
490 resperror.identifier = UUID.Zero;
491
492 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
493 errorResponse.uploader = "";
494 errorResponse.state = "error";
495 errorResponse.error = resperror;
496 return errorResponse;
497 break;
498 case FileAgentInventoryState.waitUpload:
499 // todo stop current uploader server
500 break;
501 case FileAgentInventoryState.idle:
502 default:
503 break;
504 }
505
506 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
507 }
508
509 int cost = 0;
510 int nreqtextures = 0;
511 int nreqmeshs= 0;
512 int nreqinstances = 0;
513 bool IsAtestUpload = false;
514
515 string assetName = llsdRequest.name;
516
517 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
518
395 if (llsdRequest.asset_type == "texture" || 519 if (llsdRequest.asset_type == "texture" ||
396 llsdRequest.asset_type == "animation" || 520 llsdRequest.asset_type == "animation" ||
521 llsdRequest.asset_type == "mesh" ||
397 llsdRequest.asset_type == "sound") 522 llsdRequest.asset_type == "sound")
398 { 523 {
399 ScenePresence avatar = null; 524 ScenePresence avatar = null;
400 IClientAPI client = null;
401 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 525 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
402 526
403 // check user level 527 // check user level
404 if (avatar != null) 528 if (avatar != null)
405 { 529 {
406 client = avatar.ControllingClient;
407
408 if (avatar.UserLevel < m_levelUpload) 530 if (avatar.UserLevel < m_levelUpload)
409 { 531 {
410 if (client != null) 532 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
411 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 533 resperror.message = "Insufficient permissions to upload";
534 resperror.identifier = UUID.Zero;
412 535
413 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 536 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
414 errorResponse.uploader = ""; 537 errorResponse.uploader = "";
415 errorResponse.state = "error"; 538 errorResponse.state = "error";
539 errorResponse.error = resperror;
540 lock (m_ModelCost)
541 m_FileAgentInventoryState = FileAgentInventoryState.idle;
416 return errorResponse; 542 return errorResponse;
417 } 543 }
418 } 544 }
419 545
420 // check funds 546 // check test upload and funds
421 if (client != null) 547 if (client != null)
422 { 548 {
423 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 549 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
424 550
551 int baseCost = 0;
425 if (mm != null) 552 if (mm != null)
553 baseCost = mm.UploadCharge;
554
555 string warning = String.Empty;
556
557 if (llsdRequest.asset_type == "mesh")
426 { 558 {
427 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 559 string error;
560 int modelcost;
561
562 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
563 meshcostdata, out error, ref warning))
428 { 564 {
429 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 565 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
566 resperror.message = error;
567 resperror.identifier = UUID.Zero;
430 568
431 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 569 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
432 errorResponse.uploader = ""; 570 errorResponse.uploader = "";
433 errorResponse.state = "error"; 571 errorResponse.state = "error";
572 errorResponse.error = resperror;
573
574 lock (m_ModelCost)
575 m_FileAgentInventoryState = FileAgentInventoryState.idle;
434 return errorResponse; 576 return errorResponse;
435 } 577 }
578 cost = modelcost;
579 }
580 else
581 {
582 cost = baseCost;
583 }
584
585 if (cost > 0 && mm != null)
586 {
587 // check for test upload
588
589 if (m_ForceFreeTestUpload) // all are test
590 {
591 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
592 assetName = "TEST-" + assetName;
593
594 IsAtestUpload = true;
595 }
596
597 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
598 {
599
600 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
601 }
602
603
604 if(IsAtestUpload) // let user know, still showing cost estimation
605 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";
606
607 // check funds
608 else
609 {
610 if (!mm.UploadCovered(client.AgentId, (int)cost))
611 {
612 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
613 resperror.message = "Insuficient funds";
614 resperror.identifier = UUID.Zero;
615
616 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
617 errorResponse.uploader = "";
618 errorResponse.state = "error";
619 errorResponse.error = resperror;
620 lock (m_ModelCost)
621 m_FileAgentInventoryState = FileAgentInventoryState.idle;
622 return errorResponse;
623 }
624 }
436 } 625 }
626
627 if (client != null && warning != String.Empty)
628 client.SendAgentAlertMessage(warning, true);
437 } 629 }
438 } 630 }
439 631
440 string assetName = llsdRequest.name;
441 string assetDes = llsdRequest.description; 632 string assetDes = llsdRequest.description;
442 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 633 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
443 UUID newAsset = UUID.Random(); 634 UUID newAsset = UUID.Random();
444 UUID newInvItem = UUID.Random(); 635 UUID newInvItem = UUID.Random();
445 UUID parentFolder = llsdRequest.folder_id; 636 UUID parentFolder = llsdRequest.folder_id;
446 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 637 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
638 UUID texturesFolder = UUID.Zero;
639
640 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
641 texturesFolder = llsdRequest.texture_folder_id;
447 642
448 AssetUploader uploader = 643 AssetUploader uploader =
449 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 644 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
450 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 645 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
646 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
451 647
452 m_HostCapsObj.HttpListener.AddStreamHandler( 648 m_HostCapsObj.HttpListener.AddStreamHandler(
453 new BinaryStreamHandler( 649 new BinaryStreamHandler(
@@ -465,10 +661,22 @@ namespace OpenSim.Region.ClientStack.Linden
465 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 661 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
466 uploaderPath; 662 uploaderPath;
467 663
664
468 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 665 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
469 uploadResponse.uploader = uploaderURL; 666 uploadResponse.uploader = uploaderURL;
470 uploadResponse.state = "upload"; 667 uploadResponse.state = "upload";
668 uploadResponse.upload_price = (int)cost;
669
670 if (llsdRequest.asset_type == "mesh")
671 {
672 uploadResponse.data = meshcostdata;
673 }
674
471 uploader.OnUpLoad += UploadCompleteHandler; 675 uploader.OnUpLoad += UploadCompleteHandler;
676
677 lock (m_ModelCost)
678 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
679
472 return uploadResponse; 680 return uploadResponse;
473 } 681 }
474 682
@@ -480,8 +688,14 @@ namespace OpenSim.Region.ClientStack.Linden
480 /// <param name="data"></param> 688 /// <param name="data"></param>
481 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 689 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
482 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 690 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
483 string assetType) 691 string assetType, int cost,
692 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
693 bool IsAtestUpload, ref string error)
484 { 694 {
695
696 lock (m_ModelCost)
697 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
698
485 m_log.DebugFormat( 699 m_log.DebugFormat(
486 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 700 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
487 assetID, inventoryItem, inventoryType, assetType); 701 assetID, inventoryItem, inventoryType, assetType);
@@ -489,117 +703,247 @@ namespace OpenSim.Region.ClientStack.Linden
489 sbyte assType = 0; 703 sbyte assType = 0;
490 sbyte inType = 0; 704 sbyte inType = 0;
491 705
706 IClientAPI client = null;
707
708 UUID owner_id = m_HostCapsObj.AgentID;
709 UUID creatorID;
710
711 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
712
713 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
714
715 if (istest && m_testAssetsCreatorID != UUID.Zero)
716 creatorID = m_testAssetsCreatorID;
717 else
718 creatorID = owner_id;
719
720 string creatorIDstr = creatorID.ToString();
721
722 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
723 if (mm != null)
724 {
725 // make sure client still has enougth credit
726 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
727 {
728 error = "Insufficient funds.";
729 return;
730 }
731 }
732
733 // strings to types
492 if (inventoryType == "sound") 734 if (inventoryType == "sound")
493 { 735 {
494 inType = 1; 736 inType = (sbyte)InventoryType.Sound;
495 assType = 1; 737 assType = (sbyte)AssetType.Sound;
496 } 738 }
497 else if (inventoryType == "animation") 739 else if (inventoryType == "animation")
498 { 740 {
499 inType = 19; 741 inType = (sbyte)InventoryType.Animation;
500 assType = 20; 742 assType = (sbyte)AssetType.Animation;
501 } 743 }
502 else if (inventoryType == "wearable") 744 else if (inventoryType == "wearable")
503 { 745 {
504 inType = 18; 746 inType = (sbyte)InventoryType.Wearable;
505 switch (assetType) 747 switch (assetType)
506 { 748 {
507 case "bodypart": 749 case "bodypart":
508 assType = 13; 750 assType = (sbyte)AssetType.Bodypart;
509 break; 751 break;
510 case "clothing": 752 case "clothing":
511 assType = 5; 753 assType = (sbyte)AssetType.Clothing;
512 break; 754 break;
513 } 755 }
514 } 756 }
515 else if (inventoryType == "object") 757 else if (inventoryType == "object")
516 { 758 {
517 inType = (sbyte)InventoryType.Object; 759 if (assetType == "mesh") // this code for now is for mesh models uploads only
518 assType = (sbyte)AssetType.Object;
519
520 List<Vector3> positions = new List<Vector3>();
521 List<Quaternion> rotations = new List<Quaternion>();
522 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
523 OSDArray instance_list = (OSDArray)request["instance_list"];
524 OSDArray mesh_list = (OSDArray)request["mesh_list"];
525 OSDArray texture_list = (OSDArray)request["texture_list"];
526 SceneObjectGroup grp = null;
527
528 List<UUID> textures = new List<UUID>();
529 for (int i = 0; i < texture_list.Count; i++)
530 { 760 {
531 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 761 inType = (sbyte)InventoryType.Object;
532 textureAsset.Data = texture_list[i].AsBinary(); 762 assType = (sbyte)AssetType.Object;
533 m_assetService.Store(textureAsset);
534 textures.Add(textureAsset.FullID);
535 }
536 763
537 for (int i = 0; i < mesh_list.Count; i++) 764 List<Vector3> positions = new List<Vector3>();
538 { 765 List<Quaternion> rotations = new List<Quaternion>();
539 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 766 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
767
768 // compare and get updated information
540 769
541 Primitive.TextureEntry textureEntry 770 bool mismatchError = true;
542 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
543 OSDMap inner_instance_list = (OSDMap)instance_list[i];
544 771
545 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 772 while (mismatchError)
546 for (uint face = 0; face < face_list.Count; face++)
547 { 773 {
548 OSDMap faceMap = (OSDMap)face_list[(int)face]; 774 mismatchError = false;
549 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 775 }
550 if(faceMap.ContainsKey("fullbright"))
551 f.Fullbright = faceMap["fullbright"].AsBoolean();
552 if (faceMap.ContainsKey ("diffuse_color"))
553 f.RGBA = faceMap["diffuse_color"].AsColor4();
554 776
555 int textureNum = faceMap["image"].AsInteger(); 777 if (mismatchError)
556 float imagerot = faceMap["imagerot"].AsInteger(); 778 {
557 float offsets = (float)faceMap["offsets"].AsReal(); 779 error = "Upload and fee estimation information don't match";
558 float offsett = (float)faceMap["offsett"].AsReal(); 780 lock (m_ModelCost)
559 float scales = (float)faceMap["scales"].AsReal(); 781 m_FileAgentInventoryState = FileAgentInventoryState.idle;
560 float scalet = (float)faceMap["scalet"].AsReal();
561 782
562 if(imagerot != 0) 783 return;
563 f.Rotation = imagerot; 784 }
564 785
565 if(offsets != 0) 786 OSDArray instance_list = (OSDArray)request["instance_list"];
566 f.OffsetU = offsets; 787 OSDArray mesh_list = (OSDArray)request["mesh_list"];
788 OSDArray texture_list = (OSDArray)request["texture_list"];
789 SceneObjectGroup grp = null;
567 790
568 if (offsett != 0) 791 // create and store texture assets
569 f.OffsetV = offsett; 792 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
793 texturesFolder != UUID.Zero);
570 794
571 if (scales != 0)
572 f.RepeatU = scales;
573 795
574 if (scalet != 0) 796 List<UUID> textures = new List<UUID>();
575 f.RepeatV = scalet;
576 797
577 if (textures.Count > textureNum) 798
578 f.TextureID = textures[textureNum]; 799 if (doTextInv)
579 else 800 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
580 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; 801
802 if(client == null) // don't put textures in inventory if there is no client
803 doTextInv = false;
804
805 for (int i = 0; i < texture_list.Count; i++)
806 {
807 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
808 textureAsset.Data = texture_list[i].AsBinary();
809 if (istest)
810 textureAsset.Local = true;
811 m_assetService.Store(textureAsset);
812 textures.Add(textureAsset.FullID);
813
814 if (doTextInv)
815 {
816 string name = assetName;
817 if (name.Length > 25)
818 name = name.Substring(0, 24);
819 name += "_Texture#" + i.ToString();
820 InventoryItemBase texitem = new InventoryItemBase();
821 texitem.Owner = m_HostCapsObj.AgentID;
822 texitem.CreatorId = creatorIDstr;
823 texitem.CreatorData = String.Empty;
824 texitem.ID = UUID.Random();
825 texitem.AssetID = textureAsset.FullID;
826 texitem.Description = "mesh model texture";
827 texitem.Name = name;
828 texitem.AssetType = (int)AssetType.Texture;
829 texitem.InvType = (int)InventoryType.Texture;
830 texitem.Folder = texturesFolder;
831
832 texitem.CurrentPermissions
833 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
834
835 texitem.BasePermissions = (uint)PermissionMask.All;
836 texitem.EveryOnePermissions = 0;
837 texitem.NextPermissions = (uint)PermissionMask.All;
838 texitem.CreationDate = Util.UnixTimeSinceEpoch();
839
840 m_Scene.AddInventoryItem(client, texitem);
841 texitem = null;
842 }
843 }
581 844
582 textureEntry.FaceTextures[face] = f; 845 // create and store meshs assets
846 List<UUID> meshAssets = new List<UUID>();
847 for (int i = 0; i < mesh_list.Count; i++)
848 {
849 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
850 meshAsset.Data = mesh_list[i].AsBinary();
851 if (istest)
852 meshAsset.Local = true;
853 m_assetService.Store(meshAsset);
854 meshAssets.Add(meshAsset.FullID);
583 } 855 }
584 856
585 pbs.TextureEntry = textureEntry.GetBytes(); 857 int skipedMeshs = 0;
858 // build prims from instances
859 for (int i = 0; i < instance_list.Count; i++)
860 {
861 OSDMap inner_instance_list = (OSDMap)instance_list[i];
862
863 // skip prims that are 2 small
864 Vector3 scale = inner_instance_list["scale"].AsVector3();
865
866 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
867 {
868 skipedMeshs++;
869 continue;
870 }
871
872 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
873
874 Primitive.TextureEntry textureEntry
875 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
586 876
587 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, "");
588 meshAsset.Data = mesh_list[i].AsBinary();
589 m_assetService.Store(meshAsset);
590 877
591 pbs.SculptEntry = true; 878 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
592 pbs.SculptTexture = meshAsset.FullID; 879 for (uint face = 0; face < face_list.Count; face++)
593 pbs.SculptType = (byte)SculptType.Mesh; 880 {
594 pbs.SculptData = meshAsset.Data; 881 OSDMap faceMap = (OSDMap)face_list[(int)face];
882 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
883 if (faceMap.ContainsKey("fullbright"))
884 f.Fullbright = faceMap["fullbright"].AsBoolean();
885 if (faceMap.ContainsKey("diffuse_color"))
886 f.RGBA = faceMap["diffuse_color"].AsColor4();
887
888 int textureNum = faceMap["image"].AsInteger();
889 float imagerot = faceMap["imagerot"].AsInteger();
890 float offsets = (float)faceMap["offsets"].AsReal();
891 float offsett = (float)faceMap["offsett"].AsReal();
892 float scales = (float)faceMap["scales"].AsReal();
893 float scalet = (float)faceMap["scalet"].AsReal();
894
895 if (imagerot != 0)
896 f.Rotation = imagerot;
897
898 if (offsets != 0)
899 f.OffsetU = offsets;
900
901 if (offsett != 0)
902 f.OffsetV = offsett;
903
904 if (scales != 0)
905 f.RepeatU = scales;
906
907 if (scalet != 0)
908 f.RepeatV = scalet;
909
910 if (textures.Count > textureNum)
911 f.TextureID = textures[textureNum];
912 else
913 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
914
915 textureEntry.FaceTextures[face] = f;
916 }
917
918 pbs.TextureEntry = textureEntry.GetBytes();
919
920 bool hasmesh = false;
921 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
922 {
923 int meshindx = inner_instance_list["mesh"].AsInteger();
924 if (meshAssets.Count > meshindx)
925 {
926 pbs.SculptEntry = true;
927 pbs.SculptType = (byte)SculptType.Mesh;
928 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
929 // data will be requested from asset on rez (i hope)
930 hasmesh = true;
931 }
932 }
933
934 Vector3 position = inner_instance_list["position"].AsVector3();
935 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
595 936
596 Vector3 position = inner_instance_list["position"].AsVector3(); 937 // for now viwers do send fixed defaults
597 Vector3 scale = inner_instance_list["scale"].AsVector3(); 938 // but this may change
598 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 939// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
940 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
941 if(hasmesh)
942 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
943// int material = inner_instance_list["material"].AsInteger();
944 byte material = (byte)Material.Wood;
599 945
600// no longer used - begin ------------------------ 946// no longer used - begin ------------------------
601// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
602// int material = inner_instance_list["material"].AsInteger();
603// int mesh = inner_instance_list["mesh"].AsInteger(); 947// int mesh = inner_instance_list["mesh"].AsInteger();
604 948
605// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 949// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -614,24 +958,42 @@ namespace OpenSim.Region.ClientStack.Linden
614// UUID owner_id = permissions["owner_id"].AsUUID(); 958// UUID owner_id = permissions["owner_id"].AsUUID();
615// int owner_mask = permissions["owner_mask"].AsInteger(); 959// int owner_mask = permissions["owner_mask"].AsInteger();
616// no longer used - end ------------------------ 960// no longer used - end ------------------------
961
962
963 SceneObjectPart prim
964 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
965
966 prim.Scale = scale;
967 rotations.Add(rotation);
968 positions.Add(position);
969 prim.UUID = UUID.Random();
970 prim.CreatorID = creatorID;
971 prim.OwnerID = owner_id;
972 prim.GroupID = UUID.Zero;
973 prim.LastOwnerID = creatorID;
974 prim.CreationDate = Util.UnixTimeSinceEpoch();
975
976 if (grp == null)
977 prim.Name = assetName;
978 else
979 prim.Name = assetName + "#" + i.ToString();
617 980
618 UUID owner_id = m_HostCapsObj.AgentID; 981 if (restrictPerms)
982 {
983 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
984 prim.EveryoneMask = 0;
985 prim.GroupMask = 0;
986 prim.NextOwnerMask = 0;
987 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
988 }
619 989
620 SceneObjectPart prim 990 if(istest)
621 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 991 prim.Description = "For testing only. Other uses are prohibited";
992 else
993 prim.Description = "";
622 994
623 prim.Scale = scale; 995 prim.Material = material;
624 //prim.OffsetPosition = position; 996 prim.PhysicsShapeType = physicsShapeType;
625 rotations.Add(rotation);
626 positions.Add(position);
627 prim.UUID = UUID.Random();
628 prim.CreatorID = owner_id;
629 prim.OwnerID = owner_id;
630 prim.GroupID = UUID.Zero;
631 prim.LastOwnerID = prim.OwnerID;
632 prim.CreationDate = Util.UnixTimeSinceEpoch();
633 prim.Name = assetName;
634 prim.Description = "";
635 997
636// prim.BaseMask = (uint)base_mask; 998// prim.BaseMask = (uint)base_mask;
637// prim.EveryoneMask = (uint)everyone_mask; 999// prim.EveryoneMask = (uint)everyone_mask;
@@ -639,52 +1001,64 @@ namespace OpenSim.Region.ClientStack.Linden
639// prim.NextOwnerMask = (uint)next_owner_mask; 1001// prim.NextOwnerMask = (uint)next_owner_mask;
640// prim.OwnerMask = (uint)owner_mask; 1002// prim.OwnerMask = (uint)owner_mask;
641 1003
642 if (grp == null) 1004 if (grp == null)
643 grp = new SceneObjectGroup(prim); 1005 {
644 else 1006 grp = new SceneObjectGroup(prim);
645 grp.AddPart(prim); 1007 grp.LastOwnerID = creatorID;
646 } 1008 }
1009 else
1010 grp.AddPart(prim);
1011 }
647 1012
648 Vector3 rootPos = positions[0]; 1013 Vector3 rootPos = positions[0];
649 1014
650 if (grp.Parts.Length > 1) 1015 if (grp.Parts.Length > 1)
651 { 1016 {
652 // Fix first link number 1017 // Fix first link number
653 grp.RootPart.LinkNum++; 1018 grp.RootPart.LinkNum++;
654 1019
655 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1020 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
656 Quaternion tmprot; 1021 Quaternion tmprot;
657 Vector3 offset; 1022 Vector3 offset;
658 1023
659 // fix children rotations and positions 1024 // fix children rotations and positions
660 for (int i = 1; i < rotations.Count; i++) 1025 for (int i = 1; i < rotations.Count; i++)
661 { 1026 {
662 tmprot = rotations[i]; 1027 tmprot = rotations[i];
663 tmprot = rootRotConj * tmprot; 1028 tmprot = rootRotConj * tmprot;
664 1029
665 grp.Parts[i].RotationOffset = tmprot; 1030 grp.Parts[i].RotationOffset = tmprot;
666 1031
667 offset = positions[i] - rootPos; 1032 offset = positions[i] - rootPos;
1033
1034 offset *= rootRotConj;
1035 grp.Parts[i].OffsetPosition = offset;
1036 }
668 1037
669 offset *= rootRotConj; 1038 grp.AbsolutePosition = rootPos;
670 grp.Parts[i].OffsetPosition = offset; 1039 grp.UpdateGroupRotationR(rotations[0]);
1040 }
1041 else
1042 {
1043 grp.AbsolutePosition = rootPos;
1044 grp.UpdateGroupRotationR(rotations[0]);
671 } 1045 }
672 1046
673 grp.AbsolutePosition = rootPos; 1047 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
674 grp.UpdateGroupRotationR(rotations[0]);
675 } 1048 }
676 else 1049
1050 else // not a mesh model
677 { 1051 {
678 grp.AbsolutePosition = rootPos; 1052 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
679 grp.UpdateGroupRotationR(rotations[0]); 1053 return;
680 } 1054 }
681
682 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
683 } 1055 }
684 1056
685 AssetBase asset; 1057 AssetBase asset;
686 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1058 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
687 asset.Data = data; 1059 asset.Data = data;
1060 if (istest)
1061 asset.Local = true;
688 if (AddNewAsset != null) 1062 if (AddNewAsset != null)
689 AddNewAsset(asset); 1063 AddNewAsset(asset);
690 else if (m_assetService != null) 1064 else if (m_assetService != null)
@@ -692,11 +1066,17 @@ namespace OpenSim.Region.ClientStack.Linden
692 1066
693 InventoryItemBase item = new InventoryItemBase(); 1067 InventoryItemBase item = new InventoryItemBase();
694 item.Owner = m_HostCapsObj.AgentID; 1068 item.Owner = m_HostCapsObj.AgentID;
695 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1069 item.CreatorId = creatorIDstr;
696 item.CreatorData = String.Empty; 1070 item.CreatorData = String.Empty;
697 item.ID = inventoryItem; 1071 item.ID = inventoryItem;
698 item.AssetID = asset.FullID; 1072 item.AssetID = asset.FullID;
699 item.Description = assetDescription; 1073 if (istest)
1074 {
1075 item.Description = "For testing only. Other uses are prohibited";
1076 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1077 }
1078 else
1079 item.Description = assetDescription;
700 item.Name = assetName; 1080 item.Name = assetName;
701 item.AssetType = assType; 1081 item.AssetType = assType;
702 item.InvType = inType; 1082 item.InvType = inType;
@@ -704,18 +1084,60 @@ namespace OpenSim.Region.ClientStack.Linden
704 1084
705 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1085 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
706 // (owner) permissions. This becomes a problem if next permissions are changed. 1086 // (owner) permissions. This becomes a problem if next permissions are changed.
707 item.CurrentPermissions
708 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
709 1087
710 item.BasePermissions = (uint)PermissionMask.All; 1088 if (restrictPerms)
711 item.EveryOnePermissions = 0; 1089 {
712 item.NextPermissions = (uint)PermissionMask.All; 1090 item.CurrentPermissions
1091 = (uint)(PermissionMask.Move | PermissionMask.Modify);
1092
1093 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1094 item.EveryOnePermissions = 0;
1095 item.NextPermissions = 0;
1096 }
1097 else
1098 {
1099 item.CurrentPermissions
1100 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
1101
1102 item.BasePermissions = (uint)PermissionMask.All;
1103 item.EveryOnePermissions = 0;
1104 item.NextPermissions = (uint)PermissionMask.All;
1105 }
1106
713 item.CreationDate = Util.UnixTimeSinceEpoch(); 1107 item.CreationDate = Util.UnixTimeSinceEpoch();
714 1108
1109 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1110
715 if (AddNewInventoryItem != null) 1111 if (AddNewInventoryItem != null)
716 { 1112 {
717 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1113 if (istest)
1114 {
1115 m_Scene.AddInventoryItem(client, item);
1116/*
1117 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1118 if (client != null)
1119 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);
1120 */
1121 }
1122 else
1123 {
1124 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1125// if (client != null)
1126// {
1127// // let users see anything.. i don't so far
1128// string str;
1129// if (cost > 0)
1130// // dont remember where is money unit name to put here
1131// str = "Upload complete. charged " + cost.ToString() + "$";
1132// else
1133// str = "Upload complete";
1134// client.SendAgentAlertMessage(str, true);
1135// }
1136 }
718 } 1137 }
1138
1139 lock (m_ModelCost)
1140 m_FileAgentInventoryState = FileAgentInventoryState.idle;
719 } 1141 }
720 1142
721 /// <summary> 1143 /// <summary>
@@ -908,6 +1330,120 @@ namespace OpenSim.Region.ClientStack.Linden
908 return response; 1330 return response;
909 } 1331 }
910 1332
1333 public string GetObjectCost(string request, string path,
1334 string param, IOSHttpRequest httpRequest,
1335 IOSHttpResponse httpResponse)
1336 {
1337 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1338 OSDMap resp = new OSDMap();
1339
1340 OSDArray object_ids = (OSDArray)req["object_ids"];
1341
1342 for (int i = 0; i < object_ids.Count; i++)
1343 {
1344 UUID uuid = object_ids[i].AsUUID();
1345
1346 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1347
1348 if (part != null)
1349 {
1350 SceneObjectGroup grp = part.ParentGroup;
1351 if (grp != null)
1352 {
1353 float linksetCost;
1354 float linksetPhysCost;
1355 float partCost;
1356 float partPhysCost;
1357
1358 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1359
1360 OSDMap object_data = new OSDMap();
1361 object_data["linked_set_resource_cost"] = linksetCost;
1362 object_data["resource_cost"] = partCost;
1363 object_data["physics_cost"] = partPhysCost;
1364 object_data["linked_set_physics_cost"] = linksetPhysCost;
1365
1366 resp[uuid.ToString()] = object_data;
1367 }
1368 }
1369 }
1370
1371 string response = OSDParser.SerializeLLSDXmlString(resp);
1372 return response;
1373 }
1374
1375 public string ResourceCostSelected(string request, string path,
1376 string param, IOSHttpRequest httpRequest,
1377 IOSHttpResponse httpResponse)
1378 {
1379 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1380 OSDMap resp = new OSDMap();
1381
1382
1383 float phys=0;
1384 float stream=0;
1385 float simul=0;
1386
1387 if (req.ContainsKey("selected_roots"))
1388 {
1389 OSDArray object_ids = (OSDArray)req["selected_roots"];
1390
1391 // should go by SOG suming costs for all parts
1392 // ll v3 works ok with several objects select we get the list and adds ok
1393 // FS calls per object so results are wrong guess fs bug
1394 for (int i = 0; i < object_ids.Count; i++)
1395 {
1396 UUID uuid = object_ids[i].AsUUID();
1397 float Physc;
1398 float simulc;
1399 float streamc;
1400
1401 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1402 if (grp != null)
1403 {
1404 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1405 phys += Physc;
1406 stream += streamc;
1407 simul += simulc;
1408 }
1409 }
1410 }
1411 else if (req.ContainsKey("selected_prims"))
1412 {
1413 OSDArray object_ids = (OSDArray)req["selected_prims"];
1414
1415 // don't see in use in any of the 2 viewers
1416 // guess it should be for edit linked but... nothing
1417 // should go to SOP per part
1418 for (int i = 0; i < object_ids.Count; i++)
1419 {
1420 UUID uuid = object_ids[i].AsUUID();
1421
1422 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1423 if (part != null)
1424 {
1425 phys += part.PhysicsCost;
1426 stream += part.StreamingCost;
1427 simul += part.SimulationCost;
1428 }
1429 }
1430 }
1431
1432 if (simul != 0)
1433 {
1434 OSDMap object_data = new OSDMap();
1435
1436 object_data["physics"] = phys;
1437 object_data["streaming"] = stream;
1438 object_data["simulation"] = simul;
1439
1440 resp["selected"] = object_data;
1441 }
1442
1443 string response = OSDParser.SerializeLLSDXmlString(resp);
1444 return response;
1445 }
1446
911 public string UpdateAgentInformation(string request, string path, 1447 public string UpdateAgentInformation(string request, string path,
912 string param, IOSHttpRequest httpRequest, 1448 string param, IOSHttpRequest httpRequest,
913 IOSHttpResponse httpResponse) 1449 IOSHttpResponse httpResponse)
@@ -927,6 +1463,10 @@ namespace OpenSim.Region.ClientStack.Linden
927 1463
928 public class AssetUploader 1464 public class AssetUploader
929 { 1465 {
1466 private static readonly ILog m_log =
1467 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1468
1469
930 public event UpLoadedAsset OnUpLoad; 1470 public event UpLoadedAsset OnUpLoad;
931 private UpLoadedAsset handlerUpLoad = null; 1471 private UpLoadedAsset handlerUpLoad = null;
932 1472
@@ -941,10 +1481,21 @@ namespace OpenSim.Region.ClientStack.Linden
941 1481
942 private string m_invType = String.Empty; 1482 private string m_invType = String.Empty;
943 private string m_assetType = String.Empty; 1483 private string m_assetType = String.Empty;
1484 private int m_cost;
1485 private string m_error = String.Empty;
1486
1487 private Timer m_timeoutTimer = new Timer();
1488 private UUID m_texturesFolder;
1489 private int m_nreqtextures;
1490 private int m_nreqmeshs;
1491 private int m_nreqinstances;
1492 private bool m_IsAtestUpload;
944 1493
945 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1494 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
946 UUID parentFolderID, string invType, string assetType, string path, 1495 UUID parentFolderID, string invType, string assetType, string path,
947 IHttpServer httpServer, bool dumpAssetsToFile) 1496 IHttpServer httpServer, bool dumpAssetsToFile,
1497 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1498 bool IsAtestUpload)
948 { 1499 {
949 m_assetName = assetName; 1500 m_assetName = assetName;
950 m_assetDes = description; 1501 m_assetDes = description;
@@ -956,6 +1507,18 @@ namespace OpenSim.Region.ClientStack.Linden
956 m_assetType = assetType; 1507 m_assetType = assetType;
957 m_invType = invType; 1508 m_invType = invType;
958 m_dumpAssetsToFile = dumpAssetsToFile; 1509 m_dumpAssetsToFile = dumpAssetsToFile;
1510 m_cost = totalCost;
1511
1512 m_texturesFolder = texturesFolder;
1513 m_nreqtextures = nreqtextures;
1514 m_nreqmeshs = nreqmeshs;
1515 m_nreqinstances = nreqinstances;
1516 m_IsAtestUpload = IsAtestUpload;
1517
1518 m_timeoutTimer.Elapsed += TimedOut;
1519 m_timeoutTimer.Interval = 120000;
1520 m_timeoutTimer.AutoReset = false;
1521 m_timeoutTimer.Start();
959 } 1522 }
960 1523
961 /// <summary> 1524 /// <summary>
@@ -970,12 +1533,14 @@ namespace OpenSim.Region.ClientStack.Linden
970 UUID inv = inventoryItemID; 1533 UUID inv = inventoryItemID;
971 string res = String.Empty; 1534 string res = String.Empty;
972 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1535 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1536/*
973 uploadComplete.new_asset = newAssetID.ToString(); 1537 uploadComplete.new_asset = newAssetID.ToString();
974 uploadComplete.new_inventory_item = inv; 1538 uploadComplete.new_inventory_item = inv;
975 uploadComplete.state = "complete"; 1539 uploadComplete.state = "complete";
976 1540
977 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1541 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
978 1542*/
1543 m_timeoutTimer.Stop();
979 httpListener.RemoveStreamHandler("POST", uploaderPath); 1544 httpListener.RemoveStreamHandler("POST", uploaderPath);
980 1545
981 // TODO: probably make this a better set of extensions here 1546 // TODO: probably make this a better set of extensions here
@@ -992,12 +1557,49 @@ namespace OpenSim.Region.ClientStack.Linden
992 handlerUpLoad = OnUpLoad; 1557 handlerUpLoad = OnUpLoad;
993 if (handlerUpLoad != null) 1558 if (handlerUpLoad != null)
994 { 1559 {
995 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1560 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1561 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
1562 }
1563 if (m_IsAtestUpload)
1564 {
1565 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1566 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1567 resperror.identifier = inv;
1568
1569 uploadComplete.error = resperror;
1570 uploadComplete.state = "Upload4Testing";
996 } 1571 }
1572 else
1573 {
1574 if (m_error == String.Empty)
1575 {
1576 uploadComplete.new_asset = newAssetID.ToString();
1577 uploadComplete.new_inventory_item = inv;
1578 // if (m_texturesFolder != UUID.Zero)
1579 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1580 uploadComplete.state = "complete";
1581 }
1582 else
1583 {
1584 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1585 resperror.message = m_error;
1586 resperror.identifier = inv;
997 1587
1588 uploadComplete.error = resperror;
1589 uploadComplete.state = "failed";
1590 }
1591 }
1592
1593 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
998 return res; 1594 return res;
999 } 1595 }
1000 1596
1597 private void TimedOut(object sender, ElapsedEventArgs args)
1598 {
1599 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1600 httpListener.RemoveStreamHandler("POST", uploaderPath);
1601 }
1602
1001 ///Left this in and commented in case there are unforseen issues 1603 ///Left this in and commented in case there are unforseen issues
1002 //private void SaveAssetToFile(string filename, byte[] data) 1604 //private void SaveAssetToFile(string filename, byte[] data)
1003 //{ 1605 //{
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 3cc3950..f6e501d 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -353,7 +353,7 @@ namespace OpenSim.Region.ClientStack.Linden
353 // TODO: Add EventQueueGet name/description for diagnostics 353 // TODO: Add EventQueueGet name/description for diagnostics
354 MainServer.Instance.AddPollServiceHTTPHandler( 354 MainServer.Instance.AddPollServiceHTTPHandler(
355 eventQueueGetPath, 355 eventQueueGetPath,
356 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID)); 356 new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 1000));
357 357
358// m_log.DebugFormat( 358// m_log.DebugFormat(
359// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", 359// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}",
@@ -395,7 +395,7 @@ namespace OpenSim.Region.ClientStack.Linden
395 } 395 }
396 } 396 }
397 397
398 public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request) 398 public Hashtable GetEvents(UUID requestID, UUID pAgentId)
399 { 399 {
400 if (DebugLevel >= 2) 400 if (DebugLevel >= 2)
401 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); 401 m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName);
@@ -467,8 +467,8 @@ namespace OpenSim.Region.ClientStack.Linden
467 responsedata["content_type"] = "text/plain"; 467 responsedata["content_type"] = "text/plain";
468 responsedata["keepalive"] = false; 468 responsedata["keepalive"] = false;
469 responsedata["reusecontext"] = false; 469 responsedata["reusecontext"] = false;
470 responsedata["str_response_string"] = "Upstream error: "; 470 responsedata["str_response_string"] = "<llsd></llsd>";
471 responsedata["error_status_text"] = "Upstream error:"; 471 responsedata["error_status_text"] = "<llsd></llsd>";
472 responsedata["http_protocol_version"] = "HTTP/1.0"; 472 responsedata["http_protocol_version"] = "HTTP/1.0";
473 return responsedata; 473 return responsedata;
474 } 474 }
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index dab727f..7dcf137 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
@@ -151,6 +151,12 @@ namespace OpenSim.Region.ClientStack.Linden
151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, 151 ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
152 uint locationID, uint flags, string capsURL, UUID agentID) 152 uint locationID, uint flags, string capsURL, UUID agentID)
153 { 153 {
154 // not sure why flags get overwritten here
155 if ((flags & (uint)TeleportFlags.IsFlying) != 0)
156 flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying;
157 else
158 flags = (uint)TeleportFlags.ViaLocation;
159
154 OSDMap info = new OSDMap(); 160 OSDMap info = new OSDMap();
155 info.Add("AgentID", OSD.FromUUID(agentID)); 161 info.Add("AgentID", OSD.FromUUID(agentID));
156 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? 162 info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this?
@@ -159,7 +165,8 @@ namespace OpenSim.Region.ClientStack.Linden
159 info.Add("SimAccess", OSD.FromInteger(simAccess)); 165 info.Add("SimAccess", OSD.FromInteger(simAccess));
160 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); 166 info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
161 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); 167 info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
162 info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation 168// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
169 info.Add("TeleportFlags", OSD.FromUInteger(flags));
163 170
164 OSDArray infoArr = new OSDArray(); 171 OSDArray infoArr = new OSDArray();
165 infoArr.Add(info); 172 infoArr.Add(info);
@@ -398,7 +405,7 @@ namespace OpenSim.Region.ClientStack.Linden
398 public static OSD partPhysicsProperties(uint localID, byte physhapetype, 405 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
399 float density, float friction, float bounce, float gravmod) 406 float density, float friction, float bounce, float gravmod)
400 { 407 {
401 408
402 OSDMap physinfo = new OSDMap(6); 409 OSDMap physinfo = new OSDMap(6);
403 physinfo["LocalID"] = localID; 410 physinfo["LocalID"] = localID;
404 physinfo["Density"] = density; 411 physinfo["Density"] = density;
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 8e1f63a..6ec1115 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Reflection; 32using System.Reflection;
32using System.IO; 33using System.IO;
34using System.Threading;
33using System.Web; 35using System.Web;
34using Mono.Addins; 36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
35using log4net; 38using log4net;
36using Nini.Config; 39using Nini.Config;
37using OpenMetaverse; 40using OpenMetaverse;
@@ -57,9 +60,45 @@ namespace OpenSim.Region.ClientStack.Linden
57 private IAssetService m_AssetService; 60 private IAssetService m_AssetService;
58 private bool m_Enabled = true; 61 private bool m_Enabled = true;
59 private string m_URL; 62 private string m_URL;
63
64 struct aPollRequest
65 {
66 public PollServiceMeshEventArgs thepoll;
67 public UUID reqID;
68 public Hashtable request;
69 }
70
71 public class aPollResponse
72 {
73 public Hashtable response;
74 public int bytes;
75 public int lod;
76 }
77
78
79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80
81 private static GetMeshHandler m_getMeshHandler;
82
83 private IAssetService m_assetService = null;
84
85 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
86 private static Thread[] m_workerThreads = null;
87
88 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
89 new OpenMetaverse.BlockingQueue<aPollRequest>();
90
91 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
60 92
61 #region Region Module interfaceBase Members 93 #region Region Module interfaceBase Members
62 94
95 ~GetMeshModule()
96 {
97 foreach (Thread t in m_workerThreads)
98 Watchdog.AbortThread(t.ManagedThreadId);
99
100 }
101
63 public Type ReplaceableInterface 102 public Type ReplaceableInterface
64 { 103 {
65 get { return null; } 104 get { return null; }
@@ -75,6 +114,7 @@ namespace OpenSim.Region.ClientStack.Linden
75 // Cap doesn't exist 114 // Cap doesn't exist
76 if (m_URL != string.Empty) 115 if (m_URL != string.Empty)
77 m_Enabled = true; 116 m_Enabled = true;
117
78 } 118 }
79 119
80 public void AddRegion(Scene pScene) 120 public void AddRegion(Scene pScene)
@@ -83,6 +123,8 @@ namespace OpenSim.Region.ClientStack.Linden
83 return; 123 return;
84 124
85 m_scene = pScene; 125 m_scene = pScene;
126
127 m_assetService = pScene.AssetService;
86 } 128 }
87 129
88 public void RemoveRegion(Scene scene) 130 public void RemoveRegion(Scene scene)
@@ -91,6 +133,9 @@ namespace OpenSim.Region.ClientStack.Linden
91 return; 133 return;
92 134
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
136 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
137 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
138
94 m_scene = null; 139 m_scene = null;
95 } 140 }
96 141
@@ -101,6 +146,27 @@ namespace OpenSim.Region.ClientStack.Linden
101 146
102 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 147 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 148 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
149 // We'll reuse the same handler for all requests.
150 m_getMeshHandler = new GetMeshHandler(m_assetService);
151 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
152 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
153
154 if (m_workerThreads == null)
155 {
156 m_workerThreads = new Thread[2];
157
158 for (uint i = 0; i < 2; i++)
159 {
160 m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
161 String.Format("MeshWorkerThread{0}", i),
162 ThreadPriority.Normal,
163 false,
164 false,
165 null,
166 int.MaxValue);
167 }
168 }
169
104 } 170 }
105 171
106 172
@@ -110,25 +176,212 @@ namespace OpenSim.Region.ClientStack.Linden
110 176
111 #endregion 177 #endregion
112 178
179 private void DoMeshRequests()
180 {
181 while (true)
182 {
183 aPollRequest poolreq = m_queue.Dequeue();
184
185 poolreq.thepoll.Process(poolreq);
186 }
187 }
188
189 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
190 public void ThrottleUpdate(ScenePresence p)
191 {
192 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
193 UUID user = p.UUID;
194 int imagethrottle = ExtractTaskThrottle(throttles);
195 PollServiceMeshEventArgs args;
196 if (m_pollservices.TryGetValue(user, out args))
197 {
198 args.UpdateThrottle(imagethrottle, p);
199 }
200 }
201
202 private int ExtractTaskThrottle(byte[] pthrottles)
203 {
204
205 byte[] adjData;
206 int pos = 0;
207
208 if (!BitConverter.IsLittleEndian)
209 {
210 byte[] newData = new byte[7 * 4];
211 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
212
213 for (int i = 0; i < 7; i++)
214 Array.Reverse(newData, i * 4, 4);
215
216 adjData = newData;
217 }
218 else
219 {
220 adjData = pthrottles;
221 }
222
223 // 0.125f converts from bits to bytes
224 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
225 //pos += 4;
226 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
227 //pos += 4;
228 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
229 // pos += 4;
230 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
231 // pos += 4;
232 pos += 16;
233 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 // pos += 4;
235 //int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
236 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
237 return task;
238 }
239
240 private class PollServiceMeshEventArgs : PollServiceEventArgs
241 {
242 private List<Hashtable> requests =
243 new List<Hashtable>();
244 private Dictionary<UUID, aPollResponse> responses =
245 new Dictionary<UUID, aPollResponse>();
246
247 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue)
251 {
252 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
254 // x is request id, y is userid
255 HasEvents = (x, y) =>
256 {
257 lock (responses)
258 {
259 bool ret = m_throttler.hasEvents(x, responses);
260 m_throttler.ProcessTime();
261 return ret;
262
263 }
264 };
265 GetEvents = (x, y) =>
266 {
267 lock (responses)
268 {
269 try
270 {
271 return responses[x].response;
272 }
273 finally
274 {
275 m_throttler.ProcessTime();
276 responses.Remove(x);
277 }
278 }
279 };
280 // x is request id, y is request data hashtable
281 Request = (x, y) =>
282 {
283 aPollRequest reqinfo = new aPollRequest();
284 reqinfo.thepoll = this;
285 reqinfo.reqID = x;
286 reqinfo.request = y;
287
288 m_queue.Enqueue(reqinfo);
289 };
290
291 // this should never happen except possible on shutdown
292 NoEvents = (x, y) =>
293 {
294 /*
295 lock (requests)
296 {
297 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
298 requests.Remove(request);
299 }
300 */
301 Hashtable response = new Hashtable();
302
303 response["int_response_code"] = 500;
304 response["str_response_string"] = "Script timeout";
305 response["content_type"] = "text/plain";
306 response["keepalive"] = false;
307 response["reusecontext"] = false;
308
309 return response;
310 };
311 }
312
313 public void Process(aPollRequest requestinfo)
314 {
315 Hashtable response;
316
317 UUID requestID = requestinfo.reqID;
318
319 // If the avatar is gone, don't bother to get the texture
320 if (m_scene.GetScenePresence(Id) == null)
321 {
322 response = new Hashtable();
323
324 response["int_response_code"] = 500;
325 response["str_response_string"] = "Script timeout";
326 response["content_type"] = "text/plain";
327 response["keepalive"] = false;
328 response["reusecontext"] = false;
329
330 lock (responses)
331 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
332
333 return;
334 }
335
336 response = m_getMeshHandler.Handle(requestinfo.request);
337 lock (responses)
338 {
339 responses[requestID] = new aPollResponse()
340 {
341 bytes = (int)response["int_bytes"],
342 lod = (int)response["int_lod"],
343 response = response
344 };
345
346 }
347 m_throttler.ProcessTime();
348 }
349
350 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
351 {
352 m_throttler.UpdateThrottle(pimagethrottle, p);
353 }
354 }
113 355
114 public void RegisterCaps(UUID agentID, Caps caps) 356 public void RegisterCaps(UUID agentID, Caps caps)
115 { 357 {
116// UUID capID = UUID.Random(); 358// UUID capID = UUID.Random();
117
118 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
119 if (m_URL == "localhost") 359 if (m_URL == "localhost")
120 { 360 {
121// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 361 string capUrl = "/CAPS/" + UUID.Random() + "/";
122 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); 362
123 IRequestHandler reqHandler 363 // Register this as a poll service
124 = new RestHTTPHandler( 364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
125 "GET", 365
126 "/CAPS/" + UUID.Random(), 366 args.Type = PollServiceEventArgs.EventType.Mesh;
127 httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), 367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
128 "GetMesh", 368
129 agentID.ToString()); 369 string hostName = m_scene.RegionInfo.ExternalHostName;
370 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
371 string protocol = "http";
130 372
131 caps.RegisterHandler("GetMesh", reqHandler); 373 if (MainServer.Instance.UseSSL)
374 {
375 hostName = MainServer.Instance.SSLCommonName;
376 port = MainServer.Instance.SSLPort;
377 protocol = "https";
378 }
379 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
380 m_pollservices[agentID] = args;
381 m_capsDict[agentID] = capUrl;
382
383
384
132 } 385 }
133 else 386 else
134 { 387 {
@@ -136,6 +389,177 @@ namespace OpenSim.Region.ClientStack.Linden
136 caps.RegisterHandler("GetMesh", m_URL); 389 caps.RegisterHandler("GetMesh", m_URL);
137 } 390 }
138 } 391 }
392 private void DeregisterCaps(UUID agentID, Caps caps)
393 {
394 string capUrl;
395 PollServiceMeshEventArgs args;
396 if (m_capsDict.TryGetValue(agentID, out capUrl))
397 {
398 MainServer.Instance.RemoveHTTPHandler("", capUrl);
399 m_capsDict.Remove(agentID);
400 }
401 if (m_pollservices.TryGetValue(agentID, out args))
402 {
403 m_pollservices.Remove(agentID);
404 }
405 }
406
407 internal sealed class MeshCapsDataThrottler
408 {
409
410 private volatile int currenttime = 0;
411 private volatile int lastTimeElapsed = 0;
412 private volatile int BytesSent = 0;
413 private int Lod3 = 0;
414 private int Lod2 = 0;
415 private int Lod1 = 0;
416 private int UserSetThrottle = 0;
417 private int UDPSetThrottle = 0;
418 private int CapSetThrottle = 0;
419 private float CapThrottleDistributon = 0.30f;
420 private readonly Scene m_scene;
421 private ThrottleOutPacketType Throttle;
422 private readonly UUID User;
423
424 public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene, UUID puser)
425 {
426 ThrottleBytes = pBytes;
427 lastTimeElapsed = Util.EnvironmentTickCount();
428 Throttle = ThrottleOutPacketType.Task;
429 m_scene = pScene;
430 User = puser;
431 }
432
433
434 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
435 {
436 const float ThirtyPercent = 0.30f;
437 const float FivePercent = 0.05f;
438 PassTime();
439 // Note, this is called IN LOCK
440 bool haskey = responses.ContainsKey(key);
441
442 if (responses.Count > 2)
443 {
444 SplitThrottle(ThirtyPercent);
445 }
446 else
447 {
448 SplitThrottle(FivePercent);
449 }
450
451 if (!haskey)
452 {
453 return false;
454 }
455 aPollResponse response;
456 if (responses.TryGetValue(key, out response))
457 {
458 float LOD3Over = (((ThrottleBytes*CapThrottleDistributon)%50000) + 1);
459 float LOD2Over = (((ThrottleBytes*CapThrottleDistributon)%10000) + 1);
460 // Normal
461 if (BytesSent + response.bytes <= ThrottleBytes)
462 {
463 BytesSent += response.bytes;
464
465 return true;
466 }
467 // Lod3 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
468 else if (response.bytes > ThrottleBytes && Lod3 <= ((LOD3Over < 1)? 1: LOD3Over) )
469 {
470 Interlocked.Increment(ref Lod3);
471 BytesSent += response.bytes;
472
473 return true;
474 }
475 // Lod2 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
476 else if (response.bytes > ThrottleBytes && Lod2 <= ((LOD2Over < 1) ? 1 : LOD2Over))
477 {
478 Interlocked.Increment(ref Lod2);
479 BytesSent += response.bytes;
480
481 return true;
482 }
483 else
484 {
485 return false;
486 }
487 }
488
489 return haskey;
490 }
491 public void SubtractBytes(int bytes,int lod)
492 {
493 BytesSent -= bytes;
494 }
495 private void SplitThrottle(float percentMultiplier)
496 {
497
498 if (CapThrottleDistributon != percentMultiplier) // don't switch it if it's already set at the % multipler
499 {
500 CapThrottleDistributon = percentMultiplier;
501 ScenePresence p;
502 if (m_scene.TryGetScenePresence(User, out p)) // If we don't get a user they're not here anymore.
503 {
504// AlterThrottle(UserSetThrottle, p);
505 UpdateThrottle(UserSetThrottle, p);
506 }
507 }
508 }
509
510 public void ProcessTime()
511 {
512 PassTime();
513 }
514
515
516 private void PassTime()
517 {
518 currenttime = Util.EnvironmentTickCount();
519 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
520 //processTimeBasedActions(responses);
521 if (currenttime - timeElapsed >= 1000)
522 {
523 lastTimeElapsed = Util.EnvironmentTickCount();
524 BytesSent -= ThrottleBytes;
525 if (BytesSent < 0) BytesSent = 0;
526 if (BytesSent < ThrottleBytes)
527 {
528 Lod3 = 0;
529 Lod2 = 0;
530 Lod1 = 0;
531 }
532 }
533 }
534 private void AlterThrottle(int setting, ScenePresence p)
535 {
536 p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
537 }
538
539 public int ThrottleBytes
540 {
541 get { return CapSetThrottle; }
542 set { CapSetThrottle = value; }
543 }
544
545 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
546 {
547 // Client set throttle !
548 UserSetThrottle = pimagethrottle;
549 CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
550// UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
551
552 float udp = 1.0f - CapThrottleDistributon;
553 if(udp < 0.5f)
554 udp = 0.5f;
555 UDPSetThrottle = (int) ((float)pimagethrottle * udp);
556 if (CapSetThrottle < 4068)
557 CapSetThrottle = 4068; // at least two discovery mesh
558 p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
559 ProcessTime();
560
561 }
562 }
139 563
140 } 564 }
141} 565}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 13415f8..d4dbfb9 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -27,18 +27,13 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Specialized; 30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection; 31using System.Reflection;
34using System.IO; 32using System.Threading;
35using System.Web;
36using log4net; 33using log4net;
37using Nini.Config; 34using Nini.Config;
38using Mono.Addins; 35using Mono.Addins;
39using OpenMetaverse; 36using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework; 37using OpenSim.Framework;
43using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
@@ -47,6 +42,7 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
50 46
51namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
52{ 48{
@@ -54,57 +50,131 @@ namespace OpenSim.Region.ClientStack.Linden
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] 50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 51 public class GetTextureModule : INonSharedRegionModule
56 { 52 {
57// private static readonly ILog m_log = 53
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 struct aPollRequest
59 55 {
56 public PollServiceTextureEventArgs thepoll;
57 public UUID reqID;
58 public Hashtable request;
59 }
60
61 public class aPollResponse
62 {
63 public Hashtable response;
64 public int bytes;
65 }
66
67
68 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69
60 private Scene m_scene; 70 private Scene m_scene;
61 private IAssetService m_assetService;
62 71
63 private bool m_Enabled = false; 72 private static GetTextureHandler m_getTextureHandler;
73
74 private IAssetService m_assetService = null;
75
76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
77 private static Thread[] m_workerThreads = null;
64 78
65 // TODO: Change this to a config option 79 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
66 const string REDIRECT_URL = null; 80 new OpenMetaverse.BlockingQueue<aPollRequest>();
67 81
68 private string m_URL; 82 private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
69 83
70 #region ISharedRegionModule Members 84 #region ISharedRegionModule Members
71 85
72 public void Initialise(IConfigSource source) 86 public void Initialise(IConfigSource source)
73 { 87 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null)
76 return;
77
78 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist
80 if (m_URL != string.Empty)
81 m_Enabled = true;
82 } 88 }
83 89
84 public void AddRegion(Scene s) 90 public void AddRegion(Scene s)
85 { 91 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 92 m_scene = s;
93 m_assetService = s.AssetService;
90 } 94 }
91 95
92 public void RemoveRegion(Scene s) 96 public void RemoveRegion(Scene s)
93 { 97 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
99 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
100 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
98 m_scene = null; 101 m_scene = null;
99 } 102 }
100 103
101 public void RegionLoaded(Scene s) 104 public void RegionLoaded(Scene s)
102 { 105 {
103 if (!m_Enabled) 106 // We'll reuse the same handler for all requests.
104 return; 107 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 108
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 109 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
110 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
111 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
112
113 if (m_workerThreads == null)
114 {
115 m_workerThreads = new Thread[2];
116
117 for (uint i = 0; i < 2; i++)
118 {
119 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
120 String.Format("TextureWorkerThread{0}", i),
121 ThreadPriority.Normal,
122 false,
123 false,
124 null,
125 int.MaxValue);
126 }
127 }
128 }
129 private int ExtractImageThrottle(byte[] pthrottles)
130 {
131
132 byte[] adjData;
133 int pos = 0;
134
135 if (!BitConverter.IsLittleEndian)
136 {
137 byte[] newData = new byte[7 * 4];
138 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
139
140 for (int i = 0; i < 7; i++)
141 Array.Reverse(newData, i * 4, 4);
142
143 adjData = newData;
144 }
145 else
146 {
147 adjData = pthrottles;
148 }
149
150 // 0.125f converts from bits to bytes
151 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
152 //pos += 4;
153 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
154 //pos += 4;
155 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
156 // pos += 4;
157 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
158 // pos += 4;
159 // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
160 // pos += 4;
161 pos = pos + 20;
162 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
163 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
164 return texture;
165 }
166
167 // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
168 public void ThrottleUpdate(ScenePresence p)
169 {
170 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
171 UUID user = p.UUID;
172 int imagethrottle = ExtractImageThrottle(throttles);
173 PollServiceTextureEventArgs args;
174 if (m_pollservices.TryGetValue(user,out args))
175 {
176 args.UpdateThrottle(imagethrottle);
177 }
108 } 178 }
109 179
110 public void PostInitialise() 180 public void PostInitialise()
@@ -122,24 +192,250 @@ namespace OpenSim.Region.ClientStack.Linden
122 192
123 #endregion 193 #endregion
124 194
125 public void RegisterCaps(UUID agentID, Caps caps) 195 ~GetTextureModule()
196 {
197 foreach (Thread t in m_workerThreads)
198 Watchdog.AbortThread(t.ManagedThreadId);
199
200 }
201
202 private class PollServiceTextureEventArgs : PollServiceEventArgs
126 { 203 {
127 UUID capID = UUID.Random(); 204 private List<Hashtable> requests =
205 new List<Hashtable>();
206 private Dictionary<UUID, aPollResponse> responses =
207 new Dictionary<UUID, aPollResponse>();
128 208
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 209 private Scene m_scene;
130 if (m_URL == "localhost") 210 private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
211 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
212 base(null, null, null, null, pId, int.MaxValue)
131 { 213 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 214 m_scene = scene;
133 caps.RegisterHandler( 215 // x is request id, y is userid
134 "GetTexture", 216 HasEvents = (x, y) =>
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 217 {
218 lock (responses)
219 {
220 bool ret = m_throttler.hasEvents(x, responses);
221 m_throttler.ProcessTime();
222 return ret;
223
224 }
225 };
226 GetEvents = (x, y) =>
227 {
228 lock (responses)
229 {
230 try
231 {
232 return responses[x].response;
233 }
234 finally
235 {
236 responses.Remove(x);
237 }
238 }
239 };
240 // x is request id, y is request data hashtable
241 Request = (x, y) =>
242 {
243 aPollRequest reqinfo = new aPollRequest();
244 reqinfo.thepoll = this;
245 reqinfo.reqID = x;
246 reqinfo.request = y;
247
248 m_queue.Enqueue(reqinfo);
249 };
250
251 // this should never happen except possible on shutdown
252 NoEvents = (x, y) =>
253 {
254/*
255 lock (requests)
256 {
257 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
258 requests.Remove(request);
259 }
260*/
261 Hashtable response = new Hashtable();
262
263 response["int_response_code"] = 500;
264 response["str_response_string"] = "Script timeout";
265 response["content_type"] = "text/plain";
266 response["keepalive"] = false;
267 response["reusecontext"] = false;
268
269 return response;
270 };
136 } 271 }
137 else 272
273 public void Process(aPollRequest requestinfo)
274 {
275 Hashtable response;
276
277 UUID requestID = requestinfo.reqID;
278
279 // If the avatar is gone, don't bother to get the texture
280 if (m_scene.GetScenePresence(Id) == null)
281 {
282 response = new Hashtable();
283
284 response["int_response_code"] = 500;
285 response["str_response_string"] = "Script timeout";
286 response["content_type"] = "text/plain";
287 response["keepalive"] = false;
288 response["reusecontext"] = false;
289
290 lock (responses)
291 responses[requestID] = new aPollResponse() {bytes = 0, response = response};
292
293 return;
294 }
295
296 response = m_getTextureHandler.Handle(requestinfo.request);
297 lock (responses)
298 {
299 responses[requestID] = new aPollResponse()
300 {
301 bytes = (int) response["int_bytes"],
302 response = response
303 };
304
305 }
306 m_throttler.ProcessTime();
307 }
308
309 internal void UpdateThrottle(int pimagethrottle)
310 {
311 m_throttler.ThrottleBytes = pimagethrottle;
312 }
313 }
314
315 private void RegisterCaps(UUID agentID, Caps caps)
316 {
317 string capUrl = "/CAPS/" + UUID.Random() + "/";
318
319 // Register this as a poll service
320 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
321
322 args.Type = PollServiceEventArgs.EventType.Texture;
323 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
324
325 string hostName = m_scene.RegionInfo.ExternalHostName;
326 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
327 string protocol = "http";
328
329 if (MainServer.Instance.UseSSL)
330 {
331 hostName = MainServer.Instance.SSLCommonName;
332 port = MainServer.Instance.SSLPort;
333 protocol = "https";
334 }
335 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
336 m_pollservices[agentID] = args;
337 m_capsDict[agentID] = capUrl;
338 }
339
340 private void DeregisterCaps(UUID agentID, Caps caps)
341 {
342 string capUrl;
343 PollServiceTextureEventArgs args;
344 if (m_capsDict.TryGetValue(agentID, out capUrl))
345 {
346 MainServer.Instance.RemoveHTTPHandler("", capUrl);
347 m_capsDict.Remove(agentID);
348 }
349 if (m_pollservices.TryGetValue(agentID, out args))
138 { 350 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 351 m_pollservices.Remove(agentID);
140 caps.RegisterHandler("GetTexture", m_URL);
141 } 352 }
142 } 353 }
143 354
355 private void DoTextureRequests()
356 {
357 while (true)
358 {
359 aPollRequest poolreq = m_queue.Dequeue();
360
361 poolreq.thepoll.Process(poolreq);
362 }
363 }
364 internal sealed class CapsDataThrottler
365 {
366
367 private volatile int currenttime = 0;
368 private volatile int lastTimeElapsed = 0;
369 private volatile int BytesSent = 0;
370 private int oversizedImages = 0;
371 public CapsDataThrottler(int pBytes, int max, int min)
372 {
373 ThrottleBytes = pBytes;
374 lastTimeElapsed = Util.EnvironmentTickCount();
375 }
376 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
377 {
378 PassTime();
379 // Note, this is called IN LOCK
380 bool haskey = responses.ContainsKey(key);
381 if (!haskey)
382 {
383 return false;
384 }
385 GetTextureModule.aPollResponse response;
386 if (responses.TryGetValue(key, out response))
387 {
388
389 // Normal
390 if (BytesSent + response.bytes <= ThrottleBytes)
391 {
392 BytesSent += response.bytes;
393 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
394 //m_actions.Add(timeBasedAction);
395 return true;
396 }
397 // Big textures
398 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
399 {
400 Interlocked.Increment(ref oversizedImages);
401 BytesSent += response.bytes;
402 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
403 //m_actions.Add(timeBasedAction);
404 return true;
405 }
406 else
407 {
408 return false;
409 }
410 }
411
412 return haskey;
413 }
414 public void ProcessTime()
415 {
416 PassTime();
417 }
418
419
420 private void PassTime()
421 {
422 currenttime = Util.EnvironmentTickCount();
423 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
424 //processTimeBasedActions(responses);
425 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
426 {
427 lastTimeElapsed = Util.EnvironmentTickCount();
428 BytesSent -= ThrottleBytes;
429 if (BytesSent < 0) BytesSent = 0;
430 if (BytesSent < ThrottleBytes)
431 {
432 oversizedImages = 0;
433 }
434 }
435 }
436 public int ThrottleBytes;
437 }
144 } 438 }
439
440
145} 441}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
index 45d33cd..1b68603 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs
@@ -129,15 +129,15 @@ namespace OpenSim.Region.ClientStack.Linden
129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); 129// m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request");
130 130
131 OSDMap data = new OSDMap(); 131 OSDMap data = new OSDMap();
132 ScenePresence sp = m_scene.GetScenePresence(agentID); 132// ScenePresence sp = m_scene.GetScenePresence(m_agentID);
133 data["username"] = sp.Firstname + "." + sp.Lastname; 133// data["username"] = sp.Firstname + "." + sp.Lastname;
134 data["display_name_next_update"] = new OSDDate(DateTime.Now); 134// data["display_name_next_update"] = new OSDDate(DateTime.Now);
135 data["legacy_first_name"] = sp.Firstname; 135// data["legacy_first_name"] = sp.Firstname;
136 data["mesh_upload_status"] = "valid"; 136 data["mesh_upload_status"] = "valid";
137 data["display_name"] = sp.Firstname + " " + sp.Lastname; 137// data["display_name"] = sp.Firstname + " " + sp.Lastname;
138 data["legacy_last_name"] = sp.Lastname; 138// data["legacy_last_name"] = sp.Lastname;
139 data["id"] = agentID; 139// data["id"] = m_agentID;
140 data["is_display_name_default"] = true; 140// data["is_display_name_default"] = true;
141 141
142 //Send back data 142 //Send back data
143 Hashtable responsedata = new Hashtable(); 143 Hashtable responsedata = new Hashtable();
@@ -148,4 +148,4 @@ namespace OpenSim.Region.ClientStack.Linden
148 return responsedata; 148 return responsedata;
149 } 149 }
150 } 150 }
151} \ No newline at end of file 151}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
deleted file mode 100644
index 5529550..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ /dev/null
@@ -1,296 +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;
47
48namespace OpenSim.Region.ClientStack.Linden
49{
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")]
51 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
52 {
53// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
55 private Scene m_scene;
56// private IAssetService m_assetService;
57 private bool m_dumpAssetsToFile = false;
58 private bool m_enabled = true;
59 private int m_levelUpload = 0;
60
61 #region Region Module interfaceBase Members
62
63
64 public Type ReplaceableInterface
65 {
66 get { return null; }
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig meshConfig = source.Configs["Mesh"];
72 if (meshConfig == null)
73 return;
74
75 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
76 m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
77 }
78
79 public void AddRegion(Scene pScene)
80 {
81 m_scene = pScene;
82 }
83
84 public void RemoveRegion(Scene scene)
85 {
86
87 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
88 m_scene = null;
89 }
90
91 public void RegionLoaded(Scene scene)
92 {
93
94// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
95 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
96 }
97
98 #endregion
99
100
101 #region Region Module interface
102
103
104
105 public void Close() { }
106
107 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
108
109
110 public void RegisterCaps(UUID agentID, Caps caps)
111 {
112 if(!m_enabled)
113 return;
114
115 UUID capID = UUID.Random();
116
117// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
118 caps.RegisterHandler(
119 "NewFileAgentInventoryVariablePrice",
120 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
121 "POST",
122 "/CAPS/" + capID.ToString(),
123 req => NewAgentInventoryRequest(req, agentID),
124 "NewFileAgentInventoryVariablePrice",
125 agentID.ToString()));
126 }
127
128 #endregion
129
130 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
131 {
132 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
133 // you need to be aware of this
134
135 //if (llsdRequest.asset_type == "texture" ||
136 // llsdRequest.asset_type == "animation" ||
137 // llsdRequest.asset_type == "sound")
138 // {
139 // check user level
140
141 ScenePresence avatar = null;
142 IClientAPI client = null;
143 m_scene.TryGetScenePresence(agentID, out avatar);
144
145 if (avatar != null)
146 {
147 client = avatar.ControllingClient;
148
149 if (avatar.UserLevel < m_levelUpload)
150 {
151 if (client != null)
152 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
153
154 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
155 errorResponse.rsvp = "";
156 errorResponse.state = "error";
157 return errorResponse;
158 }
159 }
160
161 // check funds
162 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
163
164 if (mm != null)
165 {
166 if (!mm.UploadCovered(agentID, mm.UploadCharge))
167 {
168 if (client != null)
169 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
170
171 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
172 errorResponse.rsvp = "";
173 errorResponse.state = "error";
174 return errorResponse;
175 }
176 }
177
178 // }
179
180 string assetName = llsdRequest.name;
181 string assetDes = llsdRequest.description;
182 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
183 UUID newAsset = UUID.Random();
184 UUID newInvItem = UUID.Random();
185 UUID parentFolder = llsdRequest.folder_id;
186 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
187
188 AssetUploader uploader =
189 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
190 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
191
192 MainServer.Instance.AddStreamHandler(
193 new BinaryStreamHandler(
194 "POST",
195 capsBase + uploaderPath,
196 uploader.uploaderCaps,
197 "NewFileAgentInventoryVariablePrice",
198 agentID.ToString()));
199
200 string protocol = "http://";
201
202 if (MainServer.Instance.UseSSL)
203 protocol = "https://";
204
205 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
206 uploaderPath;
207
208
209 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
210
211 uploadResponse.rsvp = uploaderURL;
212 uploadResponse.state = "upload";
213 uploadResponse.resource_cost = 0;
214 uploadResponse.upload_price = 0;
215
216 uploader.OnUpLoad += //UploadCompleteHandler;
217
218 delegate(
219 string passetName, string passetDescription, UUID passetID,
220 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
221 string passetType)
222 {
223 UploadCompleteHandler(passetName, passetDescription, passetID,
224 pinventoryItem, pparentFolder, pdata, pinventoryType,
225 passetType,agentID);
226 };
227
228 return uploadResponse;
229 }
230
231 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
232 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
233 string assetType,UUID AgentID)
234 {
235// m_log.DebugFormat(
236// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
237
238 sbyte assType = 0;
239 sbyte inType = 0;
240
241 if (inventoryType == "sound")
242 {
243 inType = 1;
244 assType = 1;
245 }
246 else if (inventoryType == "animation")
247 {
248 inType = 19;
249 assType = 20;
250 }
251 else if (inventoryType == "wearable")
252 {
253 inType = 18;
254 switch (assetType)
255 {
256 case "bodypart":
257 assType = 13;
258 break;
259 case "clothing":
260 assType = 5;
261 break;
262 }
263 }
264 else if (inventoryType == "mesh")
265 {
266 inType = (sbyte)InventoryType.Mesh;
267 assType = (sbyte)AssetType.Mesh;
268 }
269
270 AssetBase asset;
271 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
272 asset.Data = data;
273
274 if (m_scene.AssetService != null)
275 m_scene.AssetService.Store(asset);
276
277 InventoryItemBase item = new InventoryItemBase();
278 item.Owner = AgentID;
279 item.CreatorId = AgentID.ToString();
280 item.ID = inventoryItem;
281 item.AssetID = asset.FullID;
282 item.Description = assetDescription;
283 item.Name = assetName;
284 item.AssetType = assType;
285 item.InvType = inType;
286 item.Folder = parentFolder;
287 item.CurrentPermissions
288 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
289 item.BasePermissions = (uint)PermissionMask.All;
290 item.EveryOnePermissions = 0;
291 item.NextPermissions = (uint)PermissionMask.All;
292 item.CreationDate = Util.UnixTimeSinceEpoch();
293 m_scene.AddInventoryItem(item);
294 }
295 }
296}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 69dd76f..79d56c4 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -64,6 +64,8 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Commands m_commands = new Commands(); 64 private Commands m_commands = new Commands();
65 public ICommands Commands { get { return m_commands; } } 65 public ICommands Commands { get { return m_commands; } }
66 66
67 public event ConsoleMessage OnConsoleMessage;
68
67 public void Initialise(IConfigSource source) 69 public void Initialise(IConfigSource source)
68 { 70 {
69 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help); 71 m_commands.AddCommand( "Help", false, "help", "help [<item>]", "Display help on a particular command or on a list of commands in a category", Help);
@@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 104
103 public void RegisterCaps(UUID agentID, Caps caps) 105 public void RegisterCaps(UUID agentID, Caps caps)
104 { 106 {
105 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) 107 if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID))
106 return; 108 return;
107 109
108 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
@@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden
118 OSD osd = OSD.FromString(message); 120 OSD osd = OSD.FromString(message);
119 121
120 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); 122 m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID);
123
124 ConsoleMessage handlerConsoleMessage = OnConsoleMessage;
125
126 if (handlerConsoleMessage != null)
127 handlerConsoleMessage( agentID, message);
121 } 128 }
122 129
123 public bool RunCommand(string command, UUID invokerID) 130 public bool RunCommand(string command, UUID invokerID)
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
index 3b0ccd7..eca576d 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Drawing; 32using System.Drawing;
32using System.Drawing.Imaging; 33using System.Drawing.Imaging;
@@ -53,8 +54,8 @@ namespace OpenSim.Region.ClientStack.Linden
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")] 54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")]
54 public class UploadBakedTextureModule : INonSharedRegionModule 55 public class UploadBakedTextureModule : INonSharedRegionModule
55 { 56 {
56// private static readonly ILog m_log = 57 private static readonly ILog m_log =
57// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 59
59 /// <summary> 60 /// <summary>
60 /// For historical reasons this is fixed, but there 61 /// For historical reasons this is fixed, but there
@@ -64,31 +65,210 @@ namespace OpenSim.Region.ClientStack.Linden
64 private Scene m_scene; 65 private Scene m_scene;
65 private bool m_persistBakedTextures; 66 private bool m_persistBakedTextures;
66 67
68 private IBakedTextureModule m_BakedTextureModule;
69
67 public void Initialise(IConfigSource source) 70 public void Initialise(IConfigSource source)
68 { 71 {
69 IConfig appearanceConfig = source.Configs["Appearance"]; 72 IConfig appearanceConfig = source.Configs["Appearance"];
70 if (appearanceConfig != null) 73 if (appearanceConfig != null)
71 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 74 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
75
76
72 } 77 }
73 78
74 public void AddRegion(Scene s) 79 public void AddRegion(Scene s)
75 { 80 {
76 m_scene = s; 81 m_scene = s;
82
77 } 83 }
78 84
79 public void RemoveRegion(Scene s) 85 public void RemoveRegion(Scene s)
80 { 86 {
87 s.EventManager.OnRegisterCaps -= RegisterCaps;
88 s.EventManager.OnNewPresence -= RegisterNewPresence;
89 s.EventManager.OnRemovePresence -= DeRegisterPresence;
90 m_BakedTextureModule = null;
91 m_scene = null;
81 } 92 }
82 93
94
95
83 public void RegionLoaded(Scene s) 96 public void RegionLoaded(Scene s)
84 { 97 {
85 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 98 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
99 m_scene.EventManager.OnNewPresence += RegisterNewPresence;
100 m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
101
102 }
103
104 private void DeRegisterPresence(UUID agentId)
105 {
106 ScenePresence presence = null;
107 if (m_scene.TryGetScenePresence(agentId, out presence))
108 {
109 presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
110 }
111
112 }
113
114 private void RegisterNewPresence(ScenePresence presence)
115 {
116 presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
117
118 }
119
120 private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
121 {
122 int maxCacheitemsLoop = cacheItems.Length;
123 if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
124 {
125 maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
126 m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
127 }
128
129 m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
130 if (cacheItems.Length > 0)
131 {
132 m_log.Debug("[Cacheitems]: " + cacheItems.Length);
133 for (int iter = 0; iter < maxCacheitemsLoop; iter++)
134 {
135 m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
136 cacheItems[iter].TextureID);
137 }
138
139 ScenePresence p = null;
140 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
141 {
142
143 WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
144 if (existingitems == null)
145 {
146 if (m_BakedTextureModule != null)
147 {
148 WearableCacheItem[] savedcache = null;
149 try
150 {
151 if (p.Appearance.WearableCacheItemsDirty)
152 {
153 savedcache = m_BakedTextureModule.Get(p.UUID);
154 p.Appearance.WearableCacheItems = savedcache;
155 p.Appearance.WearableCacheItemsDirty = false;
156 }
157
158 }
159 /*
160 * The following Catch types DO NOT WORK with m_BakedTextureModule.Get
161 * it jumps to the General Packet Exception Handler if you don't catch Exception!
162 *
163 catch (System.Net.Sockets.SocketException)
164 {
165 cacheItems = null;
166 }
167 catch (WebException)
168 {
169 cacheItems = null;
170 }
171 catch (InvalidOperationException)
172 {
173 cacheItems = null;
174 } */
175 catch (Exception)
176 {
177 // The service logs a sufficient error message.
178 }
179
180
181 if (savedcache != null)
182 existingitems = savedcache;
183 }
184 }
185 // Existing items null means it's a fully new appearance
186 if (existingitems == null)
187 {
188
189 for (int i = 0; i < maxCacheitemsLoop; i++)
190 {
191 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
192 {
193 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
194 if (face == null)
195 {
196 textureEntry.CreateFace(cacheItems[i].TextureIndex);
197 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
198 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
199 continue;
200 }
201 cacheItems[i].TextureID =face.TextureID;
202 if (m_scene.AssetService != null)
203 cacheItems[i].TextureAsset =
204 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
205 }
206 else
207 {
208 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
209 }
210
211
212 }
213 }
214 else
215
216
217 {
218 // for each uploaded baked texture
219 for (int i = 0; i < maxCacheitemsLoop; i++)
220 {
221 if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
222 {
223 Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
224 if (face == null)
225 {
226 textureEntry.CreateFace(cacheItems[i].TextureIndex);
227 textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
228 AppearanceManager.DEFAULT_AVATAR_TEXTURE;
229 continue;
230 }
231 cacheItems[i].TextureID =
232 face.TextureID;
233 }
234 else
235 {
236 m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
237 }
238 }
239
240 for (int i = 0; i < maxCacheitemsLoop; i++)
241 {
242 if (cacheItems[i].TextureAsset == null)
243 {
244 cacheItems[i].TextureAsset =
245 m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
246 }
247 }
248 }
249
250
251
252 p.Appearance.WearableCacheItems = cacheItems;
253
254
255
256 if (m_BakedTextureModule != null)
257 {
258 m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
259 p.Appearance.WearableCacheItemsDirty = true;
260
261 }
262 }
263 }
86 } 264 }
87 265
88 public void PostInitialise() 266 public void PostInitialise()
89 { 267 {
90 } 268 }
91 269
270
271
92 public void Close() { } 272 public void Close() { }
93 273
94 public string Name { get { return "UploadBakedTextureModule"; } } 274 public string Name { get { return "UploadBakedTextureModule"; } }
@@ -100,15 +280,23 @@ namespace OpenSim.Region.ClientStack.Linden
100 280
101 public void RegisterCaps(UUID agentID, Caps caps) 281 public void RegisterCaps(UUID agentID, Caps caps)
102 { 282 {
283 UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
284 caps, m_scene.AssetService, m_persistBakedTextures);
285
286
287
103 caps.RegisterHandler( 288 caps.RegisterHandler(
104 "UploadBakedTexture", 289 "UploadBakedTexture",
105 new RestStreamHandler( 290 new RestStreamHandler(
106 "POST", 291 "POST",
107 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, 292 "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
108 new UploadBakedTextureHandler( 293 avatarhandler.UploadBakedTexture,
109 caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
110 "UploadBakedTexture", 294 "UploadBakedTexture",
111 agentID.ToString())); 295 agentID.ToString()));
296
297
298
299
112 } 300 }
113 } 301 }
114} \ No newline at end of file 302} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 6890f4a..707cc93 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -27,18 +27,25 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
32using System.Threading;
31using log4net; 33using log4net;
32using Nini.Config; 34using Nini.Config;
33using Mono.Addins; 35using Mono.Addins;
34using OpenMetaverse; 36using OpenMetaverse;
35using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Servers;
36using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
42using OpenSim.Framework.Capabilities;
39using OpenSim.Services.Interfaces; 43using OpenSim.Services.Interfaces;
40using Caps = OpenSim.Framework.Capabilities.Caps; 44using Caps = OpenSim.Framework.Capabilities.Caps;
41using OpenSim.Capabilities.Handlers; 45using OpenSim.Capabilities.Handlers;
46using OpenSim.Framework.Monitoring;
47using OpenMetaverse;
48using OpenMetaverse.StructuredData;
42 49
43namespace OpenSim.Region.ClientStack.Linden 50namespace OpenSim.Region.ClientStack.Linden
44{ 51{
@@ -48,67 +55,74 @@ namespace OpenSim.Region.ClientStack.Linden
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")]
49 public class WebFetchInvDescModule : INonSharedRegionModule 56 public class WebFetchInvDescModule : INonSharedRegionModule
50 { 57 {
51// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 class aPollRequest
59 {
60 public PollServiceInventoryEventArgs thepoll;
61 public UUID reqID;
62 public Hashtable request;
63 public ScenePresence presence;
64 public List<UUID> folders;
65 }
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 68
53 private Scene m_scene; 69 private Scene m_scene;
54 70
55 private IInventoryService m_InventoryService; 71 private IInventoryService m_InventoryService;
56 private ILibraryService m_LibraryService; 72 private ILibraryService m_LibraryService;
57 73
58 private bool m_Enabled; 74 private static WebFetchInvDescHandler m_webFetchHandler;
59 75
60 private string m_fetchInventoryDescendents2Url; 76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
61 private string m_webFetchInventoryDescendentsUrl; 77 private static Thread[] m_workerThreads = null;
62 78
63 private WebFetchInvDescHandler m_webFetchHandler; 79 private static DoubleQueue<aPollRequest> m_queue =
80 new DoubleQueue<aPollRequest>();
64 81
65 #region ISharedRegionModule Members 82 #region ISharedRegionModule Members
66 83
67 public void Initialise(IConfigSource source) 84 public void Initialise(IConfigSource source)
68 { 85 {
69 IConfig config = source.Configs["ClientStack.LindenCaps"];
70 if (config == null)
71 return;
72
73 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
74 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
75
76 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
77 {
78 m_Enabled = true;
79 }
80 } 86 }
81 87
82 public void AddRegion(Scene s) 88 public void AddRegion(Scene s)
83 { 89 {
84 if (!m_Enabled)
85 return;
86
87 m_scene = s; 90 m_scene = s;
88 } 91 }
89 92
90 public void RemoveRegion(Scene s) 93 public void RemoveRegion(Scene s)
91 { 94 {
92 if (!m_Enabled)
93 return;
94
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
96 m_scene = null; 97 m_scene = null;
97 } 98 }
98 99
99 public void RegionLoaded(Scene s) 100 public void RegionLoaded(Scene s)
100 { 101 {
101 if (!m_Enabled)
102 return;
103
104 m_InventoryService = m_scene.InventoryService; 102 m_InventoryService = m_scene.InventoryService;
105 m_LibraryService = m_scene.LibraryService; 103 m_LibraryService = m_scene.LibraryService;
106 104
107 // We'll reuse the same handler for all requests. 105 // We'll reuse the same handler for all requests.
108 if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost") 106 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
109 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
110 107
111 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 108 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
109 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
110
111 if (m_workerThreads == null)
112 {
113 m_workerThreads = new Thread[2];
114
115 for (uint i = 0; i < 2; i++)
116 {
117 m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests,
118 String.Format("InventoryWorkerThread{0}", i),
119 ThreadPriority.Normal,
120 false,
121 true,
122 null,
123 int.MaxValue);
124 }
125 }
112 } 126 }
113 127
114 public void PostInitialise() 128 public void PostInitialise()
@@ -126,43 +140,192 @@ namespace OpenSim.Region.ClientStack.Linden
126 140
127 #endregion 141 #endregion
128 142
129 private void RegisterCaps(UUID agentID, Caps caps) 143 ~WebFetchInvDescModule()
130 { 144 {
131 if (m_webFetchInventoryDescendentsUrl != "") 145 foreach (Thread t in m_workerThreads)
132 RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl); 146 Watchdog.AbortThread(t.ManagedThreadId);
133
134 if (m_fetchInventoryDescendents2Url != "")
135 RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
136 } 147 }
137 148
138 private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) 149 private class PollServiceInventoryEventArgs : PollServiceEventArgs
139 { 150 {
140 string capUrl; 151 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
152
153 private Dictionary<UUID, Hashtable> responses =
154 new Dictionary<UUID, Hashtable>();
155
156 private Scene m_scene;
141 157
142 if (url == "localhost") 158 public PollServiceInventoryEventArgs(Scene scene, UUID pId) :
159 base(null, null, null, null, pId, int.MaxValue)
143 { 160 {
144 capUrl = "/CAPS/" + UUID.Random(); 161 m_scene = scene;
162
163 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
164 GetEvents = (x, y) =>
165 {
166 lock (responses)
167 {
168 try
169 {
170 return responses[x];
171 }
172 finally
173 {
174 responses.Remove(x);
175 }
176 }
177 };
178
179 Request = (x, y) =>
180 {
181 ScenePresence sp = m_scene.GetScenePresence(Id);
182 if (sp == null)
183 {
184 m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id);
185 return;
186 }
187
188 aPollRequest reqinfo = new aPollRequest();
189 reqinfo.thepoll = this;
190 reqinfo.reqID = x;
191 reqinfo.request = y;
192 reqinfo.presence = sp;
193 reqinfo.folders = new List<UUID>();
194
195 // Decode the request here
196 string request = y["body"].ToString();
197
198 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
199
200 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
201 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
202
203 Hashtable hash = new Hashtable();
204 try
205 {
206 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
207 }
208 catch (LLSD.LLSDParseException e)
209 {
210 m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
211 m_log.Error("Request: " + request);
212 return;
213 }
214 catch (System.Xml.XmlException)
215 {
216 m_log.ErrorFormat("[INVENTORY]: XML Format error");
217 }
218
219 ArrayList foldersrequested = (ArrayList)hash["folders"];
220
221 bool highPriority = false;
222
223 for (int i = 0; i < foldersrequested.Count; i++)
224 {
225 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
226 string folder = inventoryhash["folder_id"].ToString();
227 UUID folderID;
228 if (UUID.TryParse(folder, out folderID))
229 {
230 if (!reqinfo.folders.Contains(folderID))
231 {
232 if (sp.COF != UUID.Zero && sp.COF == folderID)
233 highPriority = true;
234 reqinfo.folders.Add(folderID);
235 }
236 }
237 }
238
239 if (highPriority)
240 m_queue.EnqueueHigh(reqinfo);
241 else
242 m_queue.EnqueueLow(reqinfo);
243 };
244
245 NoEvents = (x, y) =>
246 {
247/*
248 lock (requests)
249 {
250 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
251 requests.Remove(request);
252 }
253*/
254 Hashtable response = new Hashtable();
255
256 response["int_response_code"] = 500;
257 response["str_response_string"] = "Script timeout";
258 response["content_type"] = "text/plain";
259 response["keepalive"] = false;
260 response["reusecontext"] = false;
261
262 return response;
263 };
264 }
145 265
146 IRequestHandler reqHandler 266 public void Process(aPollRequest requestinfo)
147 = new RestStreamHandler( 267 {
148 "POST", 268 UUID requestID = requestinfo.reqID;
149 capUrl, 269
150 m_webFetchHandler.FetchInventoryDescendentsRequest, 270 Hashtable response = new Hashtable();
151 "FetchInventoryDescendents2", 271
152 agentID.ToString()); 272 response["int_response_code"] = 200;
273 response["content_type"] = "text/plain";
274 response["keepalive"] = false;
275 response["reusecontext"] = false;
153 276
154 caps.RegisterHandler(capName, reqHandler); 277 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
278 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
279
280 lock (responses)
281 responses[requestID] = response;
155 } 282 }
156 else 283 }
284
285 private void RegisterCaps(UUID agentID, Caps caps)
286 {
287 string capUrl = "/CAPS/" + UUID.Random() + "/";
288
289 // Register this as a poll service
290 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
291
292 args.Type = PollServiceEventArgs.EventType.Inventory;
293 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
294
295 string hostName = m_scene.RegionInfo.ExternalHostName;
296 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
297 string protocol = "http";
298
299 if (MainServer.Instance.UseSSL)
157 { 300 {
158 capUrl = url; 301 hostName = MainServer.Instance.SSLCommonName;
302 port = MainServer.Instance.SSLPort;
303 protocol = "https";
304 }
305 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
306
307 m_capsDict[agentID] = capUrl;
308 }
159 309
160 caps.RegisterHandler(capName, capUrl); 310 private void DeregisterCaps(UUID agentID, Caps caps)
311 {
312 string capUrl;
313
314 if (m_capsDict.TryGetValue(agentID, out capUrl))
315 {
316 MainServer.Instance.RemoveHTTPHandler("", capUrl);
317 m_capsDict.Remove(agentID);
161 } 318 }
319 }
162 320
163// m_log.DebugFormat( 321 private void DoInventoryRequests()
164// "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}", 322 {
165// capName, capUrl, m_scene.RegionInfo.RegionName, agentID); 323 while (true)
324 {
325 aPollRequest poolreq = m_queue.Dequeue();
326
327 poolreq.thepoll.Process(poolreq);
328 }
166 } 329 }
167 } 330 }
168} \ No newline at end of file 331}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index afbe56b..3995620 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 m_stopPacket = TexturePacketCount(); 234 m_stopPacket = TexturePacketCount();
235 } 235 }
236 236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
237 m_currentPacket = StartPacket; 240 m_currentPacket = StartPacket;
238 } 241 }
239 } 242 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 7ea538c..5b2bad4 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -99,6 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 public event AvatarPickerRequest OnAvatarPickerRequest; 99 public event AvatarPickerRequest OnAvatarPickerRequest;
100 public event StartAnim OnStartAnim; 100 public event StartAnim OnStartAnim;
101 public event StopAnim OnStopAnim; 101 public event StopAnim OnStopAnim;
102 public event ChangeAnim OnChangeAnim;
102 public event Action<IClientAPI> OnRequestAvatarsData; 103 public event Action<IClientAPI> OnRequestAvatarsData;
103 public event LinkObjects OnLinkObjects; 104 public event LinkObjects OnLinkObjects;
104 public event DelinkObjects OnDelinkObjects; 105 public event DelinkObjects OnDelinkObjects;
@@ -126,6 +127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; 127 public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily;
127 public event UpdatePrimFlags OnUpdatePrimFlags; 128 public event UpdatePrimFlags OnUpdatePrimFlags;
128 public event UpdatePrimTexture OnUpdatePrimTexture; 129 public event UpdatePrimTexture OnUpdatePrimTexture;
130 public event ClientChangeObject onClientChangeObject;
129 public event UpdateVector OnUpdatePrimGroupPosition; 131 public event UpdateVector OnUpdatePrimGroupPosition;
130 public event UpdateVector OnUpdatePrimSinglePosition; 132 public event UpdateVector OnUpdatePrimSinglePosition;
131 public event UpdatePrimRotation OnUpdatePrimGroupRotation; 133 public event UpdatePrimRotation OnUpdatePrimGroupRotation;
@@ -159,6 +161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
159 public event RequestTaskInventory OnRequestTaskInventory; 161 public event RequestTaskInventory OnRequestTaskInventory;
160 public event UpdateInventoryItem OnUpdateInventoryItem; 162 public event UpdateInventoryItem OnUpdateInventoryItem;
161 public event CopyInventoryItem OnCopyInventoryItem; 163 public event CopyInventoryItem OnCopyInventoryItem;
164 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
162 public event MoveInventoryItem OnMoveInventoryItem; 165 public event MoveInventoryItem OnMoveInventoryItem;
163 public event RemoveInventoryItem OnRemoveInventoryItem; 166 public event RemoveInventoryItem OnRemoveInventoryItem;
164 public event RemoveInventoryFolder OnRemoveInventoryFolder; 167 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -257,7 +260,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
257 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 260 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
258 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 261 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
259 public event ClassifiedDelete OnClassifiedDelete; 262 public event ClassifiedDelete OnClassifiedDelete;
260 public event ClassifiedDelete OnClassifiedGodDelete; 263 public event ClassifiedGodDelete OnClassifiedGodDelete;
261 public event EventNotificationAddRequest OnEventNotificationAddRequest; 264 public event EventNotificationAddRequest OnEventNotificationAddRequest;
262 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 265 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
263 public event EventGodDelete OnEventGodDelete; 266 public event EventGodDelete OnEventGodDelete;
@@ -288,10 +291,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
288 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 291 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
289 public event SimWideDeletesDelegate OnSimWideDeletes; 292 public event SimWideDeletesDelegate OnSimWideDeletes;
290 public event SendPostcard OnSendPostcard; 293 public event SendPostcard OnSendPostcard;
294 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
291 public event MuteListEntryUpdate OnUpdateMuteListEntry; 295 public event MuteListEntryUpdate OnUpdateMuteListEntry;
292 public event MuteListEntryRemove OnRemoveMuteListEntry; 296 public event MuteListEntryRemove OnRemoveMuteListEntry;
293 public event GodlikeMessage onGodlikeMessage; 297 public event GodlikeMessage onGodlikeMessage;
294 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; 298 public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
299 public event GenericCall2 OnUpdateThrottles;
295 300
296 #endregion Events 301 #endregion Events
297 302
@@ -326,6 +331,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
326 private Prioritizer m_prioritizer; 331 private Prioritizer m_prioritizer;
327 private bool m_disableFacelights = false; 332 private bool m_disableFacelights = false;
328 333
334 private bool m_VelocityInterpolate = false;
335 private const uint MaxTransferBytesPerPacket = 600;
336
337
329 /// <value> 338 /// <value>
330 /// List used in construction of data blocks for an object update packet. This is to stop us having to 339 /// List used in construction of data blocks for an object update packet. This is to stop us having to
331 /// continually recreate it. 340 /// continually recreate it.
@@ -337,14 +346,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
337 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 346 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
338 /// ownerless phantom. 347 /// ownerless phantom.
339 /// 348 ///
340 /// All manipulation of this set has to occur under a lock 349 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
341 /// 350 ///
342 /// </value> 351 /// </value>
343 protected HashSet<uint> m_killRecord; 352// protected HashSet<uint> m_killRecord;
344 353
345// protected HashSet<uint> m_attachmentsSent; 354// protected HashSet<uint> m_attachmentsSent;
346 355
347 private int m_moneyBalance; 356 private int m_moneyBalance;
357 private bool m_deliverPackets = true;
348 private int m_animationSequenceNumber = 1; 358 private int m_animationSequenceNumber = 1;
349 private bool m_SendLogoutPacketWhenClosing = true; 359 private bool m_SendLogoutPacketWhenClosing = true;
350 360
@@ -391,6 +401,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
391 get { return m_startpos; } 401 get { return m_startpos; }
392 set { m_startpos = value; } 402 set { m_startpos = value; }
393 } 403 }
404 public bool DeliverPackets
405 {
406 get { return m_deliverPackets; }
407 set {
408 m_deliverPackets = value;
409 m_udpClient.m_deliverPackets = value;
410 }
411 }
394 public UUID AgentId { get { return m_agentId; } } 412 public UUID AgentId { get { return m_agentId; } }
395 public ISceneAgent SceneAgent { get; set; } 413 public ISceneAgent SceneAgent { get; set; }
396 public UUID ActiveGroupId { get { return m_activeGroupID; } } 414 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -442,6 +460,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
442 } 460 }
443 461
444 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } } 462 public bool SendLogoutPacketWhenClosing { set { m_SendLogoutPacketWhenClosing = value; } }
463
445 464
446 #endregion Properties 465 #endregion Properties
447 466
@@ -468,7 +487,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
468 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); 487 m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
469 m_entityProps = new PriorityQueue(m_scene.Entities.Count); 488 m_entityProps = new PriorityQueue(m_scene.Entities.Count);
470 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); 489 m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
471 m_killRecord = new HashSet<uint>(); 490// m_killRecord = new HashSet<uint>();
472// m_attachmentsSent = new HashSet<uint>(); 491// m_attachmentsSent = new HashSet<uint>();
473 492
474 m_assetService = m_scene.RequestModuleInterface<IAssetService>(); 493 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
@@ -498,12 +517,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
498 517
499 #region Client Methods 518 #region Client Methods
500 519
520
521 /// <summary>
522 /// Close down the client view
523 /// </summary>
501 public void Close() 524 public void Close()
502 { 525 {
503 Close(false); 526 Close(true, false);
504 } 527 }
505 528
506 public void Close(bool force) 529 public void Close(bool sendStop, bool force)
507 { 530 {
508 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 531 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
509 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 532 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
@@ -515,7 +538,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
515 return; 538 return;
516 539
517 IsActive = false; 540 IsActive = false;
518 CloseWithoutChecks(); 541 CloseWithoutChecks(sendStop);
519 } 542 }
520 } 543 }
521 544
@@ -528,12 +551,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
528 /// 551 ///
529 /// Callers must lock ClosingSyncLock before calling. 552 /// Callers must lock ClosingSyncLock before calling.
530 /// </remarks> 553 /// </remarks>
531 public void CloseWithoutChecks() 554 public void CloseWithoutChecks(bool sendStop)
532 { 555 {
533 m_log.DebugFormat( 556 m_log.DebugFormat(
534 "[CLIENT]: Close has been called for {0} attached to scene {1}", 557 "[CLIENT]: Close has been called for {0} attached to scene {1}",
535 Name, m_scene.RegionInfo.RegionName); 558 Name, m_scene.RegionInfo.RegionName);
536 559
560 if (sendStop)
561 {
562 // Send the STOP packet
563 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
564 OutPacket(disable, ThrottleOutPacketType.Unknown);
565 }
566
537 // Shutdown the image manager 567 // Shutdown the image manager
538 ImageManager.Close(); 568 ImageManager.Close();
539 569
@@ -556,6 +586,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
556 // Disable UDP handling for this client 586 // Disable UDP handling for this client
557 m_udpClient.Shutdown(); 587 m_udpClient.Shutdown();
558 588
589
559 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 590 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
560 //GC.Collect(); 591 //GC.Collect();
561 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); 592 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -790,9 +821,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
790 handshake.RegionInfo3.ColoName = Utils.EmptyBytes; 821 handshake.RegionInfo3.ColoName = Utils.EmptyBytes;
791 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); 822 handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType);
792 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; 823 handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes;
824
793 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; 825 handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0];
794 826// OutPacket(handshake, ThrottleOutPacketType.Task);
795 OutPacket(handshake, ThrottleOutPacketType.Task); 827 // use same as MoveAgentIntoRegion (both should be task )
828 OutPacket(handshake, ThrottleOutPacketType.Unknown);
796 } 829 }
797 830
798 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 831 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
@@ -832,7 +865,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
832 reply.ChatData.OwnerID = ownerID; 865 reply.ChatData.OwnerID = ownerID;
833 reply.ChatData.SourceID = fromAgentID; 866 reply.ChatData.SourceID = fromAgentID;
834 867
835 OutPacket(reply, ThrottleOutPacketType.Task); 868 OutPacket(reply, ThrottleOutPacketType.Unknown);
836 } 869 }
837 870
838 /// <summary> 871 /// <summary>
@@ -865,32 +898,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
865 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 898 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
866 msg.MessageBlock.BinaryBucket = im.binaryBucket; 899 msg.MessageBlock.BinaryBucket = im.binaryBucket;
867 900
868 if (im.message.StartsWith("[grouptest]")) 901 OutPacket(msg, ThrottleOutPacketType.Task);
869 { // this block is test code for implementing group IM - delete when group IM is finished
870 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
871 if (eq != null)
872 {
873 im.dialog = 17;
874
875 //eq.ChatterboxInvitation(
876 // new UUID("00000000-68f9-1111-024e-222222111123"),
877 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
878 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
879
880 eq.ChatterboxInvitation(
881 new UUID("00000000-68f9-1111-024e-222222111123"),
882 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
883 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
884
885 eq.ChatterBoxSessionAgentListUpdates(
886 new UUID("00000000-68f9-1111-024e-222222111123"),
887 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
888 }
889
890 Console.WriteLine("SendInstantMessage: " + msg);
891 }
892 else
893 OutPacket(msg, ThrottleOutPacketType.Task);
894 } 902 }
895 } 903 }
896 904
@@ -1118,6 +1126,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1118 public virtual void SendLayerData(float[] map) 1126 public virtual void SendLayerData(float[] map)
1119 { 1127 {
1120 Util.FireAndForget(DoSendLayerData, map); 1128 Util.FireAndForget(DoSendLayerData, map);
1129
1130 // Send it sync, and async. It's not that much data
1131 // and it improves user experience just so much!
1132 DoSendLayerData(map);
1121 } 1133 }
1122 1134
1123 /// <summary> 1135 /// <summary>
@@ -1130,16 +1142,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1130 1142
1131 try 1143 try
1132 { 1144 {
1133 //for (int y = 0; y < 16; y++) 1145 for (int y = 0; y < 16; y++)
1134 //{ 1146 {
1135 // for (int x = 0; x < 16; x++) 1147 for (int x = 0; x < 16; x+=4)
1136 // { 1148 {
1137 // SendLayerData(x, y, map); 1149 SendLayerPacket(x, y, map);
1138 // } 1150 }
1139 //} 1151 }
1140
1141 // Send LayerData in a spiral pattern. Fun!
1142 SendLayerTopRight(map, 0, 0, 15, 15);
1143 } 1152 }
1144 catch (Exception e) 1153 catch (Exception e)
1145 { 1154 {
@@ -1147,51 +1156,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1147 } 1156 }
1148 } 1157 }
1149 1158
1150 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1151 {
1152 // Row
1153 for (int i = x1; i <= x2; i++)
1154 SendLayerData(i, y1, map);
1155
1156 // Column
1157 for (int j = y1 + 1; j <= y2; j++)
1158 SendLayerData(x2, j, map);
1159
1160 if (x2 - x1 > 0)
1161 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1162 }
1163
1164 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1165 {
1166 // Row in reverse
1167 for (int i = x2; i >= x1; i--)
1168 SendLayerData(i, y2, map);
1169
1170 // Column in reverse
1171 for (int j = y2 - 1; j >= y1; j--)
1172 SendLayerData(x1, j, map);
1173
1174 if (x2 - x1 > 0)
1175 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1176 }
1177
1178 /// <summary> 1159 /// <summary>
1179 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1160 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1180 /// </summary> 1161 /// </summary>
1181 /// <param name="map">heightmap</param> 1162 /// <param name="map">heightmap</param>
1182 /// <param name="px">X coordinate for patches 0..12</param> 1163 /// <param name="px">X coordinate for patches 0..12</param>
1183 /// <param name="py">Y coordinate for patches 0..15</param> 1164 /// <param name="py">Y coordinate for patches 0..15</param>
1184 // private void SendLayerPacket(float[] map, int y, int x) 1165 private void SendLayerPacket(int x, int y, float[] map)
1185 // { 1166 {
1186 // int[] patches = new int[4]; 1167 int[] patches = new int[4];
1187 // patches[0] = x + 0 + y * 16; 1168 patches[0] = x + 0 + y * 16;
1188 // patches[1] = x + 1 + y * 16; 1169 patches[1] = x + 1 + y * 16;
1189 // patches[2] = x + 2 + y * 16; 1170 patches[2] = x + 2 + y * 16;
1190 // patches[3] = x + 3 + y * 16; 1171 patches[3] = x + 3 + y * 16;
1191 1172
1192 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1173 float[] heightmap = (map.Length == 65536) ?
1193 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1174 map :
1194 // } 1175 LLHeightFieldMoronize(map);
1176
1177 try
1178 {
1179 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1180 OutPacket(layerpack, ThrottleOutPacketType.Land);
1181 }
1182 catch
1183 {
1184 for (int px = x ; px < x + 4 ; px++)
1185 SendLayerData(px, y, map);
1186 }
1187 }
1195 1188
1196 /// <summary> 1189 /// <summary>
1197 /// Sends a specified patch to a client 1190 /// Sends a specified patch to a client
@@ -1211,7 +1204,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1204 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1212 layerpack.Header.Reliable = true; 1205 layerpack.Header.Reliable = true;
1213 1206
1214 OutPacket(layerpack, ThrottleOutPacketType.Land); 1207 OutPacket(layerpack, ThrottleOutPacketType.Task);
1215 } 1208 }
1216 catch (Exception e) 1209 catch (Exception e)
1217 { 1210 {
@@ -1574,7 +1567,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1574 1567
1575 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1568 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1576 { 1569 {
1577// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1570// foreach (uint id in localIDs)
1571// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1578 1572
1579 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1573 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1580 // TODO: don't create new blocks if recycling an old packet 1574 // TODO: don't create new blocks if recycling an old packet
@@ -1596,17 +1590,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1596 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1590 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1597 // condition where a kill can be processed before an out-of-date update for the same object. 1591 // condition where a kill can be processed before an out-of-date update for the same object.
1598 // ProcessEntityUpdates() also takes the m_killRecord lock. 1592 // ProcessEntityUpdates() also takes the m_killRecord lock.
1599 lock (m_killRecord) 1593// lock (m_killRecord)
1600 { 1594// {
1601 foreach (uint localID in localIDs) 1595// foreach (uint localID in localIDs)
1602 m_killRecord.Add(localID); 1596// m_killRecord.Add(localID);
1603 1597
1604 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1598 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1605 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1599 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1606 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1600 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1607 // scene objects in a viewer until that viewer is relogged in. 1601 // scene objects in a viewer until that viewer is relogged in.
1608 OutPacket(kill, ThrottleOutPacketType.Task); 1602 OutPacket(kill, ThrottleOutPacketType.Task);
1609 } 1603// }
1610 } 1604 }
1611 } 1605 }
1612 1606
@@ -2064,9 +2058,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2064 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2058 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2065 } 2059 }
2066 2060
2067 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2068 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2061 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2069 { 2062 {
2063 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2064 }
2065
2066 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2067 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2068 {
2070 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 2069 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
2071 2070
2072 UpdateCreateInventoryItemPacket InventoryReply 2071 UpdateCreateInventoryItemPacket InventoryReply
@@ -2076,6 +2075,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2076 // TODO: don't create new blocks if recycling an old packet 2075 // TODO: don't create new blocks if recycling an old packet
2077 InventoryReply.AgentData.AgentID = AgentId; 2076 InventoryReply.AgentData.AgentID = AgentId;
2078 InventoryReply.AgentData.SimApproved = true; 2077 InventoryReply.AgentData.SimApproved = true;
2078 InventoryReply.AgentData.TransactionID = transactionID;
2079 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2079 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2080 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2080 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2081 InventoryReply.InventoryData[0].ItemID = Item.ID; 2081 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2145,16 +2145,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2145 replytask.InventoryData.TaskID = taskID; 2145 replytask.InventoryData.TaskID = taskID;
2146 replytask.InventoryData.Serial = serial; 2146 replytask.InventoryData.Serial = serial;
2147 replytask.InventoryData.Filename = fileName; 2147 replytask.InventoryData.Filename = fileName;
2148 OutPacket(replytask, ThrottleOutPacketType.Asset); 2148 OutPacket(replytask, ThrottleOutPacketType.Task);
2149 } 2149 }
2150 2150
2151 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2151 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2152 { 2152 {
2153 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2154 if (isTaskInventory)
2155 type = ThrottleOutPacketType.Task;
2156
2153 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2157 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2154 sendXfer.XferID.ID = xferID; 2158 sendXfer.XferID.ID = xferID;
2155 sendXfer.XferID.Packet = packet; 2159 sendXfer.XferID.Packet = packet;
2156 sendXfer.DataPacket.Data = data; 2160 sendXfer.DataPacket.Data = data;
2157 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2161 OutPacket(sendXfer, type);
2158 } 2162 }
2159 2163
2160 public void SendAbortXferPacket(ulong xferID) 2164 public void SendAbortXferPacket(ulong xferID)
@@ -2336,6 +2340,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2336 OutPacket(sound, ThrottleOutPacketType.Task); 2340 OutPacket(sound, ThrottleOutPacketType.Task);
2337 } 2341 }
2338 2342
2343 public void SendTransferAbort(TransferRequestPacket transferRequest)
2344 {
2345 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2346 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2347 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2348 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2349 OutPacket(abort, ThrottleOutPacketType.Task);
2350 }
2351
2339 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2352 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2340 { 2353 {
2341 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2354 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2644,6 +2657,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2644 float friction = part.Friction; 2657 float friction = part.Friction;
2645 float bounce = part.Restitution; 2658 float bounce = part.Restitution;
2646 float gravmod = part.GravityModifier; 2659 float gravmod = part.GravityModifier;
2660
2647 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId); 2661 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2648 } 2662 }
2649 } 2663 }
@@ -2714,8 +2728,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2714 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2728 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2715 return; 2729 return;
2716 } 2730 }
2731 int WearableOut = 0;
2732 bool isWearable = false;
2717 2733
2718 //m_log.Debug("sending asset " + req.RequestAssetID); 2734 if (req.AssetInf != null)
2735 isWearable =
2736 ((AssetType) req.AssetInf.Type ==
2737 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2738
2739
2740 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2741
2742
2743 //if (isWearable)
2744 // m_log.Debug((AssetType)req.AssetInf.Type);
2745
2719 TransferInfoPacket Transfer = new TransferInfoPacket(); 2746 TransferInfoPacket Transfer = new TransferInfoPacket();
2720 Transfer.TransferInfo.ChannelType = 2; 2747 Transfer.TransferInfo.ChannelType = 2;
2721 Transfer.TransferInfo.Status = 0; 2748 Transfer.TransferInfo.Status = 0;
@@ -2737,7 +2764,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2737 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2764 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2738 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2765 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2739 Transfer.Header.Zerocoded = true; 2766 Transfer.Header.Zerocoded = true;
2740 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2767 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2741 2768
2742 if (req.NumPackets == 1) 2769 if (req.NumPackets == 1)
2743 { 2770 {
@@ -2748,12 +2775,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2748 TransferPacket.TransferData.Data = req.AssetInf.Data; 2775 TransferPacket.TransferData.Data = req.AssetInf.Data;
2749 TransferPacket.TransferData.Status = 1; 2776 TransferPacket.TransferData.Status = 1;
2750 TransferPacket.Header.Zerocoded = true; 2777 TransferPacket.Header.Zerocoded = true;
2751 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2778 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2752 } 2779 }
2753 else 2780 else
2754 { 2781 {
2755 int processedLength = 0; 2782 int processedLength = 0;
2756 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2783// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2784
2785 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2757 int packetNumber = 0; 2786 int packetNumber = 0;
2758 2787
2759 while (processedLength < req.AssetInf.Data.Length) 2788 while (processedLength < req.AssetInf.Data.Length)
@@ -2779,7 +2808,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2779 TransferPacket.TransferData.Status = 1; 2808 TransferPacket.TransferData.Status = 1;
2780 } 2809 }
2781 TransferPacket.Header.Zerocoded = true; 2810 TransferPacket.Header.Zerocoded = true;
2782 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2811 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2783 2812
2784 processedLength += chunkSize; 2813 processedLength += chunkSize;
2785 packetNumber++; 2814 packetNumber++;
@@ -2824,7 +2853,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2824 reply.Data.ParcelID = parcelID; 2853 reply.Data.ParcelID = parcelID;
2825 reply.Data.OwnerID = land.OwnerID; 2854 reply.Data.OwnerID = land.OwnerID;
2826 reply.Data.Name = Utils.StringToBytes(land.Name); 2855 reply.Data.Name = Utils.StringToBytes(land.Name);
2827 reply.Data.Desc = Utils.StringToBytes(land.Description); 2856 if (land != null && land.Description != null && land.Description != String.Empty)
2857 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2858 else
2859 reply.Data.Desc = new Byte[0];
2828 reply.Data.ActualArea = land.Area; 2860 reply.Data.ActualArea = land.Area;
2829 reply.Data.BillableArea = land.Area; // TODO: what is this? 2861 reply.Data.BillableArea = land.Area; // TODO: what is this?
2830 2862
@@ -3531,24 +3563,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3531 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3563 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3532 AgentWearablesUpdatePacket.WearableDataBlock awb; 3564 AgentWearablesUpdatePacket.WearableDataBlock awb;
3533 int idx = 0; 3565 int idx = 0;
3534 for (int i = 0; i < wearables.Length; i++) 3566
3535 { 3567 for (int i = 0; i < wearables.Length; i++)
3536 for (int j = 0; j < wearables[i].Count; j++) 3568 {
3537 { 3569 for (int j = 0; j < wearables[i].Count; j++)
3538 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3570 {
3539 awb.WearableType = (byte)i; 3571 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3540 awb.AssetID = wearables[i][j].AssetID; 3572 awb.WearableType = (byte) i;
3541 awb.ItemID = wearables[i][j].ItemID; 3573 awb.AssetID = wearables[i][j].AssetID;
3542 aw.WearableData[idx] = awb; 3574 awb.ItemID = wearables[i][j].ItemID;
3543 idx++; 3575 aw.WearableData[idx] = awb;
3544 3576 idx++;
3545// m_log.DebugFormat( 3577
3546// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3578 // m_log.DebugFormat(
3547// awb.ItemID, awb.AssetID, i, Name); 3579 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3548 } 3580 // awb.ItemID, awb.AssetID, i, Name);
3549 } 3581 }
3582 }
3550 3583
3551 OutPacket(aw, ThrottleOutPacketType.Task); 3584 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3552 } 3585 }
3553 3586
3554 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3587 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3559,7 +3592,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3559 3592
3560 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3593 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3561 // TODO: don't create new blocks if recycling an old packet 3594 // TODO: don't create new blocks if recycling an old packet
3562 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3595 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3563 avp.ObjectData.TextureEntry = textureEntry; 3596 avp.ObjectData.TextureEntry = textureEntry;
3564 3597
3565 AvatarAppearancePacket.VisualParamBlock avblock = null; 3598 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3690,7 +3723,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3690 /// </summary> 3723 /// </summary>
3691 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3724 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3692 { 3725 {
3693 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3726 if (entity is SceneObjectPart)
3727 {
3728 SceneObjectPart e = (SceneObjectPart)entity;
3729 SceneObjectGroup g = e.ParentGroup;
3730 if (g.RootPart.Shape.State > 30) // HUD
3731 if (g.OwnerID != AgentId)
3732 return; // Don't send updates for other people's HUDs
3733 }
3734
3694 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3735 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3695 3736
3696 lock (m_entityUpdates.SyncRoot) 3737 lock (m_entityUpdates.SyncRoot)
@@ -3757,27 +3798,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3757 3798
3758 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3799 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3759 // condition where a kill can be processed before an out-of-date update for the same object. 3800 // condition where a kill can be processed before an out-of-date update for the same object.
3760 lock (m_killRecord) 3801 float avgTimeDilation = 1.0f;
3802 IEntityUpdate iupdate;
3803 Int32 timeinqueue; // this is just debugging code & can be dropped later
3804
3805 while (updatesThisCall < maxUpdates)
3761 { 3806 {
3762 float avgTimeDilation = 1.0f; 3807 lock (m_entityUpdates.SyncRoot)
3763 IEntityUpdate iupdate; 3808 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3764 Int32 timeinqueue; // this is just debugging code & can be dropped later 3809 break;
3810
3811 EntityUpdate update = (EntityUpdate)iupdate;
3812
3813 avgTimeDilation += update.TimeDilation;
3814 avgTimeDilation *= 0.5f;
3765 3815
3766 while (updatesThisCall < maxUpdates) 3816 if (update.Entity is SceneObjectPart)
3767 { 3817 {
3768 lock (m_entityUpdates.SyncRoot) 3818 SceneObjectPart part = (SceneObjectPart)update.Entity;
3769 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3770 break;
3771 3819
3772 EntityUpdate update = (EntityUpdate)iupdate; 3820 if (part.ParentGroup.IsDeleted)
3773 3821 continue;
3774 avgTimeDilation += update.TimeDilation;
3775 avgTimeDilation *= 0.5f;
3776 3822
3777 if (update.Entity is SceneObjectPart) 3823 if (part.ParentGroup.IsAttachment)
3824 { // Someone else's HUD, why are we getting these?
3825 if (part.ParentGroup.OwnerID != AgentId &&
3826 part.ParentGroup.RootPart.Shape.State > 30)
3827 continue;
3828 ScenePresence sp;
3829 // Owner is not in the sim, don't update it to
3830 // anyone
3831 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3832 continue;
3833
3834 List<SceneObjectGroup> atts = sp.GetAttachments();
3835 bool found = false;
3836 foreach (SceneObjectGroup att in atts)
3837 {
3838 if (att == part.ParentGroup)
3839 {
3840 found = true;
3841 break;
3842 }
3843 }
3844
3845 // It's an attachment of a valid avatar, but
3846 // doesn't seem to be attached, skip
3847 if (!found)
3848 continue;
3849
3850 // On vehicle crossing, the attachments are received
3851 // while the avatar is still a child. Don't send
3852 // updates here because the LocalId has not yet
3853 // been updated and the viewer will derender the
3854 // attachments until the avatar becomes root.
3855 if (sp.IsChildAgent)
3856 continue;
3857
3858 // If the object is an attachment we don't want it to be in the kill
3859 // record. Else attaching from inworld and subsequently dropping
3860 // it will no longer work.
3861// lock (m_killRecord)
3862// {
3863// m_killRecord.Remove(part.LocalId);
3864// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3865// }
3866 }
3867 else
3778 { 3868 {
3779 SceneObjectPart part = (SceneObjectPart)update.Entity;
3780
3781 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3869 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3782 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3870 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3783 // safety measure. 3871 // safety measure.
@@ -3788,21 +3876,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3788 // 3876 //
3789 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3877 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3790 // after the root prim has been deleted. 3878 // after the root prim has been deleted.
3791 if (m_killRecord.Contains(part.LocalId)) 3879 //
3792 { 3880 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3793 // m_log.WarnFormat( 3881// lock (m_killRecord)
3794 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3882// {
3795 // part.LocalId, Name); 3883// if (m_killRecord.Contains(part.LocalId))
3796 continue; 3884// continue;
3797 } 3885// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3798 3886// continue;
3799 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3887// }
3888 }
3889
3890 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3891 {
3892 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3893 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3800 { 3894 {
3801 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3895 part.Shape.LightEntry = false;
3802 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3803 {
3804 part.Shape.LightEntry = false;
3805 }
3806 } 3896 }
3807 3897
3808 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh)) 3898 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
@@ -3813,224 +3903,166 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3813 part.Shape.ProfileHollow = 27500; 3903 part.Shape.ProfileHollow = 27500;
3814 } 3904 }
3815 } 3905 }
3816 3906
3817 #region UpdateFlags to packet type conversion 3907 if (part.Shape != null && (part.Shape.SculptType == (byte)SculptType.Mesh))
3818
3819 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3820
3821 bool canUseCompressed = true;
3822 bool canUseImproved = true;
3823
3824 // Compressed object updates only make sense for LL primitives
3825 if (!(update.Entity is SceneObjectPart))
3826 { 3908 {
3827 canUseCompressed = false; 3909 // Ensure that mesh has at least 8 valid faces
3910 part.Shape.ProfileBegin = 12500;
3911 part.Shape.ProfileEnd = 0;
3912 part.Shape.ProfileHollow = 27500;
3828 } 3913 }
3829 3914 }
3830 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3915
3916 ++updatesThisCall;
3917
3918 #region UpdateFlags to packet type conversion
3919
3920 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3921
3922 bool canUseCompressed = true;
3923 bool canUseImproved = true;
3924
3925 // Compressed object updates only make sense for LL primitives
3926 if (!(update.Entity is SceneObjectPart))
3927 {
3928 canUseCompressed = false;
3929 }
3930
3931 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3932 {
3933 canUseCompressed = false;
3934 canUseImproved = false;
3935 }
3936 else
3937 {
3938 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3939 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3940 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3941 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3831 { 3942 {
3832 canUseCompressed = false; 3943 canUseCompressed = false;
3833 canUseImproved = false;
3834 } 3944 }
3835 else 3945
3946 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3947 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3948 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3949 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3950 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3951 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3952 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3953 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3954 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3955 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3956 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3957 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3958 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3959 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3836 { 3960 {
3837 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3961 canUseImproved = false;
3838 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3839 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3840 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3841 {
3842 canUseCompressed = false;
3843 }
3844
3845 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3846 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3847 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3848 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3849 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3850 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3851 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3852 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3853 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3854 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3855 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3856 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3857 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3858 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3859 {
3860 canUseImproved = false;
3861 }
3862 } 3962 }
3963 }
3863 3964
3864 #endregion UpdateFlags to packet type conversion 3965 #endregion UpdateFlags to packet type conversion
3865
3866 #region Block Construction
3867
3868 // TODO: Remove this once we can build compressed updates
3869 canUseCompressed = false;
3870
3871 if (!canUseImproved && !canUseCompressed)
3872 {
3873 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3874 3966
3875 if (update.Entity is ScenePresence) 3967 #region Block Construction
3876 {
3877 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3878 }
3879 else
3880 {
3881 SceneObjectPart part = (SceneObjectPart)update.Entity;
3882 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3883
3884 // If the part has become a private hud since the update was scheduled then we do not
3885 // want to send it to other avatars.
3886 if (part.ParentGroup.IsAttachment
3887 && part.ParentGroup.HasPrivateAttachmentPoint
3888 && part.ParentGroup.AttachedAvatar != AgentId)
3889 continue;
3890
3891 // If the part has since been deleted, then drop the update. In the case of attachments,
3892 // this is to avoid spurious updates to other viewers since post-processing of attachments
3893 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3894 // of the test above).
3895 //
3896 // Actual deletions (kills) happen in another method.
3897 if (part.ParentGroup.IsDeleted)
3898 continue;
3899 }
3900 3968
3901 objectUpdateBlocks.Value.Add(updateBlock); 3969 // TODO: Remove this once we can build compressed updates
3902 objectUpdates.Value.Add(update); 3970 canUseCompressed = false;
3903 }
3904 else if (!canUseImproved)
3905 {
3906 SceneObjectPart part = (SceneObjectPart)update.Entity;
3907 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
3908 = CreateCompressedUpdateBlock(part, updateFlags);
3909
3910 // If the part has since been deleted, then drop the update. In the case of attachments,
3911 // this is to avoid spurious updates to other viewers since post-processing of attachments
3912 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3913 // of the test above).
3914 //
3915 // Actual deletions (kills) happen in another method.
3916 if (part.ParentGroup.IsDeleted)
3917 continue;
3918 3971
3919 compressedUpdateBlocks.Value.Add(compressedBlock); 3972 if (!canUseImproved && !canUseCompressed)
3920 compressedUpdates.Value.Add(update); 3973 {
3974 if (update.Entity is ScenePresence)
3975 {
3976 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3921 } 3977 }
3922 else 3978 else
3923 { 3979 {
3924 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3980 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3925 {
3926 // Self updates go into a special list
3927 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3928 terseAgentUpdates.Value.Add(update);
3929 }
3930 else
3931 {
3932 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
3933 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
3934
3935 // Everything else goes here
3936 if (update.Entity is SceneObjectPart)
3937 {
3938 SceneObjectPart part = (SceneObjectPart)update.Entity;
3939
3940 // If the part has become a private hud since the update was scheduled then we do not
3941 // want to send it to other avatars.
3942 if (part.ParentGroup.IsAttachment
3943 && part.ParentGroup.HasPrivateAttachmentPoint
3944 && part.ParentGroup.AttachedAvatar != AgentId)
3945 continue;
3946
3947 // If the part has since been deleted, then drop the update. In the case of attachments,
3948 // this is to avoid spurious updates to other viewers since post-processing of attachments
3949 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3950 // of the test above).
3951 //
3952 // Actual deletions (kills) happen in another method.
3953 if (part.ParentGroup.IsDeleted)
3954 continue;
3955 }
3956
3957 terseUpdateBlocks.Value.Add(terseUpdateBlock);
3958 terseUpdates.Value.Add(update);
3959 }
3960 } 3981 }
3961
3962 ++updatesThisCall;
3963
3964 #endregion Block Construction
3965 } 3982 }
3966 3983 else if (!canUseImproved)
3967 #region Packet Sending 3984 {
3968 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3985 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3969 3986 }
3970 if (terseAgentUpdateBlocks.IsValueCreated) 3987 else
3971 { 3988 {
3972 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3989 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3990 // Self updates go into a special list
3991 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3992 else
3993 // Everything else goes here
3994 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3995 }
3973 3996
3974 ImprovedTerseObjectUpdatePacket packet 3997 #endregion Block Construction
3975 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 3998 }
3976 3999
3977 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4000 #region Packet Sending
3978 packet.RegionData.TimeDilation = timeDilation; 4001
3979 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4002 const float TIME_DILATION = 1.0f;
4003 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
4004
4005 if (terseAgentUpdateBlocks.IsValueCreated)
4006 {
4007 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3980 4008
3981 for (int i = 0; i < blocks.Count; i++) 4009 ImprovedTerseObjectUpdatePacket packet
3982 packet.ObjectData[i] = blocks[i]; 4010 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3983 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4011 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3984 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 4012 packet.RegionData.TimeDilation = timeDilation;
3985 } 4013 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3986 4014
3987 if (objectUpdateBlocks.IsValueCreated) 4015 for (int i = 0; i < blocks.Count; i++)
3988 { 4016 packet.ObjectData[i] = blocks[i];
3989 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3990
3991 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3992 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3993 packet.RegionData.TimeDilation = timeDilation;
3994 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3995
3996 for (int i = 0; i < blocks.Count; i++)
3997 packet.ObjectData[i] = blocks[i];
3998 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3999 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
4000 }
4001
4002 if (compressedUpdateBlocks.IsValueCreated)
4003 {
4004 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4005
4006 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4007 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4008 packet.RegionData.TimeDilation = timeDilation;
4009 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4010
4011 for (int i = 0; i < blocks.Count; i++)
4012 packet.ObjectData[i] = blocks[i];
4013 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
4014 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
4015 }
4016 4017
4017 if (terseUpdateBlocks.IsValueCreated) 4018 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
4018 { 4019 }
4019 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4020
4021 ImprovedTerseObjectUpdatePacket packet
4022 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4023 PacketType.ImprovedTerseObjectUpdate);
4024 4020
4025 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4021 if (objectUpdateBlocks.IsValueCreated)
4026 packet.RegionData.TimeDilation = timeDilation; 4022 {
4027 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4023 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
4028 4024
4029 for (int i = 0; i < blocks.Count; i++) 4025 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
4030 packet.ObjectData[i] = blocks[i]; 4026 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4031 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4027 packet.RegionData.TimeDilation = timeDilation;
4032 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4028 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4033 } 4029
4030 for (int i = 0; i < blocks.Count; i++)
4031 packet.ObjectData[i] = blocks[i];
4032
4033 OutPacket(packet, ThrottleOutPacketType.Task, true);
4034 }
4035
4036 if (compressedUpdateBlocks.IsValueCreated)
4037 {
4038 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4039
4040 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4041 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4042 packet.RegionData.TimeDilation = timeDilation;
4043 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4044
4045 for (int i = 0; i < blocks.Count; i++)
4046 packet.ObjectData[i] = blocks[i];
4047
4048 OutPacket(packet, ThrottleOutPacketType.Task, true);
4049 }
4050
4051 if (terseUpdateBlocks.IsValueCreated)
4052 {
4053 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4054
4055 ImprovedTerseObjectUpdatePacket packet
4056 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4057 PacketType.ImprovedTerseObjectUpdate);
4058 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4059 packet.RegionData.TimeDilation = timeDilation;
4060 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4061
4062 for (int i = 0; i < blocks.Count; i++)
4063 packet.ObjectData[i] = blocks[i];
4064
4065 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4034 } 4066 }
4035 4067
4036 #endregion Packet Sending 4068 #endregion Packet Sending
@@ -4323,11 +4355,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4323 4355
4324 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4356 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4325 // of the object rather than the properties when the packet was created 4357 // of the object rather than the properties when the packet was created
4326 OutPacket(packet, ThrottleOutPacketType.Task, true, 4358 // HACK : Remove intelligent resending until it's fixed in core
4327 delegate(OutgoingPacket oPacket) 4359 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4328 { 4360 // delegate(OutgoingPacket oPacket)
4329 ResendPropertyUpdates(updates, oPacket); 4361 // {
4330 }); 4362 // ResendPropertyUpdates(updates, oPacket);
4363 // });
4364 OutPacket(packet, ThrottleOutPacketType.Task, true);
4331 4365
4332 // pbcnt += blocks.Count; 4366 // pbcnt += blocks.Count;
4333 // ppcnt++; 4367 // ppcnt++;
@@ -4353,11 +4387,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4353 // of the object rather than the properties when the packet was created 4387 // of the object rather than the properties when the packet was created
4354 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4388 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4355 updates.Add(familyUpdates.Value[i]); 4389 updates.Add(familyUpdates.Value[i]);
4356 OutPacket(packet, ThrottleOutPacketType.Task, true, 4390 // HACK : Remove intelligent resending until it's fixed in core
4357 delegate(OutgoingPacket oPacket) 4391 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4358 { 4392 // delegate(OutgoingPacket oPacket)
4359 ResendPropertyUpdates(updates, oPacket); 4393 // {
4360 }); 4394 // ResendPropertyUpdates(updates, oPacket);
4395 // });
4396 OutPacket(packet, ThrottleOutPacketType.Task, true);
4361 4397
4362 // fpcnt++; 4398 // fpcnt++;
4363 // fbcnt++; 4399 // fbcnt++;
@@ -4729,7 +4765,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4729 4765
4730 if (landData.SimwideArea > 0) 4766 if (landData.SimwideArea > 0)
4731 { 4767 {
4732 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4768 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4769 // Never report more than sim total capacity
4770 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4771 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4733 updateMessage.SimWideMaxPrims = simulatorCapacity; 4772 updateMessage.SimWideMaxPrims = simulatorCapacity;
4734 } 4773 }
4735 else 4774 else
@@ -4858,14 +4897,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4858 4897
4859 if (notifyCount > 0) 4898 if (notifyCount > 0)
4860 { 4899 {
4861 if (notifyCount > 32) 4900// if (notifyCount > 32)
4862 { 4901// {
4863 m_log.InfoFormat( 4902// m_log.InfoFormat(
4864 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4903// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4865 + " - a developer might want to investigate whether this is a hard limit", 32); 4904// + " - a developer might want to investigate whether this is a hard limit", 32);
4866 4905//
4867 notifyCount = 32; 4906// notifyCount = 32;
4868 } 4907// }
4869 4908
4870 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4909 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4871 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4910 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4920,9 +4959,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4920 { 4959 {
4921 ScenePresence presence = (ScenePresence)entity; 4960 ScenePresence presence = (ScenePresence)entity;
4922 4961
4962 position = presence.OffsetPosition;
4963 rotation = presence.Rotation;
4964
4965 if (presence.ParentID != 0)
4966 {
4967 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
4968 if (part != null && part != part.ParentGroup.RootPart)
4969 {
4970 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
4971 rotation = part.RotationOffset * presence.Rotation;
4972 }
4973 angularVelocity = Vector3.Zero;
4974 }
4975 else
4976 {
4977 angularVelocity = presence.AngularVelocity;
4978 rotation = presence.Rotation;
4979 }
4980
4923 attachPoint = 0; 4981 attachPoint = 0;
4924 collisionPlane = presence.CollisionPlane; 4982 collisionPlane = presence.CollisionPlane;
4925 position = presence.OffsetPosition;
4926 velocity = presence.Velocity; 4983 velocity = presence.Velocity;
4927 acceleration = Vector3.Zero; 4984 acceleration = Vector3.Zero;
4928 4985
@@ -4931,9 +4988,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4931 // may improve movement smoothness. 4988 // may improve movement smoothness.
4932// acceleration = new Vector3(1, 0, 0); 4989// acceleration = new Vector3(1, 0, 0);
4933 4990
4934 angularVelocity = presence.AngularVelocity;
4935 rotation = presence.Rotation;
4936
4937 if (sendTexture) 4991 if (sendTexture)
4938 textureEntry = presence.Appearance.Texture.GetBytes(); 4992 textureEntry = presence.Appearance.Texture.GetBytes();
4939 else 4993 else
@@ -5039,13 +5093,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5039 5093
5040 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5094 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5041 { 5095 {
5096 Vector3 offsetPosition = data.OffsetPosition;
5097 Quaternion rotation = data.Rotation;
5098 uint parentID = data.ParentID;
5099
5100 if (parentID != 0)
5101 {
5102 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5103 if (part != null && part != part.ParentGroup.RootPart)
5104 {
5105 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5106 rotation = part.RotationOffset * data.Rotation;
5107 parentID = part.ParentGroup.RootPart.LocalId;
5108 }
5109 }
5110
5042 byte[] objectData = new byte[76]; 5111 byte[] objectData = new byte[76];
5043 5112
5044 data.CollisionPlane.ToBytes(objectData, 0); 5113 data.CollisionPlane.ToBytes(objectData, 0);
5045 data.OffsetPosition.ToBytes(objectData, 16); 5114 offsetPosition.ToBytes(objectData, 16);
5046// data.Velocity.ToBytes(objectData, 28); 5115// data.Velocity.ToBytes(objectData, 28);
5047// data.Acceleration.ToBytes(objectData, 40); 5116// data.Acceleration.ToBytes(objectData, 40);
5048 data.Rotation.ToBytes(objectData, 52); 5117 rotation.ToBytes(objectData, 52);
5049 //data.AngularVelocity.ToBytes(objectData, 64); 5118 //data.AngularVelocity.ToBytes(objectData, 64);
5050 5119
5051 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5120 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5059,14 +5128,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5059 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5128 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5060 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5129 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5061 update.ObjectData = objectData; 5130 update.ObjectData = objectData;
5062 update.ParentID = data.ParentID; 5131 update.ParentID = parentID;
5063 update.PathCurve = 16; 5132 update.PathCurve = 16;
5064 update.PathScaleX = 100; 5133 update.PathScaleX = 100;
5065 update.PathScaleY = 100; 5134 update.PathScaleY = 100;
5066 update.PCode = (byte)PCode.Avatar; 5135 update.PCode = (byte)PCode.Avatar;
5067 update.ProfileCurve = 1; 5136 update.ProfileCurve = 1;
5068 update.PSBlock = Utils.EmptyBytes; 5137 update.PSBlock = Utils.EmptyBytes;
5069 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5138 update.Scale = data.Appearance.AvatarSize;
5139// update.Scale.Z -= 0.2f;
5140
5070 update.Text = Utils.EmptyBytes; 5141 update.Text = Utils.EmptyBytes;
5071 update.TextColor = new byte[4]; 5142 update.TextColor = new byte[4];
5072 5143
@@ -5077,10 +5148,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5077 update.TextureEntry = Utils.EmptyBytes; 5148 update.TextureEntry = Utils.EmptyBytes;
5078// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5149// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5079 5150
5151/* 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)
5080 update.UpdateFlags = (uint)( 5152 update.UpdateFlags = (uint)(
5081 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5153 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5082 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5154 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5083 PrimFlags.ObjectOwnerModify); 5155 PrimFlags.ObjectOwnerModify);
5156*/
5157 update.UpdateFlags = 0;
5084 5158
5085 return update; 5159 return update;
5086 } 5160 }
@@ -5251,8 +5325,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5251 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5325 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5252 // for each AgentUpdate packet. 5326 // for each AgentUpdate packet.
5253 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5327 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5254 5328
5255 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5329 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5330 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5331 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5256 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5332 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5257 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5333 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5258 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5334 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5404,6 +5480,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5404 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5480 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5405 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5481 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5406 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5482 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5483 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5407 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5484 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5408 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5485 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5409 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5486 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5470,6 +5547,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5470 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5547 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5471 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5548 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5472 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5549 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5550 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5473 5551
5474 AddGenericPacketHandler("autopilot", HandleAutopilot); 5552 AddGenericPacketHandler("autopilot", HandleAutopilot);
5475 } 5553 }
@@ -5508,6 +5586,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5508 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || 5586 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5509 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || 5587 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5510 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || 5588 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5589 (x.ControlFlags != 0) ||
5511 (x.Far != m_lastAgentUpdateArgs.Far) || 5590 (x.Far != m_lastAgentUpdateArgs.Far) ||
5512 (x.Flags != m_lastAgentUpdateArgs.Flags) || 5591 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5513 (x.State != m_lastAgentUpdateArgs.State) || 5592 (x.State != m_lastAgentUpdateArgs.State) ||
@@ -5767,6 +5846,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5767 return true; 5846 return true;
5768 } 5847 }
5769 5848
5849 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
5850 {
5851 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
5852 if (p.AgentData.SessionID != SessionId ||
5853 p.AgentData.AgentID != AgentId)
5854 return true;
5855
5856 m_VelocityInterpolate = false;
5857 return true;
5858 }
5859
5860 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
5861 {
5862 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
5863 if (p.AgentData.SessionID != SessionId ||
5864 p.AgentData.AgentID != AgentId)
5865 return true;
5866
5867 m_VelocityInterpolate = true;
5868 return true;
5869 }
5870
5871
5770 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 5872 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5771 { 5873 {
5772 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 5874 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6187,17 +6289,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6187 // Temporarily protect ourselves from the mantis #951 failure. 6289 // Temporarily protect ourselves from the mantis #951 failure.
6188 // However, we could do this for several other handlers where a failure isn't terminal 6290 // However, we could do this for several other handlers where a failure isn't terminal
6189 // for the client session anyway, in order to protect ourselves against bad code in plugins 6291 // for the client session anyway, in order to protect ourselves against bad code in plugins
6292 Vector3 avSize = appear.AgentData.Size;
6190 try 6293 try
6191 { 6294 {
6192 byte[] visualparams = new byte[appear.VisualParam.Length]; 6295 byte[] visualparams = new byte[appear.VisualParam.Length];
6193 for (int i = 0; i < appear.VisualParam.Length; i++) 6296 for (int i = 0; i < appear.VisualParam.Length; i++)
6194 visualparams[i] = appear.VisualParam[i].ParamValue; 6297 visualparams[i] = appear.VisualParam[i].ParamValue;
6195 6298 //var b = appear.WearableData[0];
6299
6196 Primitive.TextureEntry te = null; 6300 Primitive.TextureEntry te = null;
6197 if (appear.ObjectData.TextureEntry.Length > 1) 6301 if (appear.ObjectData.TextureEntry.Length > 1)
6198 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6302 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6303
6304 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6305 for (int i=0; i<appear.WearableData.Length;i++)
6306 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6199 6307
6200 handlerSetAppearance(sender, te, visualparams); 6308
6309
6310 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6201 } 6311 }
6202 catch (Exception e) 6312 catch (Exception e)
6203 { 6313 {
@@ -6406,6 +6516,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6406 { 6516 {
6407 handlerCompleteMovementToRegion(sender, true); 6517 handlerCompleteMovementToRegion(sender, true);
6408 } 6518 }
6519 else
6520 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6521
6409 handlerCompleteMovementToRegion = null; 6522 handlerCompleteMovementToRegion = null;
6410 6523
6411 return true; 6524 return true;
@@ -6423,7 +6536,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6423 return true; 6536 return true;
6424 } 6537 }
6425 #endregion 6538 #endregion
6426 6539/*
6427 StartAnim handlerStartAnim = null; 6540 StartAnim handlerStartAnim = null;
6428 StopAnim handlerStopAnim = null; 6541 StopAnim handlerStopAnim = null;
6429 6542
@@ -6447,6 +6560,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6447 } 6560 }
6448 } 6561 }
6449 return true; 6562 return true;
6563*/
6564 ChangeAnim handlerChangeAnim = null;
6565
6566 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6567 {
6568 handlerChangeAnim = OnChangeAnim;
6569 if (handlerChangeAnim != null)
6570 {
6571 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6572 }
6573 }
6574
6575 handlerChangeAnim = OnChangeAnim;
6576 if (handlerChangeAnim != null)
6577 {
6578 handlerChangeAnim(UUID.Zero, false, true);
6579 }
6580
6581 return true;
6450 } 6582 }
6451 6583
6452 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6584 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6672,6 +6804,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6672 #endregion 6804 #endregion
6673 6805
6674 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6806 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6807 GenericCall2 handler = OnUpdateThrottles;
6808 if (handler != null)
6809 {
6810 handler();
6811 }
6675 return true; 6812 return true;
6676 } 6813 }
6677 6814
@@ -7096,7 +7233,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7096 physdata.Bounce = phsblock.Restitution; 7233 physdata.Bounce = phsblock.Restitution;
7097 physdata.Density = phsblock.Density; 7234 physdata.Density = phsblock.Density;
7098 physdata.Friction = phsblock.Friction; 7235 physdata.Friction = phsblock.Friction;
7099 physdata.GravitationModifier = phsblock.GravityMultiplier; 7236 physdata.GravitationModifier = phsblock.GravityMultiplier;
7100 } 7237 }
7101 7238
7102 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this); 7239 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
@@ -7682,6 +7819,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7682 // surrounding scene 7819 // surrounding scene
7683 if ((ImageType)block.Type == ImageType.Baked) 7820 if ((ImageType)block.Type == ImageType.Baked)
7684 args.Priority *= 2.0f; 7821 args.Priority *= 2.0f;
7822 int wearableout = 0;
7685 7823
7686 ImageManager.EnqueueReq(args); 7824 ImageManager.EnqueueReq(args);
7687 } 7825 }
@@ -8700,16 +8838,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8700 8838
8701 #region Parcel related packets 8839 #region Parcel related packets
8702 8840
8841 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
8842 // to be done with minimal resources as possible
8843 // variables temporary here while in test
8844
8845 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
8846 bool RegionHandleRequestsInService = false;
8847
8703 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 8848 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8704 { 8849 {
8705 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 8850 UUID currentUUID;
8706 8851
8707 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 8852 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8708 if (handlerRegionHandleRequest != null) 8853
8854 if (handlerRegionHandleRequest == null)
8855 return true;
8856
8857 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
8858
8859 lock (RegionHandleRequests)
8709 { 8860 {
8710 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 8861 if (RegionHandleRequestsInService)
8862 {
8863 // we are already busy doing a previus request
8864 // so enqueue it
8865 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
8866 return true;
8867 }
8868
8869 // else do it
8870 currentUUID = rhrPack.RequestBlock.RegionID;
8871 RegionHandleRequestsInService = true;
8711 } 8872 }
8712 return true; 8873
8874 while (true)
8875 {
8876 handlerRegionHandleRequest(this, currentUUID);
8877
8878 lock (RegionHandleRequests)
8879 {
8880 // exit condition, nothing to do or closed
8881 // current code seems to assume we may loose the handler at anytime,
8882 // so keep checking it
8883 handlerRegionHandleRequest = OnRegionHandleRequest;
8884
8885 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
8886 {
8887 RegionHandleRequests.Clear();
8888 RegionHandleRequestsInService = false;
8889 return true;
8890 }
8891 currentUUID = RegionHandleRequests.Dequeue();
8892 }
8893 }
8894
8895 return true; // actually unreached
8713 } 8896 }
8714 8897
8715 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 8898 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -9965,7 +10148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9965 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10148 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9966 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10149 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9967 UpdateMuteListEntry.MuteData.MuteType, 10150 UpdateMuteListEntry.MuteData.MuteType,
9968 UpdateMuteListEntry.AgentData.AgentID); 10151 UpdateMuteListEntry.MuteData.MuteFlags);
9969 return true; 10152 return true;
9970 } 10153 }
9971 return false; 10154 return false;
@@ -9980,8 +10163,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9980 { 10163 {
9981 handlerRemoveMuteListEntry(this, 10164 handlerRemoveMuteListEntry(this,
9982 RemoveMuteListEntry.MuteData.MuteID, 10165 RemoveMuteListEntry.MuteData.MuteID,
9983 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10166 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9984 RemoveMuteListEntry.AgentData.AgentID);
9985 return true; 10167 return true;
9986 } 10168 }
9987 return false; 10169 return false;
@@ -10025,10 +10207,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10025 return false; 10207 return false;
10026 } 10208 }
10027 10209
10210 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10211 {
10212 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10213 (ChangeInventoryItemFlagsPacket)packet;
10214 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10215 if (handlerChangeInventoryItemFlags != null)
10216 {
10217 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10218 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10219 return true;
10220 }
10221 return false;
10222 }
10223
10028 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10224 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
10029 { 10225 {
10030 return true; 10226 return true;
10031 } 10227 }
10228
10229 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10230 {
10231 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10232
10233 #region Packet Session and User Check
10234 if (m_checkPackets)
10235 {
10236 if (packet.AgentData.SessionID != SessionId ||
10237 packet.AgentData.AgentID != AgentId)
10238 return true;
10239 }
10240 #endregion
10241 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10242 List<InventoryItemBase> items = new List<InventoryItemBase>();
10243 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10244 {
10245 InventoryItemBase b = new InventoryItemBase();
10246 b.ID = n.OldItemID;
10247 b.Folder = n.OldFolderID;
10248 items.Add(b);
10249 }
10250
10251 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10252 if (handlerMoveItemsAndLeaveCopy != null)
10253 {
10254 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10255 }
10256
10257 return true;
10258 }
10032 10259
10033 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10260 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
10034 { 10261 {
@@ -10455,6 +10682,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10455 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10682 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10456 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10683 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10457 10684
10685 Scene scene = (Scene)m_scene;
10686 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10687 {
10688 ScenePresence p;
10689 if (scene.TryGetScenePresence(sender.AgentId, out p))
10690 {
10691 if (p.GodLevel >= 200)
10692 {
10693 groupProfileReply.GroupData.OpenEnrollment = true;
10694 groupProfileReply.GroupData.MembershipFee = 0;
10695 }
10696 }
10697 }
10698
10458 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10699 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10459 } 10700 }
10460 return true; 10701 return true;
@@ -11028,11 +11269,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11028 11269
11029 StartLure handlerStartLure = OnStartLure; 11270 StartLure handlerStartLure = OnStartLure;
11030 if (handlerStartLure != null) 11271 if (handlerStartLure != null)
11031 handlerStartLure(startLureRequest.Info.LureType, 11272 {
11032 Utils.BytesToString( 11273 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
11033 startLureRequest.Info.Message), 11274 {
11034 startLureRequest.TargetData[0].TargetID, 11275 handlerStartLure(startLureRequest.Info.LureType,
11035 this); 11276 Utils.BytesToString(
11277 startLureRequest.Info.Message),
11278 startLureRequest.TargetData[i].TargetID,
11279 this);
11280 }
11281 }
11036 return true; 11282 return true;
11037 } 11283 }
11038 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11284 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11146,10 +11392,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11146 } 11392 }
11147 #endregion 11393 #endregion
11148 11394
11149 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11395 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11150 if (handlerClassifiedGodDelete != null) 11396 if (handlerClassifiedGodDelete != null)
11151 handlerClassifiedGodDelete( 11397 handlerClassifiedGodDelete(
11152 classifiedGodDelete.Data.ClassifiedID, 11398 classifiedGodDelete.Data.ClassifiedID,
11399 classifiedGodDelete.Data.QueryID,
11153 this); 11400 this);
11154 return true; 11401 return true;
11155 } 11402 }
@@ -11462,6 +11709,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11462 11709
11463 if (cachedtex.AgentData.SessionID != SessionId) 11710 if (cachedtex.AgentData.SessionID != SessionId)
11464 return false; 11711 return false;
11712
11465 11713
11466 // TODO: don't create new blocks if recycling an old packet 11714 // TODO: don't create new blocks if recycling an old packet
11467 cachedresp.AgentData.AgentID = AgentId; 11715 cachedresp.AgentData.AgentID = AgentId;
@@ -11471,14 +11719,140 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11471 cachedresp.WearableData = 11719 cachedresp.WearableData =
11472 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 11720 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11473 11721
11474 for (int i = 0; i < cachedtex.WearableData.Length; i++) 11722 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11723 // var item = fac.GetBakedTextureFaces(AgentId);
11724 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11725
11726 IAssetService cache = m_scene.AssetService;
11727 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11728 //bakedTextureModule = null;
11729 int maxWearablesLoop = cachedtex.WearableData.Length;
11730 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11731 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11732
11733 if (bakedTextureModule != null && cache != null)
11475 { 11734 {
11476 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 11735 // 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
11477 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 11736
11478 cachedresp.WearableData[i].TextureID = UUID.Zero; 11737 WearableCacheItem[] cacheItems = null;
11479 cachedresp.WearableData[i].HostName = new byte[0]; 11738 ScenePresence p = m_scene.GetScenePresence(AgentId);
11739 if (p.Appearance != null)
11740 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11741 {
11742 try
11743 {
11744 cacheItems = bakedTextureModule.Get(AgentId);
11745 p.Appearance.WearableCacheItems = cacheItems;
11746 p.Appearance.WearableCacheItemsDirty = false;
11747 }
11748
11749 /*
11750 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11751 *
11752 catch (System.Net.Sockets.SocketException)
11753 {
11754 cacheItems = null;
11755 }
11756 catch (WebException)
11757 {
11758 cacheItems = null;
11759 }
11760 catch (InvalidOperationException)
11761 {
11762 cacheItems = null;
11763 } */
11764 catch (Exception)
11765 {
11766 cacheItems = null;
11767 }
11768
11769 }
11770 else if (p.Appearance.WearableCacheItems != null)
11771 {
11772 cacheItems = p.Appearance.WearableCacheItems;
11773 }
11774
11775 if (cache != null && cacheItems != null)
11776 {
11777 foreach (WearableCacheItem item in cacheItems)
11778 {
11779
11780 if (cache.GetCached(item.TextureID.ToString()) == null)
11781 {
11782 item.TextureAsset.Temporary = true;
11783 cache.Store(item.TextureAsset);
11784 }
11785
11786
11787 }
11788 }
11789
11790 if (cacheItems != null)
11791 {
11792
11793 for (int i = 0; i < maxWearablesLoop; i++)
11794 {
11795 WearableCacheItem item =
11796 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11797
11798 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11799 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
11800 cachedresp.WearableData[i].HostName = new byte[0];
11801 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11802 {
11803
11804 cachedresp.WearableData[i].TextureID = item.TextureID;
11805 }
11806 else
11807 {
11808 cachedresp.WearableData[i].TextureID = UUID.Zero;
11809 }
11810 }
11811 }
11812 else
11813 {
11814 for (int i = 0; i < maxWearablesLoop; i++)
11815 {
11816 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11817 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11818 cachedresp.WearableData[i].TextureID = UUID.Zero;
11819 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11820 cachedresp.WearableData[i].HostName = new byte[0];
11821 }
11822 }
11480 } 11823 }
11824 else
11825 {
11826 if (cache == null)
11827 {
11828 for (int i = 0; i < maxWearablesLoop; i++)
11829 {
11830 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11831 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11832 cachedresp.WearableData[i].TextureID = UUID.Zero;
11833 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11834 cachedresp.WearableData[i].HostName = new byte[0];
11835 }
11836 }
11837 else
11838 {
11839 for (int i = 0; i < maxWearablesLoop; i++)
11840 {
11841 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11842 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11481 11843
11844
11845
11846 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11847 cachedresp.WearableData[i].TextureID = UUID.Zero;
11848 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11849 else
11850 cachedresp.WearableData[i].TextureID = UUID.Zero;
11851 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11852 cachedresp.WearableData[i].HostName = new byte[0];
11853 }
11854 }
11855 }
11482 cachedresp.Header.Zerocoded = true; 11856 cachedresp.Header.Zerocoded = true;
11483 OutPacket(cachedresp, ThrottleOutPacketType.Task); 11857 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11484 11858
@@ -11515,209 +11889,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11515 } 11889 }
11516 else 11890 else
11517 { 11891 {
11518// m_log.DebugFormat( 11892 ClientChangeObject updatehandler = onClientChangeObject;
11519// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11520// i, block.Type, part.Name, part.LocalId);
11521 11893
11522// // Do this once since fetch parts creates a new array. 11894 if (updatehandler != null)
11523// SceneObjectPart[] parts = part.ParentGroup.Parts; 11895 {
11524// for (int j = 0; j < parts.Length; j++) 11896 ObjectChangeData udata = new ObjectChangeData();
11525// {
11526// part.StoreUndoState();
11527// parts[j].IgnoreUndoUpdate = true;
11528// }
11529 11897
11530 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 11898 /*ubit from ll JIRA:
11899 * 0x01 position
11900 * 0x02 rotation
11901 * 0x04 scale
11902
11903 * 0x08 LINK_SET
11904 * 0x10 UNIFORM for scale
11905 */
11531 11906
11532 switch (block.Type) 11907 // translate to internal changes
11533 { 11908 // not all cases .. just the ones older code did
11534 case 1:
11535 Vector3 pos1 = new Vector3(block.Data, 0);
11536 11909
11537 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11910 switch (block.Type)
11538 if (handlerUpdatePrimSinglePosition != null) 11911 {
11539 { 11912 case 1: //change position sp
11540 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11913 udata.position = new Vector3(block.Data, 0);
11541 handlerUpdatePrimSinglePosition(localId, pos1, this);
11542 }
11543 break;
11544 11914
11545 case 2: 11915 udata.change = ObjectChangeType.primP;
11546 Quaternion rot1 = new Quaternion(block.Data, 0, true); 11916 updatehandler(localId, udata, this);
11917 break;
11547 11918
11548 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 11919 case 2: // rotation sp
11549 if (handlerUpdatePrimSingleRotation != null) 11920 udata.rotation = new Quaternion(block.Data, 0, true);
11550 {
11551 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11552 handlerUpdatePrimSingleRotation(localId, rot1, this);
11553 }
11554 break;
11555 11921
11556 case 3: 11922 udata.change = ObjectChangeType.primR;
11557 Vector3 rotPos = new Vector3(block.Data, 0); 11923 updatehandler(localId, udata, this);
11558 Quaternion rot2 = new Quaternion(block.Data, 12, true); 11924 break;
11559 11925
11560 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 11926 case 3: // position plus rotation
11561 if (handlerUpdatePrimSingleRotationPosition != null) 11927 udata.position = new Vector3(block.Data, 0);
11562 { 11928 udata.rotation = new Quaternion(block.Data, 12, true);
11563 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11564 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11565 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11566 }
11567 break;
11568 11929
11569 case 4: 11930 udata.change = ObjectChangeType.primPR;
11570 case 20: 11931 updatehandler(localId, udata, this);
11571 Vector3 scale4 = new Vector3(block.Data, 0); 11932 break;
11572 11933
11573 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 11934 case 4: // scale sp
11574 if (handlerUpdatePrimScale != null) 11935 udata.scale = new Vector3(block.Data, 0);
11575 { 11936 udata.change = ObjectChangeType.primS;
11576 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11577 handlerUpdatePrimScale(localId, scale4, this);
11578 }
11579 break;
11580 11937
11581 case 5: 11938 updatehandler(localId, udata, this);
11582 Vector3 scale1 = new Vector3(block.Data, 12); 11939 break;
11583 Vector3 pos11 = new Vector3(block.Data, 0);
11584 11940
11585 handlerUpdatePrimScale = OnUpdatePrimScale; 11941 case 0x14: // uniform scale sp
11586 if (handlerUpdatePrimScale != null) 11942 udata.scale = new Vector3(block.Data, 0);
11587 {
11588 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11589 handlerUpdatePrimScale(localId, scale1, this);
11590 11943
11591 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11944 udata.change = ObjectChangeType.primUS;
11592 if (handlerUpdatePrimSinglePosition != null) 11945 updatehandler(localId, udata, this);
11593 { 11946 break;
11594 handlerUpdatePrimSinglePosition(localId, pos11, this);
11595 }
11596 }
11597 break;
11598 11947
11599 case 9: 11948 case 5: // scale and position sp
11600 Vector3 pos2 = new Vector3(block.Data, 0); 11949 udata.position = new Vector3(block.Data, 0);
11950 udata.scale = new Vector3(block.Data, 12);
11601 11951
11602 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 11952 udata.change = ObjectChangeType.primPS;
11953 updatehandler(localId, udata, this);
11954 break;
11603 11955
11604 if (handlerUpdateVector != null) 11956 case 0x15: //uniform scale and position
11605 { 11957 udata.position = new Vector3(block.Data, 0);
11606 handlerUpdateVector(localId, pos2, this); 11958 udata.scale = new Vector3(block.Data, 12);
11607 }
11608 break;
11609 11959
11610 case 10: 11960 udata.change = ObjectChangeType.primPUS;
11611 Quaternion rot3 = new Quaternion(block.Data, 0, true); 11961 updatehandler(localId, udata, this);
11962 break;
11612 11963
11613 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 11964 // now group related (bit 4)
11614 if (handlerUpdatePrimRotation != null) 11965 case 9: //( 8 + 1 )group position
11615 { 11966 udata.position = new Vector3(block.Data, 0);
11616 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11617 handlerUpdatePrimRotation(localId, rot3, this);
11618 }
11619 break;
11620 11967
11621 case 11: 11968 udata.change = ObjectChangeType.groupP;
11622 Vector3 pos3 = new Vector3(block.Data, 0); 11969 updatehandler(localId, udata, this);
11623 Quaternion rot4 = new Quaternion(block.Data, 12, true); 11970 break;
11624 11971
11625 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 11972 case 0x0A: // (8 + 2) group rotation
11626 if (handlerUpdatePrimGroupRotation != null) 11973 udata.rotation = new Quaternion(block.Data, 0, true);
11627 {
11628 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11629 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11630 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11631 }
11632 break;
11633 case 12:
11634 case 28:
11635 Vector3 scale7 = new Vector3(block.Data, 0);
11636 11974
11637 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 11975 udata.change = ObjectChangeType.groupR;
11638 if (handlerUpdatePrimGroupScale != null) 11976 updatehandler(localId, udata, this);
11639 { 11977 break;
11640 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11641 handlerUpdatePrimGroupScale(localId, scale7, this);
11642 }
11643 break;
11644 11978
11645 case 13: 11979 case 0x0B: //( 8 + 2 + 1) group rotation and position
11646 Vector3 scale2 = new Vector3(block.Data, 12); 11980 udata.position = new Vector3(block.Data, 0);
11647 Vector3 pos4 = new Vector3(block.Data, 0); 11981 udata.rotation = new Quaternion(block.Data, 12, true);
11648 11982
11649 handlerUpdatePrimScale = OnUpdatePrimScale; 11983 udata.change = ObjectChangeType.groupPR;
11650 if (handlerUpdatePrimScale != null) 11984 updatehandler(localId, udata, this);
11651 { 11985 break;
11652 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11653 handlerUpdatePrimScale(localId, scale2, this);
11654 11986
11655 // Change the position based on scale (for bug number 246) 11987 case 0x0C: // (8 + 4) group scale
11656 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11988 // only afects root prim and only sent by viewer editor object tab scaling
11657 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11989 // mouse edition only allows uniform scaling
11658 if (handlerUpdatePrimSinglePosition != null) 11990 // SL MAY CHANGE THIS in viewers
11659 {
11660 handlerUpdatePrimSinglePosition(localId, pos4, this);
11661 }
11662 }
11663 break;
11664 11991
11665 case 29: 11992 udata.scale = new Vector3(block.Data, 0);
11666 Vector3 scale5 = new Vector3(block.Data, 12);
11667 Vector3 pos5 = new Vector3(block.Data, 0);
11668 11993
11669 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 11994 udata.change = ObjectChangeType.groupS;
11670 if (handlerUpdatePrimGroupScale != null) 11995 updatehandler(localId, udata, this);
11671 {
11672 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11673 part.StoreUndoState(true);
11674 part.IgnoreUndoUpdate = true;
11675 handlerUpdatePrimGroupScale(localId, scale5, this);
11676 handlerUpdateVector = OnUpdatePrimGroupPosition;
11677 11996
11678 if (handlerUpdateVector != null) 11997 break;
11679 {
11680 handlerUpdateVector(localId, pos5, this);
11681 }
11682 11998
11683 part.IgnoreUndoUpdate = false; 11999 case 0x0D: //(8 + 4 + 1) group scale and position
11684 } 12000 // exception as above
11685 12001
11686 break; 12002 udata.position = new Vector3(block.Data, 0);
12003 udata.scale = new Vector3(block.Data, 12);
11687 12004
11688 case 21: 12005 udata.change = ObjectChangeType.groupPS;
11689 Vector3 scale6 = new Vector3(block.Data, 12); 12006 updatehandler(localId, udata, this);
11690 Vector3 pos6 = new Vector3(block.Data, 0); 12007 break;
11691 12008
11692 handlerUpdatePrimScale = OnUpdatePrimScale; 12009 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11693 if (handlerUpdatePrimScale != null) 12010 udata.scale = new Vector3(block.Data, 0);
11694 {
11695 part.StoreUndoState(false);
11696 part.IgnoreUndoUpdate = true;
11697 12011
11698 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 12012 udata.change = ObjectChangeType.groupUS;
11699 handlerUpdatePrimScale(localId, scale6, this); 12013 updatehandler(localId, udata, this);
11700 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 12014 break;
11701 if (handlerUpdatePrimSinglePosition != null)
11702 {
11703 handlerUpdatePrimSinglePosition(localId, pos6, this);
11704 }
11705 12015
11706 part.IgnoreUndoUpdate = false; 12016 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11707 } 12017 udata.position = new Vector3(block.Data, 0);
11708 break; 12018 udata.scale = new Vector3(block.Data, 12);
11709 12019
11710 default: 12020 udata.change = ObjectChangeType.groupPUS;
11711 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12021 updatehandler(localId, udata, this);
11712 break; 12022 break;
12023
12024 default:
12025 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12026 break;
12027 }
11713 } 12028 }
11714 12029
11715// for (int j = 0; j < parts.Length; j++)
11716// parts[j].IgnoreUndoUpdate = false;
11717 } 12030 }
11718 } 12031 }
11719 } 12032 }
11720
11721 return true; 12033 return true;
11722 } 12034 }
11723 12035
@@ -11778,9 +12090,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11778 public void SetChildAgentThrottle(byte[] throttles) 12090 public void SetChildAgentThrottle(byte[] throttles)
11779 { 12091 {
11780 m_udpClient.SetThrottles(throttles); 12092 m_udpClient.SetThrottles(throttles);
12093 GenericCall2 handler = OnUpdateThrottles;
12094 if (handler != null)
12095 {
12096 handler();
12097 }
11781 } 12098 }
11782 12099
11783 /// <summary> 12100 /// <summary>
12101 /// Sets the throttles from values supplied by the client
12102 /// </summary>
12103 /// <param name="throttles"></param>
12104 public void SetAgentThrottleSilent(int throttle, int setting)
12105 {
12106 m_udpClient.ForceThrottleSetting(throttle,setting);
12107 //m_udpClient.SetThrottles(throttles);
12108
12109 }
12110
12111
12112 /// <summary>
11784 /// Get the current throttles for this client as a packed byte array 12113 /// Get the current throttles for this client as a packed byte array
11785 /// </summary> 12114 /// </summary>
11786 /// <param name="multiplier">Unused</param> 12115 /// <param name="multiplier">Unused</param>
@@ -12172,7 +12501,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12172// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12501// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12173// requestID, taskID, (SourceType)sourceType, Name); 12502// requestID, taskID, (SourceType)sourceType, Name);
12174 12503
12504
12505 //Note, the bool returned from the below function is useless since it is always false.
12175 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12506 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12507
12176 } 12508 }
12177 12509
12178 /// <summary> 12510 /// <summary>
@@ -12238,7 +12570,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12238 /// <returns></returns> 12570 /// <returns></returns>
12239 private static int CalculateNumPackets(byte[] data) 12571 private static int CalculateNumPackets(byte[] data)
12240 { 12572 {
12241 const uint m_maxPacketSize = 600; 12573// const uint m_maxPacketSize = 600;
12574 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12242 int numPackets = 1; 12575 int numPackets = 1;
12243 12576
12244 if (data == null) 12577 if (data == null)
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 621e0fd..e52ac37 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -92,7 +92,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
92 /// <summary>Packets we have sent that need to be ACKed by the client</summary> 92 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
93 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 93 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
94 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 94 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
95 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); 95 public readonly DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>();
96 96
97 /// <summary>Current packet sequence number</summary> 97 /// <summary>Current packet sequence number</summary>
98 public int CurrentSequence; 98 public int CurrentSequence;
@@ -146,7 +146,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
146 /// <summary>Throttle buckets for each packet category</summary> 146 /// <summary>Throttle buckets for each packet category</summary>
147 private readonly TokenBucket[] m_throttleCategories; 147 private readonly TokenBucket[] m_throttleCategories;
148 /// <summary>Outgoing queues for throttled packets</summary> 148 /// <summary>Outgoing queues for throttled packets</summary>
149 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 149 private readonly DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
150 /// <summary>A container that can hold one packet for each outbox, used to store 150 /// <summary>A container that can hold one packet for each outbox, used to store
151 /// dequeued packets that are being held for throttling</summary> 151 /// dequeued packets that are being held for throttling</summary>
152 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 152 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
@@ -158,6 +158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
158 158
159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
160 private int m_maxRTO = 60000; 160 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true;
161 162
162 /// <summary> 163 /// <summary>
163 /// Default constructor 164 /// Default constructor
@@ -201,7 +202,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
201 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 202 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
202 203
203 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 204 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
204 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 205 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
205 // Initialize the token buckets that control the throttling for each category 206 // Initialize the token buckets that control the throttling for each category
206 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); 207 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
207 } 208 }
@@ -429,11 +430,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
429 /// </returns> 430 /// </returns>
430 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) 431 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
431 { 432 {
433 return EnqueueOutgoing(packet, forceQueue, false);
434 }
435
436 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
437 {
432 int category = (int)packet.Category; 438 int category = (int)packet.Category;
433 439
434 if (category >= 0 && category < m_packetOutboxes.Length) 440 if (category >= 0 && category < m_packetOutboxes.Length)
435 { 441 {
436 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 442 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
443
444 if (m_deliverPackets == false)
445 {
446 queue.Enqueue(packet, highPriority);
447 return true;
448 }
449
437 TokenBucket bucket = m_throttleCategories[category]; 450 TokenBucket bucket = m_throttleCategories[category];
438 451
439 // Don't send this packet if there is already a packet waiting in the queue 452 // Don't send this packet if there is already a packet waiting in the queue
@@ -441,7 +454,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
441 // queued packets 454 // queued packets
442 if (queue.Count > 0) 455 if (queue.Count > 0)
443 { 456 {
444 queue.Enqueue(packet); 457 queue.Enqueue(packet, highPriority);
445 return true; 458 return true;
446 } 459 }
447 460
@@ -454,7 +467,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
454 else 467 else
455 { 468 {
456 // Force queue specified or not enough tokens in the bucket, queue this packet 469 // Force queue specified or not enough tokens in the bucket, queue this packet
457 queue.Enqueue(packet); 470 queue.Enqueue(packet, highPriority);
458 return true; 471 return true;
459 } 472 }
460 } 473 }
@@ -483,8 +496,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
483 /// <returns>True if any packets were sent, otherwise false</returns> 496 /// <returns>True if any packets were sent, otherwise false</returns>
484 public bool DequeueOutgoing() 497 public bool DequeueOutgoing()
485 { 498 {
486 OutgoingPacket packet; 499 if (m_deliverPackets == false) return false;
487 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 500
501 OutgoingPacket packet = null;
502 DoubleLocklessQueue<OutgoingPacket> queue;
488 TokenBucket bucket; 503 TokenBucket bucket;
489 bool packetSent = false; 504 bool packetSent = false;
490 ThrottleOutPacketTypeFlags emptyCategories = 0; 505 ThrottleOutPacketTypeFlags emptyCategories = 0;
@@ -515,32 +530,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
515 // No dequeued packet waiting to be sent, try to pull one off 530 // No dequeued packet waiting to be sent, try to pull one off
516 // this queue 531 // this queue
517 queue = m_packetOutboxes[i]; 532 queue = m_packetOutboxes[i];
518 if (queue.Dequeue(out packet)) 533 if (queue != null)
519 { 534 {
520 // A packet was pulled off the queue. See if we have 535 bool success = false;
521 // enough tokens in the bucket to send it out 536 try
522 if (bucket.RemoveTokens(packet.Buffer.DataLength))
523 { 537 {
524 // Send the packet 538 success = queue.Dequeue(out packet);
525 m_udpServer.SendPacketFinal(packet);
526 packetSent = true;
527 } 539 }
528 else 540 catch
529 { 541 {
530 // Save the dequeued packet for the next iteration 542 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
531 m_nextPackets[i] = packet;
532 } 543 }
533 544 if (success)
534 // If the queue is empty after this dequeue, fire the queue 545 {
535 // empty callback now so it has a chance to fill before we 546 // A packet was pulled off the queue. See if we have
536 // get back here 547 // enough tokens in the bucket to send it out
537 if (queue.Count == 0) 548 if (bucket.RemoveTokens(packet.Buffer.DataLength))
549 {
550 // Send the packet
551 m_udpServer.SendPacketFinal(packet);
552 packetSent = true;
553 }
554 else
555 {
556 // Save the dequeued packet for the next iteration
557 m_nextPackets[i] = packet;
558 }
559
560 // If the queue is empty after this dequeue, fire the queue
561 // empty callback now so it has a chance to fill before we
562 // get back here
563 if (queue.Count == 0)
564 emptyCategories |= CategoryToFlag(i);
565 }
566 else
567 {
568 // No packets in this queue. Fire the queue empty callback
569 // if it has not been called recently
538 emptyCategories |= CategoryToFlag(i); 570 emptyCategories |= CategoryToFlag(i);
571 }
539 } 572 }
540 else 573 else
541 { 574 {
542 // No packets in this queue. Fire the queue empty callback 575 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
543 // if it has not been called recently
544 emptyCategories |= CategoryToFlag(i); 576 emptyCategories |= CategoryToFlag(i);
545 } 577 }
546 } 578 }
@@ -649,6 +681,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
649 if (m_nextOnQueueEmpty == 0) 681 if (m_nextOnQueueEmpty == 0)
650 m_nextOnQueueEmpty = 1; 682 m_nextOnQueueEmpty = 1;
651 } 683 }
684 internal void ForceThrottleSetting(int throttle, int setting)
685 {
686 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ;
687 }
652 688
653 /// <summary> 689 /// <summary>
654 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a 690 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
@@ -693,4 +729,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
693 } 729 }
694 } 730 }
695 } 731 }
732
733 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
734 {
735 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
736
737 public override int Count
738 {
739 get
740 {
741 return base.Count + highQueue.Count;
742 }
743 }
744
745 public override bool Dequeue(out T item)
746 {
747 if (highQueue.Dequeue(out item))
748 return true;
749
750 return base.Dequeue(out item);
751 }
752
753 public void Enqueue(T item, bool highPriority)
754 {
755 if (highPriority)
756 highQueue.Enqueue(item);
757 else
758 Enqueue(item);
759 }
760 }
696} 761}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 72516cd..e07ce4c 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -126,7 +126,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 /// <summary>Handlers for incoming packets</summary> 126 /// <summary>Handlers for incoming packets</summary>
127 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 127 //PacketEventDictionary packetEvents = new PacketEventDictionary();
128 /// <summary>Incoming packets that are awaiting handling</summary> 128 /// <summary>Incoming packets that are awaiting handling</summary>
129 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 129 //private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
130
131 private DoubleQueue<IncomingPacket> packetInbox = new DoubleQueue<IncomingPacket>();
130 132
131 /// <summary></summary> 133 /// <summary></summary>
132 //private UDPClientCollection m_clients = new UDPClientCollection(); 134 //private UDPClientCollection m_clients = new UDPClientCollection();
@@ -181,6 +183,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 /// <summary>Flag to signal when clients should send pings</summary> 183 /// <summary>Flag to signal when clients should send pings</summary>
182 protected bool m_sendPing; 184 protected bool m_sendPing;
183 185
186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
184 private Pool<IncomingPacket> m_incomingPacketPool; 187 private Pool<IncomingPacket> m_incomingPacketPool;
185 188
186 /// <summary> 189 /// <summary>
@@ -787,6 +790,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
787 790
788 #region Queue or Send 791 #region Queue or Send
789 792
793 bool highPriority = false;
794
795 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
796 {
797 category = (ThrottleOutPacketType)((int)category & 127);
798 highPriority = true;
799 }
800
790 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 801 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
791 // If we were not provided a method for handling unacked, use the UDPServer default method 802 // If we were not provided a method for handling unacked, use the UDPServer default method
792 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 803 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
@@ -795,7 +806,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
795 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 806 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
796 // packet so that it isn't sent before a queued update packet. 807 // packet so that it isn't sent before a queued update packet.
797 bool requestQueue = type == PacketType.KillObject; 808 bool requestQueue = type == PacketType.KillObject;
798 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 809 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
799 SendPacketFinal(outgoingPacket); 810 SendPacketFinal(outgoingPacket);
800 811
801 #endregion Queue or Send 812 #endregion Queue or Send
@@ -1080,21 +1091,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1080 1091
1081 #region Packet to Client Mapping 1092 #region Packet to Client Mapping
1082 1093
1083 // UseCircuitCode handling 1094 // If there is already a client for this endpoint, don't process UseCircuitCode
1084 if (packet.Type == PacketType.UseCircuitCode) 1095 IClientAPI client = null;
1096 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1085 { 1097 {
1086 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1098 // UseCircuitCode handling
1087 // buffer. 1099 if (packet.Type == PacketType.UseCircuitCode)
1088 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1100 {
1101 // And if there is a UseCircuitCode pending, also drop it
1102 lock (m_pendingCache)
1103 {
1104 if (m_pendingCache.Contains(endPoint))
1105 return;
1089 1106
1090 Util.FireAndForget(HandleUseCircuitCode, array); 1107 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1108 }
1091 1109
1092 return; 1110 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1111 // buffer.
1112 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1113
1114 Util.FireAndForget(HandleUseCircuitCode, array);
1115
1116 return;
1117 }
1118 }
1119
1120 // If this is a pending connection, enqueue, don't process yet
1121 lock (m_pendingCache)
1122 {
1123 Queue<UDPPacketBuffer> queue;
1124 if (m_pendingCache.TryGetValue(endPoint, out queue))
1125 {
1126 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1127 queue.Enqueue(buffer);
1128 return;
1129 }
1093 } 1130 }
1094 1131
1095 // Determine which agent this packet came from 1132 // Determine which agent this packet came from
1096 IClientAPI client; 1133 if (client == null || !(client is LLClientView))
1097 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1098 { 1134 {
1099 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1135 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1100 return; 1136 return;
@@ -1103,7 +1139,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1103 udpClient = ((LLClientView)client).UDPClient; 1139 udpClient = ((LLClientView)client).UDPClient;
1104 1140
1105 if (!udpClient.IsConnected) 1141 if (!udpClient.IsConnected)
1142 {
1143// m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1106 return; 1144 return;
1145 }
1107 1146
1108 #endregion Packet to Client Mapping 1147 #endregion Packet to Client Mapping
1109 1148
@@ -1233,7 +1272,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1233 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1272 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1234 } 1273 }
1235 1274
1236 packetInbox.Enqueue(incomingPacket); 1275 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1276 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1277 packetInbox.EnqueueHigh(incomingPacket);
1278 else
1279 packetInbox.EnqueueLow(incomingPacket);
1237 } 1280 }
1238 1281
1239 #region BinaryStats 1282 #region BinaryStats
@@ -1379,6 +1422,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1379 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1422 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1380 if (client != null) 1423 if (client != null)
1381 client.SceneAgent.SendInitialDataToMe(); 1424 client.SceneAgent.SendInitialDataToMe();
1425
1426 // Now we know we can handle more data
1427 Thread.Sleep(200);
1428
1429 // Obtain the queue and remove it from the cache
1430 Queue<UDPPacketBuffer> queue = null;
1431
1432 lock (m_pendingCache)
1433 {
1434 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1435 {
1436 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1437 return;
1438 }
1439 m_pendingCache.Remove(endPoint);
1440 }
1441
1442 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1443
1444 // Reinject queued packets
1445 while(queue.Count > 0)
1446 {
1447 UDPPacketBuffer buf = queue.Dequeue();
1448 PacketReceived(buf);
1449 }
1450 queue = null;
1382 } 1451 }
1383 else 1452 else
1384 { 1453 {
@@ -1386,6 +1455,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1386 m_log.WarnFormat( 1455 m_log.WarnFormat(
1387 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1456 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1388 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1457 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1458 lock (m_pendingCache)
1459 m_pendingCache.Remove(endPoint);
1389 } 1460 }
1390 1461
1391 // m_log.DebugFormat( 1462 // m_log.DebugFormat(
@@ -1504,7 +1575,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1504 if (!client.SceneAgent.IsChildAgent) 1575 if (!client.SceneAgent.IsChildAgent)
1505 client.Kick("Simulator logged you out due to connection timeout"); 1576 client.Kick("Simulator logged you out due to connection timeout");
1506 1577
1507 client.CloseWithoutChecks(); 1578 client.CloseWithoutChecks(true);
1508 } 1579 }
1509 } 1580 }
1510 1581
@@ -1516,6 +1587,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1516 1587
1517 while (IsRunningInbound) 1588 while (IsRunningInbound)
1518 { 1589 {
1590 m_scene.ThreadAlive(1);
1519 try 1591 try
1520 { 1592 {
1521 IncomingPacket incomingPacket = null; 1593 IncomingPacket incomingPacket = null;
@@ -1563,6 +1635,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1563 1635
1564 while (base.IsRunningOutbound) 1636 while (base.IsRunningOutbound)
1565 { 1637 {
1638 m_scene.ThreadAlive(2);
1566 try 1639 try
1567 { 1640 {
1568 m_packetSent = false; 1641 m_packetSent = false;
@@ -1793,8 +1866,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1793 Packet packet = incomingPacket.Packet; 1866 Packet packet = incomingPacket.Packet;
1794 LLClientView client = incomingPacket.Client; 1867 LLClientView client = incomingPacket.Client;
1795 1868
1796 if (client.IsActive) 1869// if (client.IsActive)
1797 { 1870// {
1798 m_currentIncomingClient = client; 1871 m_currentIncomingClient = client;
1799 1872
1800 try 1873 try
@@ -1821,13 +1894,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1821 { 1894 {
1822 m_currentIncomingClient = null; 1895 m_currentIncomingClient = null;
1823 } 1896 }
1824 } 1897// }
1825 else 1898// else
1826 { 1899// {
1827 m_log.DebugFormat( 1900// m_log.DebugFormat(
1828 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1901// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1829 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1902// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1830 } 1903// }
1831 1904
1832 IncomingPacketsProcessed++; 1905 IncomingPacketsProcessed++;
1833 } 1906 }
@@ -1839,8 +1912,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1839 if (!client.IsLoggingOut) 1912 if (!client.IsLoggingOut)
1840 { 1913 {
1841 client.IsLoggingOut = true; 1914 client.IsLoggingOut = true;
1842 client.Close(); 1915 client.Close(false, false);
1843 } 1916 }
1844 } 1917 }
1845 } 1918 }
1846} \ No newline at end of file 1919}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index f143c32..7035e38 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -114,10 +114,6 @@ namespace OpenMetaverse
114 const int SIO_UDP_CONNRESET = -1744830452; 114 const int SIO_UDP_CONNRESET = -1744830452;
115 115
116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 116 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
117
118 m_log.DebugFormat(
119 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
120 ipep.Address, ipep.Port);
121 117
122 m_udpSocket = new Socket( 118 m_udpSocket = new Socket(
123 AddressFamily.InterNetwork, 119 AddressFamily.InterNetwork,