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.cs924
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs671
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs12
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs29
-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.cs16
-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.cs200
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs1497
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs115
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs229
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
16 files changed, 3852 insertions, 1179 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 568e216..83347e2 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/";
@@ -96,6 +100,9 @@ namespace OpenSim.Region.ClientStack.Linden
96 // private static readonly string m_fetchInventoryPath = "0006/"; 100 // private static readonly string m_fetchInventoryPath = "0006/";
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.
103 private static readonly string m_getObjectPhysicsDataPath = "0101/";
104 private static readonly string m_getObjectCostPath = "0102/";
105 private static readonly string m_ResourceCostSelectedPath = "0103/";
99 private static readonly string m_UpdateAgentInformationPath = "0500/"; 106 private static readonly string m_UpdateAgentInformationPath = "0500/";
100 107
101 // 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
@@ -111,12 +118,50 @@ namespace OpenSim.Region.ClientStack.Linden
111 private IAssetService m_assetService; 118 private IAssetService m_assetService;
112 private bool m_dumpAssetsToFile = false; 119 private bool m_dumpAssetsToFile = false;
113 private string m_regionName; 120 private string m_regionName;
121
114 private int m_levelUpload = 0; 122 private int m_levelUpload = 0;
115 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
116 public BunchOfCaps(Scene scene, Caps caps) 144 public BunchOfCaps(Scene scene, Caps caps)
117 { 145 {
118 m_Scene = scene; 146 m_Scene = scene;
119 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
120 IConfigSource config = m_Scene.Config; 165 IConfigSource config = m_Scene.Config;
121 if (config != null) 166 if (config != null)
122 { 167 {
@@ -131,6 +176,37 @@ namespace OpenSim.Region.ClientStack.Linden
131 { 176 {
132 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); 177 m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
133 } 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 }
134 } 210 }
135 211
136 m_assetService = m_Scene.AssetService; 212 m_assetService = m_Scene.AssetService;
@@ -142,6 +218,8 @@ namespace OpenSim.Region.ClientStack.Linden
142 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; 218 ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset;
143 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; 219 TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset;
144 GetClient = m_Scene.SceneGraph.GetControllingClient; 220 GetClient = m_Scene.SceneGraph.GetControllingClient;
221
222 m_FileAgentInventoryState = FileAgentInventoryState.idle;
145 } 223 }
146 224
147 /// <summary> 225 /// <summary>
@@ -187,7 +265,6 @@ namespace OpenSim.Region.ClientStack.Linden
187 { 265 {
188 try 266 try
189 { 267 {
190 // I don't think this one works...
191 m_HostCapsObj.RegisterHandler( 268 m_HostCapsObj.RegisterHandler(
192 "NewFileAgentInventory", 269 "NewFileAgentInventory",
193 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>( 270 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
@@ -204,6 +281,12 @@ namespace OpenSim.Region.ClientStack.Linden
204 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); 281 m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
205 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); 282 m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
206 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); 283 m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
284 IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
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);
207 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); 290 IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
208 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); 291 m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
209 292
@@ -388,62 +471,176 @@ namespace OpenSim.Region.ClientStack.Linden
388 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 471 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
389 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 472 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
390 473
474 // start by getting the client
475 IClientAPI client = null;
476 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
477
478 // check current state so we only have one service at a time
479 lock (m_ModelCost)
480 {
481 switch (m_FileAgentInventoryState)
482 {
483 case FileAgentInventoryState.processRequest:
484 case FileAgentInventoryState.processUpload:
485 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
486 resperror.message = "Uploader busy processing previus request";
487 resperror.identifier = UUID.Zero;
488
489 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
490 errorResponse.uploader = "";
491 errorResponse.state = "error";
492 errorResponse.error = resperror;
493 return errorResponse;
494 break;
495 case FileAgentInventoryState.waitUpload:
496 // todo stop current uploader server
497 break;
498 case FileAgentInventoryState.idle:
499 default:
500 break;
501 }
502
503 m_FileAgentInventoryState = FileAgentInventoryState.processRequest;
504 }
505
506 int cost = 0;
507 int nreqtextures = 0;
508 int nreqmeshs= 0;
509 int nreqinstances = 0;
510 bool IsAtestUpload = false;
511
512 string assetName = llsdRequest.name;
513
514 LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData();
515
391 if (llsdRequest.asset_type == "texture" || 516 if (llsdRequest.asset_type == "texture" ||
392 llsdRequest.asset_type == "animation" || 517 llsdRequest.asset_type == "animation" ||
518 llsdRequest.asset_type == "mesh" ||
393 llsdRequest.asset_type == "sound") 519 llsdRequest.asset_type == "sound")
394 { 520 {
395 ScenePresence avatar = null; 521 ScenePresence avatar = null;
396 IClientAPI client = null;
397 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); 522 m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar);
398 523
399 // check user level 524 // check user level
400 if (avatar != null) 525 if (avatar != null)
401 { 526 {
402 client = avatar.ControllingClient;
403
404 if (avatar.UserLevel < m_levelUpload) 527 if (avatar.UserLevel < m_levelUpload)
405 { 528 {
406 if (client != null) 529 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
407 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); 530 resperror.message = "Insufficient permissions to upload";
531 resperror.identifier = UUID.Zero;
408 532
409 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 533 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
410 errorResponse.uploader = ""; 534 errorResponse.uploader = "";
411 errorResponse.state = "error"; 535 errorResponse.state = "error";
536 errorResponse.error = resperror;
537 lock (m_ModelCost)
538 m_FileAgentInventoryState = FileAgentInventoryState.idle;
412 return errorResponse; 539 return errorResponse;
413 } 540 }
414 } 541 }
415 542
416 // check funds 543 // check test upload and funds
417 if (client != null) 544 if (client != null)
418 { 545 {
419 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>(); 546 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
420 547
548 int baseCost = 0;
421 if (mm != null) 549 if (mm != null)
550 baseCost = mm.UploadCharge;
551
552 string warning = String.Empty;
553
554 if (llsdRequest.asset_type == "mesh")
422 { 555 {
423 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 556 string error;
557 int modelcost;
558
559 if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost,
560 meshcostdata, out error, ref warning))
424 { 561 {
425 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 562 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
563 resperror.message = error;
564 resperror.identifier = UUID.Zero;
426 565
427 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); 566 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
428 errorResponse.uploader = ""; 567 errorResponse.uploader = "";
429 errorResponse.state = "error"; 568 errorResponse.state = "error";
569 errorResponse.error = resperror;
570
571 lock (m_ModelCost)
572 m_FileAgentInventoryState = FileAgentInventoryState.idle;
430 return errorResponse; 573 return errorResponse;
431 } 574 }
575 cost = modelcost;
576 }
577 else
578 {
579 cost = baseCost;
580 }
581
582 if (cost > 0 && mm != null)
583 {
584 // check for test upload
585
586 if (m_ForceFreeTestUpload) // all are test
587 {
588 if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it
589 assetName = "TEST-" + assetName;
590
591 IsAtestUpload = true;
592 }
593
594 else if (m_enableFreeTestUpload) // only if prefixed with "TEST-"
595 {
596
597 IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-"));
598 }
599
600
601 if(IsAtestUpload) // let user know, still showing cost estimation
602 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";
603
604 // check funds
605 else
606 {
607 if (!mm.UploadCovered(client.AgentId, (int)cost))
608 {
609 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
610 resperror.message = "Insuficient funds";
611 resperror.identifier = UUID.Zero;
612
613 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
614 errorResponse.uploader = "";
615 errorResponse.state = "error";
616 errorResponse.error = resperror;
617 lock (m_ModelCost)
618 m_FileAgentInventoryState = FileAgentInventoryState.idle;
619 return errorResponse;
620 }
621 }
432 } 622 }
623
624 if (client != null && warning != String.Empty)
625 client.SendAgentAlertMessage(warning, true);
433 } 626 }
434 } 627 }
435 628
436 string assetName = llsdRequest.name;
437 string assetDes = llsdRequest.description; 629 string assetDes = llsdRequest.description;
438 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; 630 string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath;
439 UUID newAsset = UUID.Random(); 631 UUID newAsset = UUID.Random();
440 UUID newInvItem = UUID.Random(); 632 UUID newInvItem = UUID.Random();
441 UUID parentFolder = llsdRequest.folder_id; 633 UUID parentFolder = llsdRequest.folder_id;
442 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 634 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
635 UUID texturesFolder = UUID.Zero;
636
637 if(!IsAtestUpload && m_enableModelUploadTextureToInventory)
638 texturesFolder = llsdRequest.texture_folder_id;
443 639
444 AssetUploader uploader = 640 AssetUploader uploader =
445 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 641 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
446 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 642 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost,
643 texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload);
447 644
448 m_HostCapsObj.HttpListener.AddStreamHandler( 645 m_HostCapsObj.HttpListener.AddStreamHandler(
449 new BinaryStreamHandler( 646 new BinaryStreamHandler(
@@ -461,10 +658,22 @@ namespace OpenSim.Region.ClientStack.Linden
461 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 658 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
462 uploaderPath; 659 uploaderPath;
463 660
661
464 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 662 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
465 uploadResponse.uploader = uploaderURL; 663 uploadResponse.uploader = uploaderURL;
466 uploadResponse.state = "upload"; 664 uploadResponse.state = "upload";
665 uploadResponse.upload_price = (int)cost;
666
667 if (llsdRequest.asset_type == "mesh")
668 {
669 uploadResponse.data = meshcostdata;
670 }
671
467 uploader.OnUpLoad += UploadCompleteHandler; 672 uploader.OnUpLoad += UploadCompleteHandler;
673
674 lock (m_ModelCost)
675 m_FileAgentInventoryState = FileAgentInventoryState.waitUpload;
676
468 return uploadResponse; 677 return uploadResponse;
469 } 678 }
470 679
@@ -476,8 +685,14 @@ namespace OpenSim.Region.ClientStack.Linden
476 /// <param name="data"></param> 685 /// <param name="data"></param>
477 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 686 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
478 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 687 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
479 string assetType) 688 string assetType, int cost,
689 UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
690 bool IsAtestUpload, ref string error)
480 { 691 {
692
693 lock (m_ModelCost)
694 m_FileAgentInventoryState = FileAgentInventoryState.processUpload;
695
481 m_log.DebugFormat( 696 m_log.DebugFormat(
482 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 697 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
483 assetID, inventoryItem, inventoryType, assetType); 698 assetID, inventoryItem, inventoryType, assetType);
@@ -485,117 +700,247 @@ namespace OpenSim.Region.ClientStack.Linden
485 sbyte assType = 0; 700 sbyte assType = 0;
486 sbyte inType = 0; 701 sbyte inType = 0;
487 702
703 IClientAPI client = null;
704
705 UUID owner_id = m_HostCapsObj.AgentID;
706 UUID creatorID;
707
708 bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0);
709
710 bool restrictPerms = m_RestrictFreeTestUploadPerms && istest;
711
712 if (istest && m_testAssetsCreatorID != UUID.Zero)
713 creatorID = m_testAssetsCreatorID;
714 else
715 creatorID = owner_id;
716
717 string creatorIDstr = creatorID.ToString();
718
719 IMoneyModule mm = m_Scene.RequestModuleInterface<IMoneyModule>();
720 if (mm != null)
721 {
722 // make sure client still has enougth credit
723 if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost))
724 {
725 error = "Insufficient funds.";
726 return;
727 }
728 }
729
730 // strings to types
488 if (inventoryType == "sound") 731 if (inventoryType == "sound")
489 { 732 {
490 inType = 1; 733 inType = (sbyte)InventoryType.Sound;
491 assType = 1; 734 assType = (sbyte)AssetType.Sound;
492 } 735 }
493 else if (inventoryType == "animation") 736 else if (inventoryType == "animation")
494 { 737 {
495 inType = 19; 738 inType = (sbyte)InventoryType.Animation;
496 assType = 20; 739 assType = (sbyte)AssetType.Animation;
497 } 740 }
498 else if (inventoryType == "wearable") 741 else if (inventoryType == "wearable")
499 { 742 {
500 inType = 18; 743 inType = (sbyte)InventoryType.Wearable;
501 switch (assetType) 744 switch (assetType)
502 { 745 {
503 case "bodypart": 746 case "bodypart":
504 assType = 13; 747 assType = (sbyte)AssetType.Bodypart;
505 break; 748 break;
506 case "clothing": 749 case "clothing":
507 assType = 5; 750 assType = (sbyte)AssetType.Clothing;
508 break; 751 break;
509 } 752 }
510 } 753 }
511 else if (inventoryType == "object") 754 else if (inventoryType == "object")
512 { 755 {
513 inType = (sbyte)InventoryType.Object; 756 if (assetType == "mesh") // this code for now is for mesh models uploads only
514 assType = (sbyte)AssetType.Object;
515
516 List<Vector3> positions = new List<Vector3>();
517 List<Quaternion> rotations = new List<Quaternion>();
518 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
519 OSDArray instance_list = (OSDArray)request["instance_list"];
520 OSDArray mesh_list = (OSDArray)request["mesh_list"];
521 OSDArray texture_list = (OSDArray)request["texture_list"];
522 SceneObjectGroup grp = null;
523
524 List<UUID> textures = new List<UUID>();
525 for (int i = 0; i < texture_list.Count; i++)
526 { 757 {
527 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); 758 inType = (sbyte)InventoryType.Object;
528 textureAsset.Data = texture_list[i].AsBinary(); 759 assType = (sbyte)AssetType.Object;
529 m_assetService.Store(textureAsset);
530 textures.Add(textureAsset.FullID);
531 }
532 760
533 for (int i = 0; i < mesh_list.Count; i++) 761 List<Vector3> positions = new List<Vector3>();
534 { 762 List<Quaternion> rotations = new List<Quaternion>();
535 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); 763 OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data);
764
765 // compare and get updated information
536 766
537 Primitive.TextureEntry textureEntry 767 bool mismatchError = true;
538 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE); 768
539 OSDMap inner_instance_list = (OSDMap)instance_list[i]; 769 while (mismatchError)
770 {
771 mismatchError = false;
772 }
540 773
541 OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; 774 if (mismatchError)
542 for (uint face = 0; face < face_list.Count; face++)
543 { 775 {
544 OSDMap faceMap = (OSDMap)face_list[(int)face]; 776 error = "Upload and fee estimation information don't match";
545 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); 777 lock (m_ModelCost)
546 if(faceMap.ContainsKey("fullbright")) 778 m_FileAgentInventoryState = FileAgentInventoryState.idle;
547 f.Fullbright = faceMap["fullbright"].AsBoolean(); 779
548 if (faceMap.ContainsKey ("diffuse_color")) 780 return;
549 f.RGBA = faceMap["diffuse_color"].AsColor4(); 781 }
550 782
551 int textureNum = faceMap["image"].AsInteger(); 783 OSDArray instance_list = (OSDArray)request["instance_list"];
552 float imagerot = faceMap["imagerot"].AsInteger(); 784 OSDArray mesh_list = (OSDArray)request["mesh_list"];
553 float offsets = (float)faceMap["offsets"].AsReal(); 785 OSDArray texture_list = (OSDArray)request["texture_list"];
554 float offsett = (float)faceMap["offsett"].AsReal(); 786 SceneObjectGroup grp = null;
555 float scales = (float)faceMap["scales"].AsReal();
556 float scalet = (float)faceMap["scalet"].AsReal();
557 787
558 if(imagerot != 0) 788 // create and store texture assets
559 f.Rotation = imagerot; 789 bool doTextInv = (!istest && m_enableModelUploadTextureToInventory &&
790 texturesFolder != UUID.Zero);
560 791
561 if(offsets != 0)
562 f.OffsetU = offsets;
563 792
564 if (offsett != 0) 793 List<UUID> textures = new List<UUID>();
565 f.OffsetV = offsett;
566 794
567 if (scales != 0) 795
568 f.RepeatU = scales; 796 if (doTextInv)
797 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
569 798
570 if (scalet != 0) 799 if(client == null) // don't put textures in inventory if there is no client
571 f.RepeatV = scalet; 800 doTextInv = false;
572 801
573 if (textures.Count > textureNum) 802 for (int i = 0; i < texture_list.Count; i++)
574 f.TextureID = textures[textureNum]; 803 {
575 else 804 AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr);
576 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; 805 textureAsset.Data = texture_list[i].AsBinary();
806 if (istest)
807 textureAsset.Local = true;
808 m_assetService.Store(textureAsset);
809 textures.Add(textureAsset.FullID);
810
811 if (doTextInv)
812 {
813 string name = assetName;
814 if (name.Length > 25)
815 name = name.Substring(0, 24);
816 name += "_Texture#" + i.ToString();
817 InventoryItemBase texitem = new InventoryItemBase();
818 texitem.Owner = m_HostCapsObj.AgentID;
819 texitem.CreatorId = creatorIDstr;
820 texitem.CreatorData = String.Empty;
821 texitem.ID = UUID.Random();
822 texitem.AssetID = textureAsset.FullID;
823 texitem.Description = "mesh model texture";
824 texitem.Name = name;
825 texitem.AssetType = (int)AssetType.Texture;
826 texitem.InvType = (int)InventoryType.Texture;
827 texitem.Folder = texturesFolder;
828
829 texitem.CurrentPermissions
830 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
831
832 texitem.BasePermissions = (uint)PermissionMask.All;
833 texitem.EveryOnePermissions = 0;
834 texitem.NextPermissions = (uint)PermissionMask.All;
835 texitem.CreationDate = Util.UnixTimeSinceEpoch();
836
837 m_Scene.AddInventoryItem(client, texitem);
838 texitem = null;
839 }
840 }
577 841
578 textureEntry.FaceTextures[face] = f; 842 // create and store meshs assets
843 List<UUID> meshAssets = new List<UUID>();
844 for (int i = 0; i < mesh_list.Count; i++)
845 {
846 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr);
847 meshAsset.Data = mesh_list[i].AsBinary();
848 if (istest)
849 meshAsset.Local = true;
850 m_assetService.Store(meshAsset);
851 meshAssets.Add(meshAsset.FullID);
579 } 852 }
580 853
581 pbs.TextureEntry = textureEntry.GetBytes(); 854 int skipedMeshs = 0;
855 // build prims from instances
856 for (int i = 0; i < instance_list.Count; i++)
857 {
858 OSDMap inner_instance_list = (OSDMap)instance_list[i];
859
860 // skip prims that are 2 small
861 Vector3 scale = inner_instance_list["scale"].AsVector3();
862
863 if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin)
864 {
865 skipedMeshs++;
866 continue;
867 }
868
869 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();
870
871 Primitive.TextureEntry textureEntry
872 = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
873
874
875 OSDArray face_list = (OSDArray)inner_instance_list["face_list"];
876 for (uint face = 0; face < face_list.Count; face++)
877 {
878 OSDMap faceMap = (OSDMap)face_list[(int)face];
879 Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
880 if (faceMap.ContainsKey("fullbright"))
881 f.Fullbright = faceMap["fullbright"].AsBoolean();
882 if (faceMap.ContainsKey("diffuse_color"))
883 f.RGBA = faceMap["diffuse_color"].AsColor4();
884
885 int textureNum = faceMap["image"].AsInteger();
886 float imagerot = faceMap["imagerot"].AsInteger();
887 float offsets = (float)faceMap["offsets"].AsReal();
888 float offsett = (float)faceMap["offsett"].AsReal();
889 float scales = (float)faceMap["scales"].AsReal();
890 float scalet = (float)faceMap["scalet"].AsReal();
891
892 if (imagerot != 0)
893 f.Rotation = imagerot;
894
895 if (offsets != 0)
896 f.OffsetU = offsets;
897
898 if (offsett != 0)
899 f.OffsetV = offsett;
900
901 if (scales != 0)
902 f.RepeatU = scales;
582 903
583 AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); 904 if (scalet != 0)
584 meshAsset.Data = mesh_list[i].AsBinary(); 905 f.RepeatV = scalet;
585 m_assetService.Store(meshAsset);
586 906
587 pbs.SculptEntry = true; 907 if (textures.Count > textureNum)
588 pbs.SculptTexture = meshAsset.FullID; 908 f.TextureID = textures[textureNum];
589 pbs.SculptType = (byte)SculptType.Mesh; 909 else
590 pbs.SculptData = meshAsset.Data; 910 f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE;
591 911
592 Vector3 position = inner_instance_list["position"].AsVector3(); 912 textureEntry.FaceTextures[face] = f;
593 Vector3 scale = inner_instance_list["scale"].AsVector3(); 913 }
594 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); 914
915 pbs.TextureEntry = textureEntry.GetBytes();
916
917 bool hasmesh = false;
918 if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ...
919 {
920 int meshindx = inner_instance_list["mesh"].AsInteger();
921 if (meshAssets.Count > meshindx)
922 {
923 pbs.SculptEntry = true;
924 pbs.SculptType = (byte)SculptType.Mesh;
925 pbs.SculptTexture = meshAssets[meshindx]; // actual asset UUID after meshs suport introduction
926 // data will be requested from asset on rez (i hope)
927 hasmesh = true;
928 }
929 }
930
931 Vector3 position = inner_instance_list["position"].AsVector3();
932 Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();
933
934 // for now viwers do send fixed defaults
935 // but this may change
936// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
937 byte physicsShapeType = (byte)PhysShapeType.prim; // default for mesh is simple convex
938 if(hasmesh)
939 physicsShapeType = (byte) PhysShapeType.convex; // default for mesh is simple convex
940// int material = inner_instance_list["material"].AsInteger();
941 byte material = (byte)Material.Wood;
595 942
596// no longer used - begin ------------------------ 943// no longer used - begin ------------------------
597// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
598// int material = inner_instance_list["material"].AsInteger();
599// int mesh = inner_instance_list["mesh"].AsInteger(); 944// int mesh = inner_instance_list["mesh"].AsInteger();
600 945
601// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; 946// OSDMap permissions = (OSDMap)inner_instance_list["permissions"];
@@ -610,24 +955,42 @@ namespace OpenSim.Region.ClientStack.Linden
610// UUID owner_id = permissions["owner_id"].AsUUID(); 955// UUID owner_id = permissions["owner_id"].AsUUID();
611// int owner_mask = permissions["owner_mask"].AsInteger(); 956// int owner_mask = permissions["owner_mask"].AsInteger();
612// no longer used - end ------------------------ 957// no longer used - end ------------------------
958
959
960 SceneObjectPart prim
961 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero);
962
963 prim.Scale = scale;
964 rotations.Add(rotation);
965 positions.Add(position);
966 prim.UUID = UUID.Random();
967 prim.CreatorID = creatorID;
968 prim.OwnerID = owner_id;
969 prim.GroupID = UUID.Zero;
970 prim.LastOwnerID = creatorID;
971 prim.CreationDate = Util.UnixTimeSinceEpoch();
972
973 if (grp == null)
974 prim.Name = assetName;
975 else
976 prim.Name = assetName + "#" + i.ToString();
613 977
614 UUID owner_id = m_HostCapsObj.AgentID; 978 if (restrictPerms)
979 {
980 prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
981 prim.EveryoneMask = 0;
982 prim.GroupMask = 0;
983 prim.NextOwnerMask = 0;
984 prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify);
985 }
615 986
616 SceneObjectPart prim 987 if(istest)
617 = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); 988 prim.Description = "For testing only. Other uses are prohibited";
989 else
990 prim.Description = "";
618 991
619 prim.Scale = scale; 992 prim.Material = material;
620 //prim.OffsetPosition = position; 993 prim.PhysicsShapeType = physicsShapeType;
621 rotations.Add(rotation);
622 positions.Add(position);
623 prim.UUID = UUID.Random();
624 prim.CreatorID = owner_id;
625 prim.OwnerID = owner_id;
626 prim.GroupID = UUID.Zero;
627 prim.LastOwnerID = prim.OwnerID;
628 prim.CreationDate = Util.UnixTimeSinceEpoch();
629 prim.Name = assetName;
630 prim.Description = "";
631 994
632// prim.BaseMask = (uint)base_mask; 995// prim.BaseMask = (uint)base_mask;
633// prim.EveryoneMask = (uint)everyone_mask; 996// prim.EveryoneMask = (uint)everyone_mask;
@@ -635,52 +998,64 @@ namespace OpenSim.Region.ClientStack.Linden
635// prim.NextOwnerMask = (uint)next_owner_mask; 998// prim.NextOwnerMask = (uint)next_owner_mask;
636// prim.OwnerMask = (uint)owner_mask; 999// prim.OwnerMask = (uint)owner_mask;
637 1000
638 if (grp == null) 1001 if (grp == null)
639 grp = new SceneObjectGroup(prim); 1002 {
640 else 1003 grp = new SceneObjectGroup(prim);
641 grp.AddPart(prim); 1004 grp.LastOwnerID = creatorID;
642 } 1005 }
1006 else
1007 grp.AddPart(prim);
1008 }
643 1009
644 Vector3 rootPos = positions[0]; 1010 Vector3 rootPos = positions[0];
645 1011
646 if (grp.Parts.Length > 1) 1012 if (grp.Parts.Length > 1)
647 { 1013 {
648 // Fix first link number 1014 // Fix first link number
649 grp.RootPart.LinkNum++; 1015 grp.RootPart.LinkNum++;
650 1016
651 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); 1017 Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]);
652 Quaternion tmprot; 1018 Quaternion tmprot;
653 Vector3 offset; 1019 Vector3 offset;
654 1020
655 // fix children rotations and positions 1021 // fix children rotations and positions
656 for (int i = 1; i < rotations.Count; i++) 1022 for (int i = 1; i < rotations.Count; i++)
657 { 1023 {
658 tmprot = rotations[i]; 1024 tmprot = rotations[i];
659 tmprot = rootRotConj * tmprot; 1025 tmprot = rootRotConj * tmprot;
1026
1027 grp.Parts[i].RotationOffset = tmprot;
660 1028
661 grp.Parts[i].RotationOffset = tmprot; 1029 offset = positions[i] - rootPos;
662 1030
663 offset = positions[i] - rootPos; 1031 offset *= rootRotConj;
1032 grp.Parts[i].OffsetPosition = offset;
1033 }
664 1034
665 offset *= rootRotConj; 1035 grp.AbsolutePosition = rootPos;
666 grp.Parts[i].OffsetPosition = offset; 1036 grp.UpdateGroupRotationR(rotations[0]);
1037 }
1038 else
1039 {
1040 grp.AbsolutePosition = rootPos;
1041 grp.UpdateGroupRotationR(rotations[0]);
667 } 1042 }
668 1043
669 grp.AbsolutePosition = rootPos; 1044 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
670 grp.UpdateGroupRotationR(rotations[0]);
671 } 1045 }
672 else 1046
1047 else // not a mesh model
673 { 1048 {
674 grp.AbsolutePosition = rootPos; 1049 m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload");
675 grp.UpdateGroupRotationR(rotations[0]); 1050 return;
676 } 1051 }
677
678 data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp));
679 } 1052 }
680 1053
681 AssetBase asset; 1054 AssetBase asset;
682 asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); 1055 asset = new AssetBase(assetID, assetName, assType, creatorIDstr);
683 asset.Data = data; 1056 asset.Data = data;
1057 if (istest)
1058 asset.Local = true;
684 if (AddNewAsset != null) 1059 if (AddNewAsset != null)
685 AddNewAsset(asset); 1060 AddNewAsset(asset);
686 else if (m_assetService != null) 1061 else if (m_assetService != null)
@@ -688,11 +1063,17 @@ namespace OpenSim.Region.ClientStack.Linden
688 1063
689 InventoryItemBase item = new InventoryItemBase(); 1064 InventoryItemBase item = new InventoryItemBase();
690 item.Owner = m_HostCapsObj.AgentID; 1065 item.Owner = m_HostCapsObj.AgentID;
691 item.CreatorId = m_HostCapsObj.AgentID.ToString(); 1066 item.CreatorId = creatorIDstr;
692 item.CreatorData = String.Empty; 1067 item.CreatorData = String.Empty;
693 item.ID = inventoryItem; 1068 item.ID = inventoryItem;
694 item.AssetID = asset.FullID; 1069 item.AssetID = asset.FullID;
695 item.Description = assetDescription; 1070 if (istest)
1071 {
1072 item.Description = "For testing only. Other uses are prohibited";
1073 item.Flags = (uint) (InventoryItemFlags.SharedSingleReference);
1074 }
1075 else
1076 item.Description = assetDescription;
696 item.Name = assetName; 1077 item.Name = assetName;
697 item.AssetType = assType; 1078 item.AssetType = assType;
698 item.InvType = inType; 1079 item.InvType = inType;
@@ -700,18 +1081,60 @@ namespace OpenSim.Region.ClientStack.Linden
700 1081
701 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current 1082 // If we set PermissionMask.All then when we rez the item the next permissions will replace the current
702 // (owner) permissions. This becomes a problem if next permissions are changed. 1083 // (owner) permissions. This becomes a problem if next permissions are changed.
703 item.CurrentPermissions
704 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
705 1084
706 item.BasePermissions = (uint)PermissionMask.All; 1085 if (restrictPerms)
707 item.EveryOnePermissions = 0; 1086 {
708 item.NextPermissions = (uint)PermissionMask.All; 1087 item.CurrentPermissions
1088 = (uint)(PermissionMask.Move | PermissionMask.Modify);
1089
1090 item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify);
1091 item.EveryOnePermissions = 0;
1092 item.NextPermissions = 0;
1093 }
1094 else
1095 {
1096 item.CurrentPermissions
1097 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
1098
1099 item.BasePermissions = (uint)PermissionMask.All;
1100 item.EveryOnePermissions = 0;
1101 item.NextPermissions = (uint)PermissionMask.All;
1102 }
1103
709 item.CreationDate = Util.UnixTimeSinceEpoch(); 1104 item.CreationDate = Util.UnixTimeSinceEpoch();
710 1105
1106 m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client);
1107
711 if (AddNewInventoryItem != null) 1108 if (AddNewInventoryItem != null)
712 { 1109 {
713 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 1110 if (istest)
1111 {
1112 m_Scene.AddInventoryItem(client, item);
1113/*
1114 AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0);
1115 if (client != null)
1116 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);
1117 */
1118 }
1119 else
1120 {
1121 AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost);
1122// if (client != null)
1123// {
1124// // let users see anything.. i don't so far
1125// string str;
1126// if (cost > 0)
1127// // dont remember where is money unit name to put here
1128// str = "Upload complete. charged " + cost.ToString() + "$";
1129// else
1130// str = "Upload complete";
1131// client.SendAgentAlertMessage(str, true);
1132// }
1133 }
714 } 1134 }
1135
1136 lock (m_ModelCost)
1137 m_FileAgentInventoryState = FileAgentInventoryState.idle;
715 } 1138 }
716 1139
717 /// <summary> 1140 /// <summary>
@@ -873,6 +1296,151 @@ namespace OpenSim.Region.ClientStack.Linden
873 return LLSDHelpers.SerialiseLLSDReply(response); 1296 return LLSDHelpers.SerialiseLLSDReply(response);
874 } 1297 }
875 1298
1299 public string GetObjectPhysicsData(string request, string path,
1300 string param, IOSHttpRequest httpRequest,
1301 IOSHttpResponse httpResponse)
1302 {
1303 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1304 OSDMap resp = new OSDMap();
1305 OSDArray object_ids = (OSDArray)req["object_ids"];
1306
1307 for (int i = 0 ; i < object_ids.Count ; i++)
1308 {
1309 UUID uuid = object_ids[i].AsUUID();
1310
1311 SceneObjectPart obj = m_Scene.GetSceneObjectPart(uuid);
1312 if (obj != null)
1313 {
1314 OSDMap object_data = new OSDMap();
1315
1316 object_data["PhysicsShapeType"] = obj.PhysicsShapeType;
1317 object_data["Density"] = obj.Density;
1318 object_data["Friction"] = obj.Friction;
1319 object_data["Restitution"] = obj.Bounciness;
1320 object_data["GravityMultiplier"] = obj.GravityModifier;
1321
1322 resp[uuid.ToString()] = object_data;
1323 }
1324 }
1325
1326 string response = OSDParser.SerializeLLSDXmlString(resp);
1327 return response;
1328 }
1329
1330 public string GetObjectCost(string request, string path,
1331 string param, IOSHttpRequest httpRequest,
1332 IOSHttpResponse httpResponse)
1333 {
1334 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1335 OSDMap resp = new OSDMap();
1336
1337 OSDArray object_ids = (OSDArray)req["object_ids"];
1338
1339 for (int i = 0; i < object_ids.Count; i++)
1340 {
1341 UUID uuid = object_ids[i].AsUUID();
1342
1343 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1344
1345 if (part != null)
1346 {
1347 SceneObjectGroup grp = part.ParentGroup;
1348 if (grp != null)
1349 {
1350 float linksetCost;
1351 float linksetPhysCost;
1352 float partCost;
1353 float partPhysCost;
1354
1355 grp.GetResourcesCosts(part, out linksetCost, out linksetPhysCost, out partCost, out partPhysCost);
1356
1357 OSDMap object_data = new OSDMap();
1358 object_data["linked_set_resource_cost"] = linksetCost;
1359 object_data["resource_cost"] = partCost;
1360 object_data["physics_cost"] = partPhysCost;
1361 object_data["linked_set_physics_cost"] = linksetPhysCost;
1362
1363 resp[uuid.ToString()] = object_data;
1364 }
1365 }
1366 }
1367
1368 string response = OSDParser.SerializeLLSDXmlString(resp);
1369 return response;
1370 }
1371
1372 public string ResourceCostSelected(string request, string path,
1373 string param, IOSHttpRequest httpRequest,
1374 IOSHttpResponse httpResponse)
1375 {
1376 OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request);
1377 OSDMap resp = new OSDMap();
1378
1379
1380 float phys=0;
1381 float stream=0;
1382 float simul=0;
1383
1384 if (req.ContainsKey("selected_roots"))
1385 {
1386 OSDArray object_ids = (OSDArray)req["selected_roots"];
1387
1388 // should go by SOG suming costs for all parts
1389 // ll v3 works ok with several objects select we get the list and adds ok
1390 // FS calls per object so results are wrong guess fs bug
1391 for (int i = 0; i < object_ids.Count; i++)
1392 {
1393 UUID uuid = object_ids[i].AsUUID();
1394 float Physc;
1395 float simulc;
1396 float streamc;
1397
1398 SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid);
1399 if (grp != null)
1400 {
1401 grp.GetSelectedCosts(out Physc, out streamc, out simulc);
1402 phys += Physc;
1403 stream += streamc;
1404 simul += simulc;
1405 }
1406 }
1407 }
1408 else if (req.ContainsKey("selected_prims"))
1409 {
1410 OSDArray object_ids = (OSDArray)req["selected_prims"];
1411
1412 // don't see in use in any of the 2 viewers
1413 // guess it should be for edit linked but... nothing
1414 // should go to SOP per part
1415 for (int i = 0; i < object_ids.Count; i++)
1416 {
1417 UUID uuid = object_ids[i].AsUUID();
1418
1419 SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid);
1420 if (part != null)
1421 {
1422 phys += part.PhysicsCost;
1423 stream += part.StreamingCost;
1424 simul += part.SimulationCost;
1425 }
1426 }
1427 }
1428
1429 if (simul != 0)
1430 {
1431 OSDMap object_data = new OSDMap();
1432
1433 object_data["physics"] = phys;
1434 object_data["streaming"] = stream;
1435 object_data["simulation"] = simul;
1436
1437 resp["selected"] = object_data;
1438 }
1439
1440 string response = OSDParser.SerializeLLSDXmlString(resp);
1441 return response;
1442 }
1443
876 public string UpdateAgentInformation(string request, string path, 1444 public string UpdateAgentInformation(string request, string path,
877 string param, IOSHttpRequest httpRequest, 1445 string param, IOSHttpRequest httpRequest,
878 IOSHttpResponse httpResponse) 1446 IOSHttpResponse httpResponse)
@@ -892,6 +1460,10 @@ namespace OpenSim.Region.ClientStack.Linden
892 1460
893 public class AssetUploader 1461 public class AssetUploader
894 { 1462 {
1463 private static readonly ILog m_log =
1464 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1465
1466
895 public event UpLoadedAsset OnUpLoad; 1467 public event UpLoadedAsset OnUpLoad;
896 private UpLoadedAsset handlerUpLoad = null; 1468 private UpLoadedAsset handlerUpLoad = null;
897 1469
@@ -906,10 +1478,21 @@ namespace OpenSim.Region.ClientStack.Linden
906 1478
907 private string m_invType = String.Empty; 1479 private string m_invType = String.Empty;
908 private string m_assetType = String.Empty; 1480 private string m_assetType = String.Empty;
1481 private int m_cost;
1482 private string m_error = String.Empty;
1483
1484 private Timer m_timeoutTimer = new Timer();
1485 private UUID m_texturesFolder;
1486 private int m_nreqtextures;
1487 private int m_nreqmeshs;
1488 private int m_nreqinstances;
1489 private bool m_IsAtestUpload;
909 1490
910 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1491 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
911 UUID parentFolderID, string invType, string assetType, string path, 1492 UUID parentFolderID, string invType, string assetType, string path,
912 IHttpServer httpServer, bool dumpAssetsToFile) 1493 IHttpServer httpServer, bool dumpAssetsToFile,
1494 int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
1495 bool IsAtestUpload)
913 { 1496 {
914 m_assetName = assetName; 1497 m_assetName = assetName;
915 m_assetDes = description; 1498 m_assetDes = description;
@@ -921,6 +1504,18 @@ namespace OpenSim.Region.ClientStack.Linden
921 m_assetType = assetType; 1504 m_assetType = assetType;
922 m_invType = invType; 1505 m_invType = invType;
923 m_dumpAssetsToFile = dumpAssetsToFile; 1506 m_dumpAssetsToFile = dumpAssetsToFile;
1507 m_cost = totalCost;
1508
1509 m_texturesFolder = texturesFolder;
1510 m_nreqtextures = nreqtextures;
1511 m_nreqmeshs = nreqmeshs;
1512 m_nreqinstances = nreqinstances;
1513 m_IsAtestUpload = IsAtestUpload;
1514
1515 m_timeoutTimer.Elapsed += TimedOut;
1516 m_timeoutTimer.Interval = 120000;
1517 m_timeoutTimer.AutoReset = false;
1518 m_timeoutTimer.Start();
924 } 1519 }
925 1520
926 /// <summary> 1521 /// <summary>
@@ -935,12 +1530,14 @@ namespace OpenSim.Region.ClientStack.Linden
935 UUID inv = inventoryItemID; 1530 UUID inv = inventoryItemID;
936 string res = String.Empty; 1531 string res = String.Empty;
937 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); 1532 LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete();
1533/*
938 uploadComplete.new_asset = newAssetID.ToString(); 1534 uploadComplete.new_asset = newAssetID.ToString();
939 uploadComplete.new_inventory_item = inv; 1535 uploadComplete.new_inventory_item = inv;
940 uploadComplete.state = "complete"; 1536 uploadComplete.state = "complete";
941 1537
942 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1538 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
943 1539*/
1540 m_timeoutTimer.Stop();
944 httpListener.RemoveStreamHandler("POST", uploaderPath); 1541 httpListener.RemoveStreamHandler("POST", uploaderPath);
945 1542
946 // TODO: probably make this a better set of extensions here 1543 // TODO: probably make this a better set of extensions here
@@ -957,12 +1554,49 @@ namespace OpenSim.Region.ClientStack.Linden
957 handlerUpLoad = OnUpLoad; 1554 handlerUpLoad = OnUpLoad;
958 if (handlerUpLoad != null) 1555 if (handlerUpLoad != null)
959 { 1556 {
960 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); 1557 handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType,
1558 m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, ref m_error);
961 } 1559 }
1560 if (m_IsAtestUpload)
1561 {
1562 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1563 resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions";
1564 resperror.identifier = inv;
1565
1566 uploadComplete.error = resperror;
1567 uploadComplete.state = "Upload4Testing";
1568 }
1569 else
1570 {
1571 if (m_error == String.Empty)
1572 {
1573 uploadComplete.new_asset = newAssetID.ToString();
1574 uploadComplete.new_inventory_item = inv;
1575 // if (m_texturesFolder != UUID.Zero)
1576 // uploadComplete.new_texture_folder_id = m_texturesFolder;
1577 uploadComplete.state = "complete";
1578 }
1579 else
1580 {
1581 LLSDAssetUploadError resperror = new LLSDAssetUploadError();
1582 resperror.message = m_error;
1583 resperror.identifier = inv;
962 1584
1585 uploadComplete.error = resperror;
1586 uploadComplete.state = "failed";
1587 }
1588 }
1589
1590 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
963 return res; 1591 return res;
964 } 1592 }
965 1593
1594 private void TimedOut(object sender, ElapsedEventArgs args)
1595 {
1596 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1597 httpListener.RemoveStreamHandler("POST", uploaderPath);
1598 }
1599
966 ///Left this in and commented in case there are unforseen issues 1600 ///Left this in and commented in case there are unforseen issues
967 //private void SaveAssetToFile(string filename, byte[] data) 1601 //private void SaveAssetToFile(string filename, byte[] data)
968 //{ 1602 //{
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 4d2c0f2..986a665 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);
@@ -807,5 +807,13 @@ namespace OpenSim.Region.ClientStack.Linden
807 { 807 {
808 return EventQueueHelper.BuildEvent(eventName, eventBody); 808 return EventQueueHelper.BuildEvent(eventName, eventBody);
809 } 809 }
810
811 public void partPhysicsProperties(uint localID, byte physhapetype,
812 float density, float friction, float bounce, float gravmod,UUID avatarID)
813 {
814 OSD item = EventQueueHelper.partPhysicsProperties(localID, physhapetype,
815 density, friction, bounce, gravmod);
816 Enqueue(item, avatarID);
817 }
810 } 818 }
811} 819}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs
index 3f49aba..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);
@@ -395,5 +402,25 @@ namespace OpenSim.Region.ClientStack.Linden
395 return message; 402 return message;
396 } 403 }
397 404
405 public static OSD partPhysicsProperties(uint localID, byte physhapetype,
406 float density, float friction, float bounce, float gravmod)
407 {
408
409 OSDMap physinfo = new OSDMap(6);
410 physinfo["LocalID"] = localID;
411 physinfo["Density"] = density;
412 physinfo["Friction"] = friction;
413 physinfo["GravityMultiplier"] = gravmod;
414 physinfo["Restitution"] = bounce;
415 physinfo["PhysicsShapeType"] = (int)physhapetype;
416
417 OSDArray array = new OSDArray(1);
418 array.Add(physinfo);
419
420 OSDMap llsdBody = new OSDMap(1);
421 llsdBody.Add("ObjectData", array);
422
423 return BuildEvent("ObjectPhysicsProperties", llsdBody);
424 }
398 } 425 }
399} 426}
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 33b1f77..60c1814 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(m_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"] = m_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();
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 17c7270..fcac182 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..04cd474 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -27,18 +27,22 @@
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;
39using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
40using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
41using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
42 46
43namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
44{ 48{
@@ -48,67 +52,72 @@ namespace OpenSim.Region.ClientStack.Linden
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] 52 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")]
49 public class WebFetchInvDescModule : INonSharedRegionModule 53 public class WebFetchInvDescModule : INonSharedRegionModule
50 { 54 {
51// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55 struct aPollRequest
56 {
57 public PollServiceInventoryEventArgs thepoll;
58 public UUID reqID;
59 public Hashtable request;
60 }
61
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 63
53 private Scene m_scene; 64 private Scene m_scene;
54 65
55 private IInventoryService m_InventoryService; 66 private IInventoryService m_InventoryService;
56 private ILibraryService m_LibraryService; 67 private ILibraryService m_LibraryService;
57 68
58 private bool m_Enabled; 69 private static WebFetchInvDescHandler m_webFetchHandler;
59 70
60 private string m_fetchInventoryDescendents2Url; 71 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
61 private string m_webFetchInventoryDescendentsUrl; 72 private static Thread[] m_workerThreads = null;
62 73
63 private WebFetchInvDescHandler m_webFetchHandler; 74 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
75 new OpenMetaverse.BlockingQueue<aPollRequest>();
64 76
65 #region ISharedRegionModule Members 77 #region ISharedRegionModule Members
66 78
67 public void Initialise(IConfigSource source) 79 public void Initialise(IConfigSource source)
68 { 80 {
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 } 81 }
81 82
82 public void AddRegion(Scene s) 83 public void AddRegion(Scene s)
83 { 84 {
84 if (!m_Enabled)
85 return;
86
87 m_scene = s; 85 m_scene = s;
88 } 86 }
89 87
90 public void RemoveRegion(Scene s) 88 public void RemoveRegion(Scene s)
91 { 89 {
92 if (!m_Enabled)
93 return;
94
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 90 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
91 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
96 m_scene = null; 92 m_scene = null;
97 } 93 }
98 94
99 public void RegionLoaded(Scene s) 95 public void RegionLoaded(Scene s)
100 { 96 {
101 if (!m_Enabled)
102 return;
103
104 m_InventoryService = m_scene.InventoryService; 97 m_InventoryService = m_scene.InventoryService;
105 m_LibraryService = m_scene.LibraryService; 98 m_LibraryService = m_scene.LibraryService;
106 99
107 // We'll reuse the same handler for all requests. 100 // We'll reuse the same handler for all requests.
108 if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost") 101 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
109 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
110 102
111 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 103 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
104 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
105
106 if (m_workerThreads == null)
107 {
108 m_workerThreads = new Thread[2];
109
110 for (uint i = 0; i < 2; i++)
111 {
112 m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests,
113 String.Format("InventoryWorkerThread{0}", i),
114 ThreadPriority.Normal,
115 false,
116 true,
117 null,
118 int.MaxValue);
119 }
120 }
112 } 121 }
113 122
114 public void PostInitialise() 123 public void PostInitialise()
@@ -126,43 +135,130 @@ namespace OpenSim.Region.ClientStack.Linden
126 135
127 #endregion 136 #endregion
128 137
129 private void RegisterCaps(UUID agentID, Caps caps) 138 ~WebFetchInvDescModule()
130 { 139 {
131 if (m_webFetchInventoryDescendentsUrl != "") 140 foreach (Thread t in m_workerThreads)
132 RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl); 141 Watchdog.AbortThread(t.ManagedThreadId);
133
134 if (m_fetchInventoryDescendents2Url != "")
135 RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
136 } 142 }
137 143
138 private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) 144 private class PollServiceInventoryEventArgs : PollServiceEventArgs
139 { 145 {
140 string capUrl; 146 private Dictionary<UUID, Hashtable> responses =
147 new Dictionary<UUID, Hashtable>();
148
149 public PollServiceInventoryEventArgs(UUID pId) :
150 base(null, null, null, null, pId, int.MaxValue)
151 {
152 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
153 GetEvents = (x, y) =>
154 {
155 lock (responses)
156 {
157 try
158 {
159 return responses[x];
160 }
161 finally
162 {
163 responses.Remove(x);
164 }
165 }
166 };
167
168 Request = (x, y) =>
169 {
170 aPollRequest reqinfo = new aPollRequest();
171 reqinfo.thepoll = this;
172 reqinfo.reqID = x;
173 reqinfo.request = y;
174
175 m_queue.Enqueue(reqinfo);
176 };
177
178 NoEvents = (x, y) =>
179 {
180/*
181 lock (requests)
182 {
183 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
184 requests.Remove(request);
185 }
186*/
187 Hashtable response = new Hashtable();
188
189 response["int_response_code"] = 500;
190 response["str_response_string"] = "Script timeout";
191 response["content_type"] = "text/plain";
192 response["keepalive"] = false;
193 response["reusecontext"] = false;
194
195 return response;
196 };
197 }
141 198
142 if (url == "localhost") 199 public void Process(aPollRequest requestinfo)
143 { 200 {
144 capUrl = "/CAPS/" + UUID.Random(); 201 UUID requestID = requestinfo.reqID;
202
203 Hashtable response = new Hashtable();
204
205 response["int_response_code"] = 200;
206 response["content_type"] = "text/plain";
207 response["keepalive"] = false;
208 response["reusecontext"] = false;
145 209
146 IRequestHandler reqHandler 210 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
147 = new RestStreamHandler( 211 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
148 "POST",
149 capUrl,
150 m_webFetchHandler.FetchInventoryDescendentsRequest,
151 "FetchInventoryDescendents2",
152 agentID.ToString());
153 212
154 caps.RegisterHandler(capName, reqHandler); 213 lock (responses)
214 responses[requestID] = response;
155 } 215 }
156 else 216 }
217
218 private void RegisterCaps(UUID agentID, Caps caps)
219 {
220 string capUrl = "/CAPS/" + UUID.Random() + "/";
221
222 // Register this as a poll service
223 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(agentID);
224
225 args.Type = PollServiceEventArgs.EventType.Inventory;
226 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
227
228 string hostName = m_scene.RegionInfo.ExternalHostName;
229 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
230 string protocol = "http";
231
232 if (MainServer.Instance.UseSSL)
157 { 233 {
158 capUrl = url; 234 hostName = MainServer.Instance.SSLCommonName;
235 port = MainServer.Instance.SSLPort;
236 protocol = "https";
237 }
238 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
239
240 m_capsDict[agentID] = capUrl;
241 }
159 242
160 caps.RegisterHandler(capName, capUrl); 243 private void DeregisterCaps(UUID agentID, Caps caps)
244 {
245 string capUrl;
246
247 if (m_capsDict.TryGetValue(agentID, out capUrl))
248 {
249 MainServer.Instance.RemoveHTTPHandler("", capUrl);
250 m_capsDict.Remove(agentID);
161 } 251 }
252 }
162 253
163// m_log.DebugFormat( 254 private void DoInventoryRequests()
164// "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}", 255 {
165// capName, capUrl, m_scene.RegionInfo.RegionName, agentID); 256 while (true)
257 {
258 aPollRequest poolreq = m_queue.Dequeue();
259
260 poolreq.thepoll.Process(poolreq);
261 }
166 } 262 }
167 } 263 }
168} \ No newline at end of file 264}
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 88b64f5..0a39ded 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));
@@ -791,7 +822,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
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;
793 824
794 OutPacket(handshake, ThrottleOutPacketType.Task); 825// OutPacket(handshake, ThrottleOutPacketType.Task);
826 // use same as MoveAgentIntoRegion (both should be task )
827 OutPacket(handshake, ThrottleOutPacketType.Unknown);
795 } 828 }
796 829
797 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) 830 public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
@@ -831,7 +864,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
831 reply.ChatData.OwnerID = ownerID; 864 reply.ChatData.OwnerID = ownerID;
832 reply.ChatData.SourceID = fromAgentID; 865 reply.ChatData.SourceID = fromAgentID;
833 866
834 OutPacket(reply, ThrottleOutPacketType.Task); 867 OutPacket(reply, ThrottleOutPacketType.Unknown);
835 } 868 }
836 869
837 /// <summary> 870 /// <summary>
@@ -864,32 +897,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
864 msg.MessageBlock.Message = Util.StringToBytes1024(im.message); 897 msg.MessageBlock.Message = Util.StringToBytes1024(im.message);
865 msg.MessageBlock.BinaryBucket = im.binaryBucket; 898 msg.MessageBlock.BinaryBucket = im.binaryBucket;
866 899
867 if (im.message.StartsWith("[grouptest]")) 900 OutPacket(msg, ThrottleOutPacketType.Task);
868 { // this block is test code for implementing group IM - delete when group IM is finished
869 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
870 if (eq != null)
871 {
872 im.dialog = 17;
873
874 //eq.ChatterboxInvitation(
875 // new UUID("00000000-68f9-1111-024e-222222111123"),
876 // "OpenSimulator Testing", im.fromAgentID, im.message, im.toAgentID, im.fromAgentName, im.dialog, 0,
877 // false, 0, new Vector3(), 1, im.imSessionID, im.fromGroup, im.binaryBucket);
878
879 eq.ChatterboxInvitation(
880 new UUID("00000000-68f9-1111-024e-222222111123"),
881 "OpenSimulator Testing", new UUID(im.fromAgentID), im.message, new UUID(im.toAgentID), im.fromAgentName, im.dialog, 0,
882 false, 0, new Vector3(), 1, new UUID(im.imSessionID), im.fromGroup, Util.StringToBytes256("OpenSimulator Testing"));
883
884 eq.ChatterBoxSessionAgentListUpdates(
885 new UUID("00000000-68f9-1111-024e-222222111123"),
886 new UUID(im.fromAgentID), new UUID(im.toAgentID), false, false, false);
887 }
888
889 Console.WriteLine("SendInstantMessage: " + msg);
890 }
891 else
892 OutPacket(msg, ThrottleOutPacketType.Task);
893 } 901 }
894 } 902 }
895 903
@@ -1117,6 +1125,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1117 public virtual void SendLayerData(float[] map) 1125 public virtual void SendLayerData(float[] map)
1118 { 1126 {
1119 Util.FireAndForget(DoSendLayerData, map); 1127 Util.FireAndForget(DoSendLayerData, map);
1128
1129 // Send it sync, and async. It's not that much data
1130 // and it improves user experience just so much!
1131 DoSendLayerData(map);
1120 } 1132 }
1121 1133
1122 /// <summary> 1134 /// <summary>
@@ -1129,16 +1141,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1129 1141
1130 try 1142 try
1131 { 1143 {
1132 //for (int y = 0; y < 16; y++) 1144 for (int y = 0; y < 16; y++)
1133 //{ 1145 {
1134 // for (int x = 0; x < 16; x++) 1146 for (int x = 0; x < 16; x+=4)
1135 // { 1147 {
1136 // SendLayerData(x, y, map); 1148 SendLayerPacket(x, y, map);
1137 // } 1149 }
1138 //} 1150 }
1139
1140 // Send LayerData in a spiral pattern. Fun!
1141 SendLayerTopRight(map, 0, 0, 15, 15);
1142 } 1151 }
1143 catch (Exception e) 1152 catch (Exception e)
1144 { 1153 {
@@ -1146,51 +1155,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1146 } 1155 }
1147 } 1156 }
1148 1157
1149 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1150 {
1151 // Row
1152 for (int i = x1; i <= x2; i++)
1153 SendLayerData(i, y1, map);
1154
1155 // Column
1156 for (int j = y1 + 1; j <= y2; j++)
1157 SendLayerData(x2, j, map);
1158
1159 if (x2 - x1 > 0)
1160 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1161 }
1162
1163 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1164 {
1165 // Row in reverse
1166 for (int i = x2; i >= x1; i--)
1167 SendLayerData(i, y2, map);
1168
1169 // Column in reverse
1170 for (int j = y2 - 1; j >= y1; j--)
1171 SendLayerData(x1, j, map);
1172
1173 if (x2 - x1 > 0)
1174 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1175 }
1176
1177 /// <summary> 1158 /// <summary>
1178 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1159 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1179 /// </summary> 1160 /// </summary>
1180 /// <param name="map">heightmap</param> 1161 /// <param name="map">heightmap</param>
1181 /// <param name="px">X coordinate for patches 0..12</param> 1162 /// <param name="px">X coordinate for patches 0..12</param>
1182 /// <param name="py">Y coordinate for patches 0..15</param> 1163 /// <param name="py">Y coordinate for patches 0..15</param>
1183 // private void SendLayerPacket(float[] map, int y, int x) 1164 private void SendLayerPacket(int x, int y, float[] map)
1184 // { 1165 {
1185 // int[] patches = new int[4]; 1166 int[] patches = new int[4];
1186 // patches[0] = x + 0 + y * 16; 1167 patches[0] = x + 0 + y * 16;
1187 // patches[1] = x + 1 + y * 16; 1168 patches[1] = x + 1 + y * 16;
1188 // patches[2] = x + 2 + y * 16; 1169 patches[2] = x + 2 + y * 16;
1189 // patches[3] = x + 3 + y * 16; 1170 patches[3] = x + 3 + y * 16;
1190 1171
1191 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1172 float[] heightmap = (map.Length == 65536) ?
1192 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1173 map :
1193 // } 1174 LLHeightFieldMoronize(map);
1175
1176 try
1177 {
1178 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1179 OutPacket(layerpack, ThrottleOutPacketType.Land);
1180 }
1181 catch
1182 {
1183 for (int px = x ; px < x + 4 ; px++)
1184 SendLayerData(px, y, map);
1185 }
1186 }
1194 1187
1195 /// <summary> 1188 /// <summary>
1196 /// Sends a specified patch to a client 1189 /// Sends a specified patch to a client
@@ -1210,7 +1203,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1203 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1211 layerpack.Header.Reliable = true; 1204 layerpack.Header.Reliable = true;
1212 1205
1213 OutPacket(layerpack, ThrottleOutPacketType.Land); 1206 OutPacket(layerpack, ThrottleOutPacketType.Task);
1214 } 1207 }
1215 catch (Exception e) 1208 catch (Exception e)
1216 { 1209 {
@@ -1573,7 +1566,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1573 1566
1574 public void SendKillObject(ulong regionHandle, List<uint> localIDs) 1567 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1575 { 1568 {
1576// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1569// foreach (uint id in localIDs)
1570// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1577 1571
1578 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1572 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1579 // TODO: don't create new blocks if recycling an old packet 1573 // TODO: don't create new blocks if recycling an old packet
@@ -1595,17 +1589,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1595 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race 1589 // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race
1596 // condition where a kill can be processed before an out-of-date update for the same object. 1590 // condition where a kill can be processed before an out-of-date update for the same object.
1597 // ProcessEntityUpdates() also takes the m_killRecord lock. 1591 // ProcessEntityUpdates() also takes the m_killRecord lock.
1598 lock (m_killRecord) 1592// lock (m_killRecord)
1599 { 1593// {
1600 foreach (uint localID in localIDs) 1594// foreach (uint localID in localIDs)
1601 m_killRecord.Add(localID); 1595// m_killRecord.Add(localID);
1602 1596
1603 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1597 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1604 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1598 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1605 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1599 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1606 // scene objects in a viewer until that viewer is relogged in. 1600 // scene objects in a viewer until that viewer is relogged in.
1607 OutPacket(kill, ThrottleOutPacketType.Task); 1601 OutPacket(kill, ThrottleOutPacketType.Task);
1608 } 1602// }
1609 } 1603 }
1610 } 1604 }
1611 1605
@@ -2063,9 +2057,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2063 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset); 2057 OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
2064 } 2058 }
2065 2059
2066 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2067 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId) 2060 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackId)
2068 { 2061 {
2062 SendInventoryItemCreateUpdate(Item, UUID.Zero, callbackId);
2063 }
2064
2065 /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
2066 public void SendInventoryItemCreateUpdate(InventoryItemBase Item, UUID transactionID, uint callbackId)
2067 {
2069 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 2068 const uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
2070 2069
2071 UpdateCreateInventoryItemPacket InventoryReply 2070 UpdateCreateInventoryItemPacket InventoryReply
@@ -2075,6 +2074,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2075 // TODO: don't create new blocks if recycling an old packet 2074 // TODO: don't create new blocks if recycling an old packet
2076 InventoryReply.AgentData.AgentID = AgentId; 2075 InventoryReply.AgentData.AgentID = AgentId;
2077 InventoryReply.AgentData.SimApproved = true; 2076 InventoryReply.AgentData.SimApproved = true;
2077 InventoryReply.AgentData.TransactionID = transactionID;
2078 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1]; 2078 InventoryReply.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
2079 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock(); 2079 InventoryReply.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
2080 InventoryReply.InventoryData[0].ItemID = Item.ID; 2080 InventoryReply.InventoryData[0].ItemID = Item.ID;
@@ -2144,16 +2144,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2144 replytask.InventoryData.TaskID = taskID; 2144 replytask.InventoryData.TaskID = taskID;
2145 replytask.InventoryData.Serial = serial; 2145 replytask.InventoryData.Serial = serial;
2146 replytask.InventoryData.Filename = fileName; 2146 replytask.InventoryData.Filename = fileName;
2147 OutPacket(replytask, ThrottleOutPacketType.Asset); 2147 OutPacket(replytask, ThrottleOutPacketType.Task);
2148 } 2148 }
2149 2149
2150 public void SendXferPacket(ulong xferID, uint packet, byte[] data) 2150 public void SendXferPacket(ulong xferID, uint packet, byte[] data, bool isTaskInventory)
2151 { 2151 {
2152 ThrottleOutPacketType type = ThrottleOutPacketType.Asset;
2153 if (isTaskInventory)
2154 type = ThrottleOutPacketType.Task;
2155
2152 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket); 2156 SendXferPacketPacket sendXfer = (SendXferPacketPacket)PacketPool.Instance.GetPacket(PacketType.SendXferPacket);
2153 sendXfer.XferID.ID = xferID; 2157 sendXfer.XferID.ID = xferID;
2154 sendXfer.XferID.Packet = packet; 2158 sendXfer.XferID.Packet = packet;
2155 sendXfer.DataPacket.Data = data; 2159 sendXfer.DataPacket.Data = data;
2156 OutPacket(sendXfer, ThrottleOutPacketType.Asset); 2160 OutPacket(sendXfer, type);
2157 } 2161 }
2158 2162
2159 public void SendAbortXferPacket(ulong xferID) 2163 public void SendAbortXferPacket(ulong xferID)
@@ -2335,6 +2339,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2335 OutPacket(sound, ThrottleOutPacketType.Task); 2339 OutPacket(sound, ThrottleOutPacketType.Task);
2336 } 2340 }
2337 2341
2342 public void SendTransferAbort(TransferRequestPacket transferRequest)
2343 {
2344 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2345 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2346 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2347 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2348 OutPacket(abort, ThrottleOutPacketType.Task);
2349 }
2350
2338 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2351 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2339 { 2352 {
2340 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2353 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2627,6 +2640,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2627 } 2640 }
2628 } 2641 }
2629 2642
2643 public void SendPartPhysicsProprieties(ISceneEntity entity)
2644 {
2645 SceneObjectPart part = (SceneObjectPart)entity;
2646 if (part != null && AgentId != UUID.Zero)
2647 {
2648 try
2649 {
2650 IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
2651 if (eq != null)
2652 {
2653 uint localid = part.LocalId;
2654 byte physshapetype = part.PhysicsShapeType;
2655 float density = part.Density;
2656 float friction = part.Friction;
2657 float bounce = part.Bounciness;
2658 float gravmod = part.GravityModifier;
2659
2660 eq.partPhysicsProperties(localid, physshapetype, density, friction, bounce, gravmod,AgentId);
2661 }
2662 }
2663 catch (Exception ex)
2664 {
2665 m_log.Error("Unable to send part Physics Proprieties - exception: " + ex.ToString());
2666 }
2667 part.UpdatePhysRequired = false;
2668 }
2669 }
2670
2671
2630 2672
2631 public void SendGroupNameReply(UUID groupLLUID, string GroupName) 2673 public void SendGroupNameReply(UUID groupLLUID, string GroupName)
2632 { 2674 {
@@ -2685,8 +2727,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2685 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2727 req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2686 return; 2728 return;
2687 } 2729 }
2730 int WearableOut = 0;
2731 bool isWearable = false;
2688 2732
2689 //m_log.Debug("sending asset " + req.RequestAssetID); 2733 if (req.AssetInf != null)
2734 isWearable =
2735 ((AssetType) req.AssetInf.Type ==
2736 AssetType.Bodypart || (AssetType) req.AssetInf.Type == AssetType.Clothing);
2737
2738
2739 //m_log.Debug("sending asset " + req.RequestAssetID + ", iswearable: " + isWearable);
2740
2741
2742 //if (isWearable)
2743 // m_log.Debug((AssetType)req.AssetInf.Type);
2744
2690 TransferInfoPacket Transfer = new TransferInfoPacket(); 2745 TransferInfoPacket Transfer = new TransferInfoPacket();
2691 Transfer.TransferInfo.ChannelType = 2; 2746 Transfer.TransferInfo.ChannelType = 2;
2692 Transfer.TransferInfo.Status = 0; 2747 Transfer.TransferInfo.Status = 0;
@@ -2708,7 +2763,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2708 Transfer.TransferInfo.Size = req.AssetInf.Data.Length; 2763 Transfer.TransferInfo.Size = req.AssetInf.Data.Length;
2709 Transfer.TransferInfo.TransferID = req.TransferRequestID; 2764 Transfer.TransferInfo.TransferID = req.TransferRequestID;
2710 Transfer.Header.Zerocoded = true; 2765 Transfer.Header.Zerocoded = true;
2711 OutPacket(Transfer, ThrottleOutPacketType.Asset); 2766 OutPacket(Transfer, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2712 2767
2713 if (req.NumPackets == 1) 2768 if (req.NumPackets == 1)
2714 { 2769 {
@@ -2719,12 +2774,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2719 TransferPacket.TransferData.Data = req.AssetInf.Data; 2774 TransferPacket.TransferData.Data = req.AssetInf.Data;
2720 TransferPacket.TransferData.Status = 1; 2775 TransferPacket.TransferData.Status = 1;
2721 TransferPacket.Header.Zerocoded = true; 2776 TransferPacket.Header.Zerocoded = true;
2722 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2777 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2723 } 2778 }
2724 else 2779 else
2725 { 2780 {
2726 int processedLength = 0; 2781 int processedLength = 0;
2727 int maxChunkSize = Settings.MAX_PACKET_SIZE - 100; 2782// int maxChunkSize = Settings.MAX_PACKET_SIZE - 100;
2783
2784 int maxChunkSize = (int) MaxTransferBytesPerPacket;
2728 int packetNumber = 0; 2785 int packetNumber = 0;
2729 2786
2730 while (processedLength < req.AssetInf.Data.Length) 2787 while (processedLength < req.AssetInf.Data.Length)
@@ -2750,7 +2807,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2750 TransferPacket.TransferData.Status = 1; 2807 TransferPacket.TransferData.Status = 1;
2751 } 2808 }
2752 TransferPacket.Header.Zerocoded = true; 2809 TransferPacket.Header.Zerocoded = true;
2753 OutPacket(TransferPacket, ThrottleOutPacketType.Asset); 2810 OutPacket(TransferPacket, isWearable ? ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority : ThrottleOutPacketType.Asset);
2754 2811
2755 processedLength += chunkSize; 2812 processedLength += chunkSize;
2756 packetNumber++; 2813 packetNumber++;
@@ -2795,7 +2852,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2795 reply.Data.ParcelID = parcelID; 2852 reply.Data.ParcelID = parcelID;
2796 reply.Data.OwnerID = land.OwnerID; 2853 reply.Data.OwnerID = land.OwnerID;
2797 reply.Data.Name = Utils.StringToBytes(land.Name); 2854 reply.Data.Name = Utils.StringToBytes(land.Name);
2798 reply.Data.Desc = Utils.StringToBytes(land.Description); 2855 if (land != null && land.Description != null && land.Description != String.Empty)
2856 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2857 else
2858 reply.Data.Desc = new Byte[0];
2799 reply.Data.ActualArea = land.Area; 2859 reply.Data.ActualArea = land.Area;
2800 reply.Data.BillableArea = land.Area; // TODO: what is this? 2860 reply.Data.BillableArea = land.Area; // TODO: what is this?
2801 2861
@@ -3502,24 +3562,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3502 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count]; 3562 aw.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[count];
3503 AgentWearablesUpdatePacket.WearableDataBlock awb; 3563 AgentWearablesUpdatePacket.WearableDataBlock awb;
3504 int idx = 0; 3564 int idx = 0;
3505 for (int i = 0; i < wearables.Length; i++) 3565
3506 { 3566 for (int i = 0; i < wearables.Length; i++)
3507 for (int j = 0; j < wearables[i].Count; j++) 3567 {
3508 { 3568 for (int j = 0; j < wearables[i].Count; j++)
3509 awb = new AgentWearablesUpdatePacket.WearableDataBlock(); 3569 {
3510 awb.WearableType = (byte)i; 3570 awb = new AgentWearablesUpdatePacket.WearableDataBlock();
3511 awb.AssetID = wearables[i][j].AssetID; 3571 awb.WearableType = (byte) i;
3512 awb.ItemID = wearables[i][j].ItemID; 3572 awb.AssetID = wearables[i][j].AssetID;
3513 aw.WearableData[idx] = awb; 3573 awb.ItemID = wearables[i][j].ItemID;
3514 idx++; 3574 aw.WearableData[idx] = awb;
3515 3575 idx++;
3516// m_log.DebugFormat( 3576
3517// "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}", 3577 // m_log.DebugFormat(
3518// awb.ItemID, awb.AssetID, i, Name); 3578 // "[APPEARANCE]: Sending wearable item/asset {0} {1} (index {2}) for {3}",
3519 } 3579 // awb.ItemID, awb.AssetID, i, Name);
3520 } 3580 }
3581 }
3521 3582
3522 OutPacket(aw, ThrottleOutPacketType.Task); 3583 OutPacket(aw, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority);
3523 } 3584 }
3524 3585
3525 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) 3586 public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry)
@@ -3530,7 +3591,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3530 3591
3531 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance); 3592 AvatarAppearancePacket avp = (AvatarAppearancePacket)PacketPool.Instance.GetPacket(PacketType.AvatarAppearance);
3532 // TODO: don't create new blocks if recycling an old packet 3593 // TODO: don't create new blocks if recycling an old packet
3533 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[218]; 3594 avp.VisualParam = new AvatarAppearancePacket.VisualParamBlock[visualParams.Length];
3534 avp.ObjectData.TextureEntry = textureEntry; 3595 avp.ObjectData.TextureEntry = textureEntry;
3535 3596
3536 AvatarAppearancePacket.VisualParamBlock avblock = null; 3597 AvatarAppearancePacket.VisualParamBlock avblock = null;
@@ -3543,7 +3604,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3543 3604
3544 avp.Sender.IsTrial = false; 3605 avp.Sender.IsTrial = false;
3545 avp.Sender.ID = agentID; 3606 avp.Sender.ID = agentID;
3546 //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); 3607 m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
3547 OutPacket(avp, ThrottleOutPacketType.Task); 3608 OutPacket(avp, ThrottleOutPacketType.Task);
3548 } 3609 }
3549 3610
@@ -3660,7 +3721,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3660 /// </summary> 3721 /// </summary>
3661 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3722 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3662 { 3723 {
3663 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3724 if (entity is SceneObjectPart)
3725 {
3726 SceneObjectPart e = (SceneObjectPart)entity;
3727 SceneObjectGroup g = e.ParentGroup;
3728 if (g.RootPart.Shape.State > 30) // HUD
3729 if (g.OwnerID != AgentId)
3730 return; // Don't send updates for other people's HUDs
3731 }
3732
3664 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3733 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3665 3734
3666 lock (m_entityUpdates.SyncRoot) 3735 lock (m_entityUpdates.SyncRoot)
@@ -3727,27 +3796,74 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3727 3796
3728 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3797 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3729 // condition where a kill can be processed before an out-of-date update for the same object. 3798 // condition where a kill can be processed before an out-of-date update for the same object.
3730 lock (m_killRecord) 3799 float avgTimeDilation = 1.0f;
3800 IEntityUpdate iupdate;
3801 Int32 timeinqueue; // this is just debugging code & can be dropped later
3802
3803 while (updatesThisCall < maxUpdates)
3731 { 3804 {
3732 float avgTimeDilation = 1.0f; 3805 lock (m_entityUpdates.SyncRoot)
3733 IEntityUpdate iupdate; 3806 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3734 Int32 timeinqueue; // this is just debugging code & can be dropped later 3807 break;
3735 3808
3736 while (updatesThisCall < maxUpdates) 3809 EntityUpdate update = (EntityUpdate)iupdate;
3810
3811 avgTimeDilation += update.TimeDilation;
3812 avgTimeDilation *= 0.5f;
3813
3814 if (update.Entity is SceneObjectPart)
3737 { 3815 {
3738 lock (m_entityUpdates.SyncRoot) 3816 SceneObjectPart part = (SceneObjectPart)update.Entity;
3739 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3740 break;
3741 3817
3742 EntityUpdate update = (EntityUpdate)iupdate; 3818 if (part.ParentGroup.IsDeleted)
3743 3819 continue;
3744 avgTimeDilation += update.TimeDilation;
3745 avgTimeDilation *= 0.5f;
3746 3820
3747 if (update.Entity is SceneObjectPart) 3821 if (part.ParentGroup.IsAttachment)
3822 { // Someone else's HUD, why are we getting these?
3823 if (part.ParentGroup.OwnerID != AgentId &&
3824 part.ParentGroup.RootPart.Shape.State > 30)
3825 continue;
3826 ScenePresence sp;
3827 // Owner is not in the sim, don't update it to
3828 // anyone
3829 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3830 continue;
3831
3832 List<SceneObjectGroup> atts = sp.GetAttachments();
3833 bool found = false;
3834 foreach (SceneObjectGroup att in atts)
3835 {
3836 if (att == part.ParentGroup)
3837 {
3838 found = true;
3839 break;
3840 }
3841 }
3842
3843 // It's an attachment of a valid avatar, but
3844 // doesn't seem to be attached, skip
3845 if (!found)
3846 continue;
3847
3848 // On vehicle crossing, the attachments are received
3849 // while the avatar is still a child. Don't send
3850 // updates here because the LocalId has not yet
3851 // been updated and the viewer will derender the
3852 // attachments until the avatar becomes root.
3853 if (sp.IsChildAgent)
3854 continue;
3855
3856 // If the object is an attachment we don't want it to be in the kill
3857 // record. Else attaching from inworld and subsequently dropping
3858 // it will no longer work.
3859// lock (m_killRecord)
3860// {
3861// m_killRecord.Remove(part.LocalId);
3862// m_killRecord.Remove(part.ParentGroup.RootPart.LocalId);
3863// }
3864 }
3865 else
3748 { 3866 {
3749 SceneObjectPart part = (SceneObjectPart)update.Entity;
3750
3751 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3867 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3752 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3868 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3753 // safety measure. 3869 // safety measure.
@@ -3758,241 +3874,177 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3758 // 3874 //
3759 // This doesn't appear to apply to child prims - a client will happily ignore these updates 3875 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3760 // after the root prim has been deleted. 3876 // after the root prim has been deleted.
3761 if (m_killRecord.Contains(part.LocalId)) 3877 //
3762 { 3878 // We ignore this for attachments because attaching something from inworld breaks unless we do.
3763 // m_log.WarnFormat( 3879// lock (m_killRecord)
3764 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", 3880// {
3765 // part.LocalId, Name); 3881// if (m_killRecord.Contains(part.LocalId))
3766 continue; 3882// continue;
3767 } 3883// if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3768 3884// continue;
3769 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3885// }
3886 }
3887
3888 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3889 {
3890 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3891 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3770 { 3892 {
3771 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3893 part.Shape.LightEntry = false;
3772 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3773 {
3774 part.Shape.LightEntry = false;
3775 }
3776 } 3894 }
3777 } 3895 }
3778 3896 }
3779 #region UpdateFlags to packet type conversion 3897
3780 3898 ++updatesThisCall;
3781 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; 3899
3782 3900 #region UpdateFlags to packet type conversion
3783 bool canUseCompressed = true; 3901
3784 bool canUseImproved = true; 3902 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3785 3903
3786 // Compressed object updates only make sense for LL primitives 3904 bool canUseCompressed = true;
3787 if (!(update.Entity is SceneObjectPart)) 3905 bool canUseImproved = true;
3906
3907 // Compressed object updates only make sense for LL primitives
3908 if (!(update.Entity is SceneObjectPart))
3909 {
3910 canUseCompressed = false;
3911 }
3912
3913 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3914 {
3915 canUseCompressed = false;
3916 canUseImproved = false;
3917 }
3918 else
3919 {
3920 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3921 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3922 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3923 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3788 { 3924 {
3789 canUseCompressed = false; 3925 canUseCompressed = false;
3790 } 3926 }
3791 3927
3792 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate)) 3928 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3929 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3930 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3931 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3932 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3933 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3934 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3935 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3936 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3937 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3938 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3939 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3940 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3941 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3793 { 3942 {
3794 canUseCompressed = false;
3795 canUseImproved = false; 3943 canUseImproved = false;
3796 } 3944 }
3797 else 3945 }
3798 {
3799 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3800 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3801 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3802 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3803 {
3804 canUseCompressed = false;
3805 }
3806
3807 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3808 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3809 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3810 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3811 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3812 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3813 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3814 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3815 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3816 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3817 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3818 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3819 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3820 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3821 {
3822 canUseImproved = false;
3823 }
3824 }
3825
3826 #endregion UpdateFlags to packet type conversion
3827
3828 #region Block Construction
3829
3830 // TODO: Remove this once we can build compressed updates
3831 canUseCompressed = false;
3832 3946
3833 if (!canUseImproved && !canUseCompressed) 3947 #endregion UpdateFlags to packet type conversion
3834 {
3835 ObjectUpdatePacket.ObjectDataBlock updateBlock;
3836 3948
3837 if (update.Entity is ScenePresence) 3949 #region Block Construction
3838 {
3839 updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
3840 }
3841 else
3842 {
3843 SceneObjectPart part = (SceneObjectPart)update.Entity;
3844 updateBlock = CreatePrimUpdateBlock(part, AgentId);
3845
3846 // If the part has become a private hud since the update was scheduled then we do not
3847 // want to send it to other avatars.
3848 if (part.ParentGroup.IsAttachment
3849 && part.ParentGroup.HasPrivateAttachmentPoint
3850 && part.ParentGroup.AttachedAvatar != AgentId)
3851 continue;
3852
3853 // If the part has since been deleted, then drop the update. In the case of attachments,
3854 // this is to avoid spurious updates to other viewers since post-processing of attachments
3855 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3856 // of the test above).
3857 //
3858 // Actual deletions (kills) happen in another method.
3859 if (part.ParentGroup.IsDeleted)
3860 continue;
3861 }
3862 3950
3863 objectUpdateBlocks.Value.Add(updateBlock); 3951 // TODO: Remove this once we can build compressed updates
3864 objectUpdates.Value.Add(update); 3952 canUseCompressed = false;
3865 }
3866 else if (!canUseImproved)
3867 {
3868 SceneObjectPart part = (SceneObjectPart)update.Entity;
3869 ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
3870 = CreateCompressedUpdateBlock(part, updateFlags);
3871
3872 // If the part has since been deleted, then drop the update. In the case of attachments,
3873 // this is to avoid spurious updates to other viewers since post-processing of attachments
3874 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3875 // of the test above).
3876 //
3877 // Actual deletions (kills) happen in another method.
3878 if (part.ParentGroup.IsDeleted)
3879 continue;
3880 3953
3881 compressedUpdateBlocks.Value.Add(compressedBlock); 3954 if (!canUseImproved && !canUseCompressed)
3882 compressedUpdates.Value.Add(update); 3955 {
3956 if (update.Entity is ScenePresence)
3957 {
3958 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3883 } 3959 }
3884 else 3960 else
3885 { 3961 {
3886 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3962 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3887 {
3888 // Self updates go into a special list
3889 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3890 terseAgentUpdates.Value.Add(update);
3891 }
3892 else
3893 {
3894 ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
3895 = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
3896
3897 // Everything else goes here
3898 if (update.Entity is SceneObjectPart)
3899 {
3900 SceneObjectPart part = (SceneObjectPart)update.Entity;
3901
3902 // If the part has become a private hud since the update was scheduled then we do not
3903 // want to send it to other avatars.
3904 if (part.ParentGroup.IsAttachment
3905 && part.ParentGroup.HasPrivateAttachmentPoint
3906 && part.ParentGroup.AttachedAvatar != AgentId)
3907 continue;
3908
3909 // If the part has since been deleted, then drop the update. In the case of attachments,
3910 // this is to avoid spurious updates to other viewers since post-processing of attachments
3911 // has to change the IsAttachment flag for various reasons (which will end up in a pass
3912 // of the test above).
3913 //
3914 // Actual deletions (kills) happen in another method.
3915 if (part.ParentGroup.IsDeleted)
3916 continue;
3917 }
3918
3919 terseUpdateBlocks.Value.Add(terseUpdateBlock);
3920 terseUpdates.Value.Add(update);
3921 }
3922 } 3963 }
3923
3924 ++updatesThisCall;
3925
3926 #endregion Block Construction
3927 } 3964 }
3928 3965 else if (!canUseImproved)
3929 #region Packet Sending 3966 {
3930 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3967 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3931 3968 }
3932 if (terseAgentUpdateBlocks.IsValueCreated) 3969 else
3933 { 3970 {
3934 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3971 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3972 // Self updates go into a special list
3973 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3974 else
3975 // Everything else goes here
3976 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3977 }
3935 3978
3936 ImprovedTerseObjectUpdatePacket packet 3979 #endregion Block Construction
3937 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); 3980 }
3938 3981
3939 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3982 #region Packet Sending
3940 packet.RegionData.TimeDilation = timeDilation; 3983
3941 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3984 const float TIME_DILATION = 1.0f;
3985 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3986
3987 if (terseAgentUpdateBlocks.IsValueCreated)
3988 {
3989 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3942 3990
3943 for (int i = 0; i < blocks.Count; i++) 3991 ImprovedTerseObjectUpdatePacket packet
3944 packet.ObjectData[i] = blocks[i]; 3992 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3945 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 3993 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3946 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); 3994 packet.RegionData.TimeDilation = timeDilation;
3947 } 3995 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3948 3996
3949 if (objectUpdateBlocks.IsValueCreated) 3997 for (int i = 0; i < blocks.Count; i++)
3950 { 3998 packet.ObjectData[i] = blocks[i];
3951 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3952
3953 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3954 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3955 packet.RegionData.TimeDilation = timeDilation;
3956 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3957
3958 for (int i = 0; i < blocks.Count; i++)
3959 packet.ObjectData[i] = blocks[i];
3960 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3961 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
3962 }
3963
3964 if (compressedUpdateBlocks.IsValueCreated)
3965 {
3966 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3967
3968 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3969 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3970 packet.RegionData.TimeDilation = timeDilation;
3971 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3972
3973 for (int i = 0; i < blocks.Count; i++)
3974 packet.ObjectData[i] = blocks[i];
3975 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3976 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
3977 }
3978 3999
3979 if (terseUpdateBlocks.IsValueCreated) 4000 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3980 { 4001 }
3981 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3982
3983 ImprovedTerseObjectUpdatePacket packet
3984 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
3985 PacketType.ImprovedTerseObjectUpdate);
3986 4002
3987 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4003 if (objectUpdateBlocks.IsValueCreated)
3988 packet.RegionData.TimeDilation = timeDilation; 4004 {
3989 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4005 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3990 4006
3991 for (int i = 0; i < blocks.Count; i++) 4007 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3992 packet.ObjectData[i] = blocks[i]; 4008 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3993 // If any of the packets created from this call go unacknowledged, all of the updates will be resent 4009 packet.RegionData.TimeDilation = timeDilation;
3994 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); 4010 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3995 } 4011
4012 for (int i = 0; i < blocks.Count; i++)
4013 packet.ObjectData[i] = blocks[i];
4014
4015 OutPacket(packet, ThrottleOutPacketType.Task, true);
4016 }
4017
4018 if (compressedUpdateBlocks.IsValueCreated)
4019 {
4020 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
4021
4022 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
4023 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4024 packet.RegionData.TimeDilation = timeDilation;
4025 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
4026
4027 for (int i = 0; i < blocks.Count; i++)
4028 packet.ObjectData[i] = blocks[i];
4029
4030 OutPacket(packet, ThrottleOutPacketType.Task, true);
4031 }
4032
4033 if (terseUpdateBlocks.IsValueCreated)
4034 {
4035 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4036
4037 ImprovedTerseObjectUpdatePacket packet
4038 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4039 PacketType.ImprovedTerseObjectUpdate);
4040 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4041 packet.RegionData.TimeDilation = timeDilation;
4042 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
4043
4044 for (int i = 0; i < blocks.Count; i++)
4045 packet.ObjectData[i] = blocks[i];
4046
4047 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
3996 } 4048 }
3997 4049
3998 #endregion Packet Sending 4050 #endregion Packet Sending
@@ -4285,11 +4337,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4285 4337
4286 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4338 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4287 // of the object rather than the properties when the packet was created 4339 // of the object rather than the properties when the packet was created
4288 OutPacket(packet, ThrottleOutPacketType.Task, true, 4340 // HACK : Remove intelligent resending until it's fixed in core
4289 delegate(OutgoingPacket oPacket) 4341 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4290 { 4342 // delegate(OutgoingPacket oPacket)
4291 ResendPropertyUpdates(updates, oPacket); 4343 // {
4292 }); 4344 // ResendPropertyUpdates(updates, oPacket);
4345 // });
4346 OutPacket(packet, ThrottleOutPacketType.Task, true);
4293 4347
4294 // pbcnt += blocks.Count; 4348 // pbcnt += blocks.Count;
4295 // ppcnt++; 4349 // ppcnt++;
@@ -4315,11 +4369,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4315 // of the object rather than the properties when the packet was created 4369 // of the object rather than the properties when the packet was created
4316 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4370 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4317 updates.Add(familyUpdates.Value[i]); 4371 updates.Add(familyUpdates.Value[i]);
4318 OutPacket(packet, ThrottleOutPacketType.Task, true, 4372 // HACK : Remove intelligent resending until it's fixed in core
4319 delegate(OutgoingPacket oPacket) 4373 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4320 { 4374 // delegate(OutgoingPacket oPacket)
4321 ResendPropertyUpdates(updates, oPacket); 4375 // {
4322 }); 4376 // ResendPropertyUpdates(updates, oPacket);
4377 // });
4378 OutPacket(packet, ThrottleOutPacketType.Task, true);
4323 4379
4324 // fpcnt++; 4380 // fpcnt++;
4325 // fbcnt++; 4381 // fbcnt++;
@@ -4691,7 +4747,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4691 4747
4692 if (landData.SimwideArea > 0) 4748 if (landData.SimwideArea > 0)
4693 { 4749 {
4694 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4750 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4751 // Never report more than sim total capacity
4752 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4753 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4695 updateMessage.SimWideMaxPrims = simulatorCapacity; 4754 updateMessage.SimWideMaxPrims = simulatorCapacity;
4696 } 4755 }
4697 else 4756 else
@@ -4820,14 +4879,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4820 4879
4821 if (notifyCount > 0) 4880 if (notifyCount > 0)
4822 { 4881 {
4823 if (notifyCount > 32) 4882// if (notifyCount > 32)
4824 { 4883// {
4825 m_log.InfoFormat( 4884// m_log.InfoFormat(
4826 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4885// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4827 + " - a developer might want to investigate whether this is a hard limit", 32); 4886// + " - a developer might want to investigate whether this is a hard limit", 32);
4828 4887//
4829 notifyCount = 32; 4888// notifyCount = 32;
4830 } 4889// }
4831 4890
4832 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4891 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4833 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4892 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4882,9 +4941,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4882 { 4941 {
4883 ScenePresence presence = (ScenePresence)entity; 4942 ScenePresence presence = (ScenePresence)entity;
4884 4943
4944 position = presence.OffsetPosition;
4945 rotation = presence.Rotation;
4946
4947 if (presence.ParentID != 0)
4948 {
4949 SceneObjectPart part = m_scene.GetSceneObjectPart(presence.ParentID);
4950 if (part != null && part != part.ParentGroup.RootPart)
4951 {
4952 position = part.OffsetPosition + presence.OffsetPosition * part.RotationOffset;
4953 rotation = part.RotationOffset * presence.Rotation;
4954 }
4955 }
4956
4885 attachPoint = 0; 4957 attachPoint = 0;
4886 collisionPlane = presence.CollisionPlane; 4958 collisionPlane = presence.CollisionPlane;
4887 position = presence.OffsetPosition;
4888 velocity = presence.Velocity; 4959 velocity = presence.Velocity;
4889 acceleration = Vector3.Zero; 4960 acceleration = Vector3.Zero;
4890 4961
@@ -5001,13 +5072,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5001 5072
5002 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data) 5073 protected ObjectUpdatePacket.ObjectDataBlock CreateAvatarUpdateBlock(ScenePresence data)
5003 { 5074 {
5075 Vector3 offsetPosition = data.OffsetPosition;
5076 Quaternion rotation = data.Rotation;
5077 uint parentID = data.ParentID;
5078
5079 if (parentID != 0)
5080 {
5081 SceneObjectPart part = m_scene.GetSceneObjectPart(parentID);
5082 if (part != null && part != part.ParentGroup.RootPart)
5083 {
5084 offsetPosition = part.OffsetPosition + data.OffsetPosition * part.RotationOffset;
5085 rotation = part.RotationOffset * data.Rotation;
5086 parentID = part.ParentGroup.RootPart.LocalId;
5087 }
5088 }
5089
5004 byte[] objectData = new byte[76]; 5090 byte[] objectData = new byte[76];
5005 5091
5006 data.CollisionPlane.ToBytes(objectData, 0); 5092 data.CollisionPlane.ToBytes(objectData, 0);
5007 data.OffsetPosition.ToBytes(objectData, 16); 5093 offsetPosition.ToBytes(objectData, 16);
5008// data.Velocity.ToBytes(objectData, 28); 5094// data.Velocity.ToBytes(objectData, 28);
5009// data.Acceleration.ToBytes(objectData, 40); 5095// data.Acceleration.ToBytes(objectData, 40);
5010 data.Rotation.ToBytes(objectData, 52); 5096 rotation.ToBytes(objectData, 52);
5011 //data.AngularVelocity.ToBytes(objectData, 64); 5097 //data.AngularVelocity.ToBytes(objectData, 64);
5012 5098
5013 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock(); 5099 ObjectUpdatePacket.ObjectDataBlock update = new ObjectUpdatePacket.ObjectDataBlock();
@@ -5021,14 +5107,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5021 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " + 5107 update.NameValue = Utils.StringToBytes("FirstName STRING RW SV " + data.Firstname + "\nLastName STRING RW SV " +
5022 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle); 5108 data.Lastname + "\nTitle STRING RW SV " + data.Grouptitle);
5023 update.ObjectData = objectData; 5109 update.ObjectData = objectData;
5024 update.ParentID = data.ParentID; 5110 update.ParentID = parentID;
5025 update.PathCurve = 16; 5111 update.PathCurve = 16;
5026 update.PathScaleX = 100; 5112 update.PathScaleX = 100;
5027 update.PathScaleY = 100; 5113 update.PathScaleY = 100;
5028 update.PCode = (byte)PCode.Avatar; 5114 update.PCode = (byte)PCode.Avatar;
5029 update.ProfileCurve = 1; 5115 update.ProfileCurve = 1;
5030 update.PSBlock = Utils.EmptyBytes; 5116 update.PSBlock = Utils.EmptyBytes;
5031 update.Scale = new Vector3(0.45f, 0.6f, 1.9f); 5117 update.Scale = data.Appearance.AvatarSize;
5118// update.Scale.Z -= 0.2f;
5119
5032 update.Text = Utils.EmptyBytes; 5120 update.Text = Utils.EmptyBytes;
5033 update.TextColor = new byte[4]; 5121 update.TextColor = new byte[4];
5034 5122
@@ -5039,10 +5127,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5039 update.TextureEntry = Utils.EmptyBytes; 5127 update.TextureEntry = Utils.EmptyBytes;
5040// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes; 5128// update.TextureEntry = (data.Appearance.Texture != null) ? data.Appearance.Texture.GetBytes() : Utils.EmptyBytes;
5041 5129
5130/* 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)
5042 update.UpdateFlags = (uint)( 5131 update.UpdateFlags = (uint)(
5043 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner | 5132 PrimFlags.Physics | PrimFlags.ObjectModify | PrimFlags.ObjectCopy | PrimFlags.ObjectAnyOwner |
5044 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer | 5133 PrimFlags.ObjectYouOwner | PrimFlags.ObjectMove | PrimFlags.InventoryEmpty | PrimFlags.ObjectTransfer |
5045 PrimFlags.ObjectOwnerModify); 5134 PrimFlags.ObjectOwnerModify);
5135*/
5136 update.UpdateFlags = 0;
5046 5137
5047 return update; 5138 return update;
5048 } 5139 }
@@ -5213,8 +5304,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5213 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs 5304 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5214 // for each AgentUpdate packet. 5305 // for each AgentUpdate packet.
5215 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5306 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5216 5307
5217 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5308 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5309 AddLocalPacketHandler(PacketType.VelocityInterpolateOff, HandleVelocityInterpolateOff, false);
5310 AddLocalPacketHandler(PacketType.VelocityInterpolateOn, HandleVelocityInterpolateOn, false);
5218 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5311 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5219 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5312 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
5220 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false); 5313 AddLocalPacketHandler(PacketType.MoneyTransferRequest, HandleMoneyTransferRequest, false);
@@ -5366,6 +5459,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5366 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5459 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5367 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5460 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5368 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5461 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5462 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5369 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5463 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5370 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5464 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5371 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5465 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5432,6 +5526,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5432 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5526 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5433 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5527 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5434 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5528 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5529 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5435 5530
5436 AddGenericPacketHandler("autopilot", HandleAutopilot); 5531 AddGenericPacketHandler("autopilot", HandleAutopilot);
5437 } 5532 }
@@ -5470,6 +5565,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5470 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || 5565 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5471 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || 5566 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5472 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || 5567 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5568 (x.ControlFlags != 0) ||
5473 (x.Far != m_lastAgentUpdateArgs.Far) || 5569 (x.Far != m_lastAgentUpdateArgs.Far) ||
5474 (x.Flags != m_lastAgentUpdateArgs.Flags) || 5570 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5475 (x.State != m_lastAgentUpdateArgs.State) || 5571 (x.State != m_lastAgentUpdateArgs.State) ||
@@ -5729,6 +5825,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5729 return true; 5825 return true;
5730 } 5826 }
5731 5827
5828 private bool HandleVelocityInterpolateOff(IClientAPI sender, Packet Pack)
5829 {
5830 VelocityInterpolateOffPacket p = (VelocityInterpolateOffPacket)Pack;
5831 if (p.AgentData.SessionID != SessionId ||
5832 p.AgentData.AgentID != AgentId)
5833 return true;
5834
5835 m_VelocityInterpolate = false;
5836 return true;
5837 }
5838
5839 private bool HandleVelocityInterpolateOn(IClientAPI sender, Packet Pack)
5840 {
5841 VelocityInterpolateOnPacket p = (VelocityInterpolateOnPacket)Pack;
5842 if (p.AgentData.SessionID != SessionId ||
5843 p.AgentData.AgentID != AgentId)
5844 return true;
5845
5846 m_VelocityInterpolate = true;
5847 return true;
5848 }
5849
5850
5732 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack) 5851 private bool HandleAvatarPropertiesRequest(IClientAPI sender, Packet Pack)
5733 { 5852 {
5734 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack; 5853 AvatarPropertiesRequestPacket avatarProperties = (AvatarPropertiesRequestPacket)Pack;
@@ -6149,17 +6268,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6149 // Temporarily protect ourselves from the mantis #951 failure. 6268 // Temporarily protect ourselves from the mantis #951 failure.
6150 // However, we could do this for several other handlers where a failure isn't terminal 6269 // However, we could do this for several other handlers where a failure isn't terminal
6151 // for the client session anyway, in order to protect ourselves against bad code in plugins 6270 // for the client session anyway, in order to protect ourselves against bad code in plugins
6271 Vector3 avSize = appear.AgentData.Size;
6152 try 6272 try
6153 { 6273 {
6154 byte[] visualparams = new byte[appear.VisualParam.Length]; 6274 byte[] visualparams = new byte[appear.VisualParam.Length];
6155 for (int i = 0; i < appear.VisualParam.Length; i++) 6275 for (int i = 0; i < appear.VisualParam.Length; i++)
6156 visualparams[i] = appear.VisualParam[i].ParamValue; 6276 visualparams[i] = appear.VisualParam[i].ParamValue;
6157 6277 //var b = appear.WearableData[0];
6278
6158 Primitive.TextureEntry te = null; 6279 Primitive.TextureEntry te = null;
6159 if (appear.ObjectData.TextureEntry.Length > 1) 6280 if (appear.ObjectData.TextureEntry.Length > 1)
6160 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); 6281 te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
6282
6283 WearableCacheItem[] cacheitems = new WearableCacheItem[appear.WearableData.Length];
6284 for (int i=0; i<appear.WearableData.Length;i++)
6285 cacheitems[i] = new WearableCacheItem(){CacheId = appear.WearableData[i].CacheID,TextureIndex=Convert.ToUInt32(appear.WearableData[i].TextureIndex)};
6286
6287
6161 6288
6162 handlerSetAppearance(sender, te, visualparams); 6289 handlerSetAppearance(sender, te, visualparams,avSize, cacheitems);
6163 } 6290 }
6164 catch (Exception e) 6291 catch (Exception e)
6165 { 6292 {
@@ -6368,6 +6495,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6368 { 6495 {
6369 handlerCompleteMovementToRegion(sender, true); 6496 handlerCompleteMovementToRegion(sender, true);
6370 } 6497 }
6498 else
6499 m_log.Debug("HandleCompleteAgentMovement NULL handler");
6500
6371 handlerCompleteMovementToRegion = null; 6501 handlerCompleteMovementToRegion = null;
6372 6502
6373 return true; 6503 return true;
@@ -6385,7 +6515,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6385 return true; 6515 return true;
6386 } 6516 }
6387 #endregion 6517 #endregion
6388 6518/*
6389 StartAnim handlerStartAnim = null; 6519 StartAnim handlerStartAnim = null;
6390 StopAnim handlerStopAnim = null; 6520 StopAnim handlerStopAnim = null;
6391 6521
@@ -6409,6 +6539,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6409 } 6539 }
6410 } 6540 }
6411 return true; 6541 return true;
6542*/
6543 ChangeAnim handlerChangeAnim = null;
6544
6545 for (int i = 0; i < AgentAni.AnimationList.Length; i++)
6546 {
6547 handlerChangeAnim = OnChangeAnim;
6548 if (handlerChangeAnim != null)
6549 {
6550 handlerChangeAnim(AgentAni.AnimationList[i].AnimID, AgentAni.AnimationList[i].StartAnim, false);
6551 }
6552 }
6553
6554 handlerChangeAnim = OnChangeAnim;
6555 if (handlerChangeAnim != null)
6556 {
6557 handlerChangeAnim(UUID.Zero, false, true);
6558 }
6559
6560 return true;
6412 } 6561 }
6413 6562
6414 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack) 6563 private bool HandleAgentRequestSit(IClientAPI sender, Packet Pack)
@@ -6634,6 +6783,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6634 #endregion 6783 #endregion
6635 6784
6636 m_udpClient.SetThrottles(atpack.Throttle.Throttles); 6785 m_udpClient.SetThrottles(atpack.Throttle.Throttles);
6786 GenericCall2 handler = OnUpdateThrottles;
6787 if (handler != null)
6788 {
6789 handler();
6790 }
6637 return true; 6791 return true;
6638 } 6792 }
6639 6793
@@ -7035,10 +7189,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7035 // 46,47,48 are special positions within the packet 7189 // 46,47,48 are special positions within the packet
7036 // This may change so perhaps we need a better way 7190 // This may change so perhaps we need a better way
7037 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) 7191 // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
7038 bool UsePhysics = (data[46] != 0) ? true : false; 7192 /*
7039 bool IsTemporary = (data[47] != 0) ? true : false; 7193 bool UsePhysics = (data[46] != 0) ? true : false;
7040 bool IsPhantom = (data[48] != 0) ? true : false; 7194 bool IsTemporary = (data[47] != 0) ? true : false;
7041 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this); 7195 bool IsPhantom = (data[48] != 0) ? true : false;
7196 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, this);
7197 */
7198 bool UsePhysics = flags.AgentData.UsePhysics;
7199 bool IsPhantom = flags.AgentData.IsPhantom;
7200 bool IsTemporary = flags.AgentData.IsTemporary;
7201 ObjectFlagUpdatePacket.ExtraPhysicsBlock[] blocks = flags.ExtraPhysics;
7202 ExtraPhysicsData physdata = new ExtraPhysicsData();
7203
7204 if (blocks == null || blocks.Length == 0)
7205 {
7206 physdata.PhysShapeType = PhysShapeType.invalid;
7207 }
7208 else
7209 {
7210 ObjectFlagUpdatePacket.ExtraPhysicsBlock phsblock = blocks[0];
7211 physdata.PhysShapeType = (PhysShapeType)phsblock.PhysicsShapeType;
7212 physdata.Bounce = phsblock.Restitution;
7213 physdata.Density = phsblock.Density;
7214 physdata.Friction = phsblock.Friction;
7215 physdata.GravitationModifier = phsblock.GravityMultiplier;
7216 }
7217
7218 handlerUpdatePrimFlags(flags.AgentData.ObjectLocalID, UsePhysics, IsTemporary, IsPhantom, physdata, this);
7042 } 7219 }
7043 return true; 7220 return true;
7044 } 7221 }
@@ -7621,6 +7798,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
7621 // surrounding scene 7798 // surrounding scene
7622 if ((ImageType)block.Type == ImageType.Baked) 7799 if ((ImageType)block.Type == ImageType.Baked)
7623 args.Priority *= 2.0f; 7800 args.Priority *= 2.0f;
7801 int wearableout = 0;
7624 7802
7625 ImageManager.EnqueueReq(args); 7803 ImageManager.EnqueueReq(args);
7626 } 7804 }
@@ -8639,16 +8817,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
8639 8817
8640 #region Parcel related packets 8818 #region Parcel related packets
8641 8819
8820 // acumulate several HandleRegionHandleRequest consecutive overlaping requests
8821 // to be done with minimal resources as possible
8822 // variables temporary here while in test
8823
8824 Queue<UUID> RegionHandleRequests = new Queue<UUID>();
8825 bool RegionHandleRequestsInService = false;
8826
8642 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack) 8827 private bool HandleRegionHandleRequest(IClientAPI sender, Packet Pack)
8643 { 8828 {
8644 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; 8829 UUID currentUUID;
8645 8830
8646 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest; 8831 RegionHandleRequest handlerRegionHandleRequest = OnRegionHandleRequest;
8647 if (handlerRegionHandleRequest != null) 8832
8833 if (handlerRegionHandleRequest == null)
8834 return true;
8835
8836 RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack;
8837
8838 lock (RegionHandleRequests)
8648 { 8839 {
8649 handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); 8840 if (RegionHandleRequestsInService)
8841 {
8842 // we are already busy doing a previus request
8843 // so enqueue it
8844 RegionHandleRequests.Enqueue(rhrPack.RequestBlock.RegionID);
8845 return true;
8846 }
8847
8848 // else do it
8849 currentUUID = rhrPack.RequestBlock.RegionID;
8850 RegionHandleRequestsInService = true;
8650 } 8851 }
8651 return true; 8852
8853 while (true)
8854 {
8855 handlerRegionHandleRequest(this, currentUUID);
8856
8857 lock (RegionHandleRequests)
8858 {
8859 // exit condition, nothing to do or closed
8860 // current code seems to assume we may loose the handler at anytime,
8861 // so keep checking it
8862 handlerRegionHandleRequest = OnRegionHandleRequest;
8863
8864 if (RegionHandleRequests.Count == 0 || !IsActive || handlerRegionHandleRequest == null)
8865 {
8866 RegionHandleRequests.Clear();
8867 RegionHandleRequestsInService = false;
8868 return true;
8869 }
8870 currentUUID = RegionHandleRequests.Dequeue();
8871 }
8872 }
8873
8874 return true; // actually unreached
8652 } 8875 }
8653 8876
8654 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack) 8877 private bool HandleParcelInfoRequest(IClientAPI sender, Packet Pack)
@@ -9904,7 +10127,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9904 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 10127 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9905 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 10128 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9906 UpdateMuteListEntry.MuteData.MuteType, 10129 UpdateMuteListEntry.MuteData.MuteType,
9907 UpdateMuteListEntry.AgentData.AgentID); 10130 UpdateMuteListEntry.MuteData.MuteFlags);
9908 return true; 10131 return true;
9909 } 10132 }
9910 return false; 10133 return false;
@@ -9919,8 +10142,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9919 { 10142 {
9920 handlerRemoveMuteListEntry(this, 10143 handlerRemoveMuteListEntry(this,
9921 RemoveMuteListEntry.MuteData.MuteID, 10144 RemoveMuteListEntry.MuteData.MuteID,
9922 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 10145 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9923 RemoveMuteListEntry.AgentData.AgentID);
9924 return true; 10146 return true;
9925 } 10147 }
9926 return false; 10148 return false;
@@ -9964,10 +10186,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9964 return false; 10186 return false;
9965 } 10187 }
9966 10188
10189 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
10190 {
10191 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
10192 (ChangeInventoryItemFlagsPacket)packet;
10193 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
10194 if (handlerChangeInventoryItemFlags != null)
10195 {
10196 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
10197 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
10198 return true;
10199 }
10200 return false;
10201 }
10202
9967 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 10203 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
9968 { 10204 {
9969 return true; 10205 return true;
9970 } 10206 }
10207
10208 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
10209 {
10210 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
10211
10212 #region Packet Session and User Check
10213 if (m_checkPackets)
10214 {
10215 if (packet.AgentData.SessionID != SessionId ||
10216 packet.AgentData.AgentID != AgentId)
10217 return true;
10218 }
10219 #endregion
10220 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
10221 List<InventoryItemBase> items = new List<InventoryItemBase>();
10222 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
10223 {
10224 InventoryItemBase b = new InventoryItemBase();
10225 b.ID = n.OldItemID;
10226 b.Folder = n.OldFolderID;
10227 items.Add(b);
10228 }
10229
10230 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
10231 if (handlerMoveItemsAndLeaveCopy != null)
10232 {
10233 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
10234 }
10235
10236 return true;
10237 }
9971 10238
9972 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 10239 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9973 { 10240 {
@@ -10394,6 +10661,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10394 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10661 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10395 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10662 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10396 10663
10664 Scene scene = (Scene)m_scene;
10665 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10666 {
10667 ScenePresence p;
10668 if (scene.TryGetScenePresence(sender.AgentId, out p))
10669 {
10670 if (p.GodLevel >= 200)
10671 {
10672 groupProfileReply.GroupData.OpenEnrollment = true;
10673 groupProfileReply.GroupData.MembershipFee = 0;
10674 }
10675 }
10676 }
10677
10397 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10678 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10398 } 10679 }
10399 return true; 10680 return true;
@@ -10967,11 +11248,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10967 11248
10968 StartLure handlerStartLure = OnStartLure; 11249 StartLure handlerStartLure = OnStartLure;
10969 if (handlerStartLure != null) 11250 if (handlerStartLure != null)
10970 handlerStartLure(startLureRequest.Info.LureType, 11251 {
10971 Utils.BytesToString( 11252 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10972 startLureRequest.Info.Message), 11253 {
10973 startLureRequest.TargetData[0].TargetID, 11254 handlerStartLure(startLureRequest.Info.LureType,
10974 this); 11255 Utils.BytesToString(
11256 startLureRequest.Info.Message),
11257 startLureRequest.TargetData[i].TargetID,
11258 this);
11259 }
11260 }
10975 return true; 11261 return true;
10976 } 11262 }
10977 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 11263 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -11085,10 +11371,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11085 } 11371 }
11086 #endregion 11372 #endregion
11087 11373
11088 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11374 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
11089 if (handlerClassifiedGodDelete != null) 11375 if (handlerClassifiedGodDelete != null)
11090 handlerClassifiedGodDelete( 11376 handlerClassifiedGodDelete(
11091 classifiedGodDelete.Data.ClassifiedID, 11377 classifiedGodDelete.Data.ClassifiedID,
11378 classifiedGodDelete.Data.QueryID,
11092 this); 11379 this);
11093 return true; 11380 return true;
11094 } 11381 }
@@ -11401,6 +11688,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11401 11688
11402 if (cachedtex.AgentData.SessionID != SessionId) 11689 if (cachedtex.AgentData.SessionID != SessionId)
11403 return false; 11690 return false;
11691
11404 11692
11405 // TODO: don't create new blocks if recycling an old packet 11693 // TODO: don't create new blocks if recycling an old packet
11406 cachedresp.AgentData.AgentID = AgentId; 11694 cachedresp.AgentData.AgentID = AgentId;
@@ -11410,14 +11698,140 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11410 cachedresp.WearableData = 11698 cachedresp.WearableData =
11411 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; 11699 new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
11412 11700
11413 for (int i = 0; i < cachedtex.WearableData.Length; i++) 11701 //IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
11702 // var item = fac.GetBakedTextureFaces(AgentId);
11703 //WearableCacheItem[] items = fac.GetCachedItems(AgentId);
11704
11705 IAssetService cache = m_scene.AssetService;
11706 IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
11707 //bakedTextureModule = null;
11708 int maxWearablesLoop = cachedtex.WearableData.Length;
11709 if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
11710 maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
11711
11712 if (bakedTextureModule != null && cache != null)
11414 { 11713 {
11415 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); 11714 // 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
11416 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; 11715
11417 cachedresp.WearableData[i].TextureID = UUID.Zero; 11716 WearableCacheItem[] cacheItems = null;
11418 cachedresp.WearableData[i].HostName = new byte[0]; 11717 ScenePresence p = m_scene.GetScenePresence(AgentId);
11718 if (p.Appearance != null)
11719 if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
11720 {
11721 try
11722 {
11723 cacheItems = bakedTextureModule.Get(AgentId);
11724 p.Appearance.WearableCacheItems = cacheItems;
11725 p.Appearance.WearableCacheItemsDirty = false;
11726 }
11727
11728 /*
11729 * The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
11730 *
11731 catch (System.Net.Sockets.SocketException)
11732 {
11733 cacheItems = null;
11734 }
11735 catch (WebException)
11736 {
11737 cacheItems = null;
11738 }
11739 catch (InvalidOperationException)
11740 {
11741 cacheItems = null;
11742 } */
11743 catch (Exception)
11744 {
11745 cacheItems = null;
11746 }
11747
11748 }
11749 else if (p.Appearance.WearableCacheItems != null)
11750 {
11751 cacheItems = p.Appearance.WearableCacheItems;
11752 }
11753
11754 if (cache != null && cacheItems != null)
11755 {
11756 foreach (WearableCacheItem item in cacheItems)
11757 {
11758
11759 if (cache.GetCached(item.TextureID.ToString()) == null)
11760 {
11761 item.TextureAsset.Temporary = true;
11762 cache.Store(item.TextureAsset);
11763 }
11764
11765
11766 }
11767 }
11768
11769 if (cacheItems != null)
11770 {
11771
11772 for (int i = 0; i < maxWearablesLoop; i++)
11773 {
11774 WearableCacheItem item =
11775 WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
11776
11777 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11778 cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
11779 cachedresp.WearableData[i].HostName = new byte[0];
11780 if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
11781 {
11782
11783 cachedresp.WearableData[i].TextureID = item.TextureID;
11784 }
11785 else
11786 {
11787 cachedresp.WearableData[i].TextureID = UUID.Zero;
11788 }
11789 }
11790 }
11791 else
11792 {
11793 for (int i = 0; i < maxWearablesLoop; i++)
11794 {
11795 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11796 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11797 cachedresp.WearableData[i].TextureID = UUID.Zero;
11798 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11799 cachedresp.WearableData[i].HostName = new byte[0];
11800 }
11801 }
11419 } 11802 }
11803 else
11804 {
11805 if (cache == null)
11806 {
11807 for (int i = 0; i < maxWearablesLoop; i++)
11808 {
11809 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11810 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11811 cachedresp.WearableData[i].TextureID = UUID.Zero;
11812 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11813 cachedresp.WearableData[i].HostName = new byte[0];
11814 }
11815 }
11816 else
11817 {
11818 for (int i = 0; i < maxWearablesLoop; i++)
11819 {
11820 cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
11821 cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
11822
11420 11823
11824
11825 if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
11826 cachedresp.WearableData[i].TextureID = UUID.Zero;
11827 //UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11828 else
11829 cachedresp.WearableData[i].TextureID = UUID.Zero;
11830 // UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
11831 cachedresp.WearableData[i].HostName = new byte[0];
11832 }
11833 }
11834 }
11421 cachedresp.Header.Zerocoded = true; 11835 cachedresp.Header.Zerocoded = true;
11422 OutPacket(cachedresp, ThrottleOutPacketType.Task); 11836 OutPacket(cachedresp, ThrottleOutPacketType.Task);
11423 11837
@@ -11454,209 +11868,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11454 } 11868 }
11455 else 11869 else
11456 { 11870 {
11457// m_log.DebugFormat( 11871 ClientChangeObject updatehandler = onClientChangeObject;
11458// "[CLIENT]: Processing block {0} type {1} for {2} {3}",
11459// i, block.Type, part.Name, part.LocalId);
11460 11872
11461// // Do this once since fetch parts creates a new array. 11873 if (updatehandler != null)
11462// SceneObjectPart[] parts = part.ParentGroup.Parts; 11874 {
11463// for (int j = 0; j < parts.Length; j++) 11875 ObjectChangeData udata = new ObjectChangeData();
11464// {
11465// part.StoreUndoState();
11466// parts[j].IgnoreUndoUpdate = true;
11467// }
11468 11876
11469 UpdatePrimGroupRotation handlerUpdatePrimGroupRotation; 11877 /*ubit from ll JIRA:
11878 * 0x01 position
11879 * 0x02 rotation
11880 * 0x04 scale
11881
11882 * 0x08 LINK_SET
11883 * 0x10 UNIFORM for scale
11884 */
11470 11885
11471 switch (block.Type) 11886 // translate to internal changes
11472 { 11887 // not all cases .. just the ones older code did
11473 case 1:
11474 Vector3 pos1 = new Vector3(block.Data, 0);
11475 11888
11476 UpdateVector handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11889 switch (block.Type)
11477 if (handlerUpdatePrimSinglePosition != null) 11890 {
11478 { 11891 case 1: //change position sp
11479 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11892 udata.position = new Vector3(block.Data, 0);
11480 handlerUpdatePrimSinglePosition(localId, pos1, this);
11481 }
11482 break;
11483 11893
11484 case 2: 11894 udata.change = ObjectChangeType.primP;
11485 Quaternion rot1 = new Quaternion(block.Data, 0, true); 11895 updatehandler(localId, udata, this);
11896 break;
11486 11897
11487 UpdatePrimSingleRotation handlerUpdatePrimSingleRotation = OnUpdatePrimSingleRotation; 11898 case 2: // rotation sp
11488 if (handlerUpdatePrimSingleRotation != null) 11899 udata.rotation = new Quaternion(block.Data, 0, true);
11489 {
11490 // m_log.Info("new tab rotation is " + rot1.X + " , " + rot1.Y + " , " + rot1.Z + " , " + rot1.W);
11491 handlerUpdatePrimSingleRotation(localId, rot1, this);
11492 }
11493 break;
11494 11900
11495 case 3: 11901 udata.change = ObjectChangeType.primR;
11496 Vector3 rotPos = new Vector3(block.Data, 0); 11902 updatehandler(localId, udata, this);
11497 Quaternion rot2 = new Quaternion(block.Data, 12, true); 11903 break;
11498 11904
11499 UpdatePrimSingleRotationPosition handlerUpdatePrimSingleRotationPosition = OnUpdatePrimSingleRotationPosition; 11905 case 3: // position plus rotation
11500 if (handlerUpdatePrimSingleRotationPosition != null) 11906 udata.position = new Vector3(block.Data, 0);
11501 { 11907 udata.rotation = new Quaternion(block.Data, 12, true);
11502 // m_log.Debug("new mouse rotation position is " + rotPos.X + " , " + rotPos.Y + " , " + rotPos.Z);
11503 // m_log.Info("new mouse rotation is " + rot2.X + " , " + rot2.Y + " , " + rot2.Z + " , " + rot2.W);
11504 handlerUpdatePrimSingleRotationPosition(localId, rot2, rotPos, this);
11505 }
11506 break;
11507 11908
11508 case 4: 11909 udata.change = ObjectChangeType.primPR;
11509 case 20: 11910 updatehandler(localId, udata, this);
11510 Vector3 scale4 = new Vector3(block.Data, 0); 11911 break;
11511 11912
11512 UpdateVector handlerUpdatePrimScale = OnUpdatePrimScale; 11913 case 4: // scale sp
11513 if (handlerUpdatePrimScale != null) 11914 udata.scale = new Vector3(block.Data, 0);
11514 { 11915 udata.change = ObjectChangeType.primS;
11515 // m_log.Debug("new scale is " + scale4.X + " , " + scale4.Y + " , " + scale4.Z);
11516 handlerUpdatePrimScale(localId, scale4, this);
11517 }
11518 break;
11519 11916
11520 case 5: 11917 updatehandler(localId, udata, this);
11521 Vector3 scale1 = new Vector3(block.Data, 12); 11918 break;
11522 Vector3 pos11 = new Vector3(block.Data, 0);
11523 11919
11524 handlerUpdatePrimScale = OnUpdatePrimScale; 11920 case 0x14: // uniform scale sp
11525 if (handlerUpdatePrimScale != null) 11921 udata.scale = new Vector3(block.Data, 0);
11526 {
11527 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11528 handlerUpdatePrimScale(localId, scale1, this);
11529 11922
11530 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11923 udata.change = ObjectChangeType.primUS;
11531 if (handlerUpdatePrimSinglePosition != null) 11924 updatehandler(localId, udata, this);
11532 { 11925 break;
11533 handlerUpdatePrimSinglePosition(localId, pos11, this);
11534 }
11535 }
11536 break;
11537 11926
11538 case 9: 11927 case 5: // scale and position sp
11539 Vector3 pos2 = new Vector3(block.Data, 0); 11928 udata.position = new Vector3(block.Data, 0);
11929 udata.scale = new Vector3(block.Data, 12);
11540 11930
11541 UpdateVector handlerUpdateVector = OnUpdatePrimGroupPosition; 11931 udata.change = ObjectChangeType.primPS;
11932 updatehandler(localId, udata, this);
11933 break;
11542 11934
11543 if (handlerUpdateVector != null) 11935 case 0x15: //uniform scale and position
11544 { 11936 udata.position = new Vector3(block.Data, 0);
11545 handlerUpdateVector(localId, pos2, this); 11937 udata.scale = new Vector3(block.Data, 12);
11546 }
11547 break;
11548 11938
11549 case 10: 11939 udata.change = ObjectChangeType.primPUS;
11550 Quaternion rot3 = new Quaternion(block.Data, 0, true); 11940 updatehandler(localId, udata, this);
11941 break;
11551 11942
11552 UpdatePrimRotation handlerUpdatePrimRotation = OnUpdatePrimGroupRotation; 11943 // now group related (bit 4)
11553 if (handlerUpdatePrimRotation != null) 11944 case 9: //( 8 + 1 )group position
11554 { 11945 udata.position = new Vector3(block.Data, 0);
11555 // Console.WriteLine("new rotation is " + rot3.X + " , " + rot3.Y + " , " + rot3.Z + " , " + rot3.W);
11556 handlerUpdatePrimRotation(localId, rot3, this);
11557 }
11558 break;
11559 11946
11560 case 11: 11947 udata.change = ObjectChangeType.groupP;
11561 Vector3 pos3 = new Vector3(block.Data, 0); 11948 updatehandler(localId, udata, this);
11562 Quaternion rot4 = new Quaternion(block.Data, 12, true); 11949 break;
11563 11950
11564 handlerUpdatePrimGroupRotation = OnUpdatePrimGroupMouseRotation; 11951 case 0x0A: // (8 + 2) group rotation
11565 if (handlerUpdatePrimGroupRotation != null) 11952 udata.rotation = new Quaternion(block.Data, 0, true);
11566 {
11567 // m_log.Debug("new rotation position is " + pos.X + " , " + pos.Y + " , " + pos.Z);
11568 // m_log.Debug("new group mouse rotation is " + rot4.X + " , " + rot4.Y + " , " + rot4.Z + " , " + rot4.W);
11569 handlerUpdatePrimGroupRotation(localId, pos3, rot4, this);
11570 }
11571 break;
11572 case 12:
11573 case 28:
11574 Vector3 scale7 = new Vector3(block.Data, 0);
11575 11953
11576 UpdateVector handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 11954 udata.change = ObjectChangeType.groupR;
11577 if (handlerUpdatePrimGroupScale != null) 11955 updatehandler(localId, udata, this);
11578 { 11956 break;
11579 // m_log.Debug("new scale is " + scale7.X + " , " + scale7.Y + " , " + scale7.Z);
11580 handlerUpdatePrimGroupScale(localId, scale7, this);
11581 }
11582 break;
11583 11957
11584 case 13: 11958 case 0x0B: //( 8 + 2 + 1) group rotation and position
11585 Vector3 scale2 = new Vector3(block.Data, 12); 11959 udata.position = new Vector3(block.Data, 0);
11586 Vector3 pos4 = new Vector3(block.Data, 0); 11960 udata.rotation = new Quaternion(block.Data, 12, true);
11587 11961
11588 handlerUpdatePrimScale = OnUpdatePrimScale; 11962 udata.change = ObjectChangeType.groupPR;
11589 if (handlerUpdatePrimScale != null) 11963 updatehandler(localId, udata, this);
11590 { 11964 break;
11591 //m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11592 handlerUpdatePrimScale(localId, scale2, this);
11593 11965
11594 // Change the position based on scale (for bug number 246) 11966 case 0x0C: // (8 + 4) group scale
11595 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11967 // only afects root prim and only sent by viewer editor object tab scaling
11596 // m_log.Debug("new movement position is " + pos.X + " , " + pos.Y + " , " + pos.Z); 11968 // mouse edition only allows uniform scaling
11597 if (handlerUpdatePrimSinglePosition != null) 11969 // SL MAY CHANGE THIS in viewers
11598 {
11599 handlerUpdatePrimSinglePosition(localId, pos4, this);
11600 }
11601 }
11602 break;
11603 11970
11604 case 29: 11971 udata.scale = new Vector3(block.Data, 0);
11605 Vector3 scale5 = new Vector3(block.Data, 12);
11606 Vector3 pos5 = new Vector3(block.Data, 0);
11607 11972
11608 handlerUpdatePrimGroupScale = OnUpdatePrimGroupScale; 11973 udata.change = ObjectChangeType.groupS;
11609 if (handlerUpdatePrimGroupScale != null) 11974 updatehandler(localId, udata, this);
11610 {
11611 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z);
11612 part.StoreUndoState(true);
11613 part.IgnoreUndoUpdate = true;
11614 handlerUpdatePrimGroupScale(localId, scale5, this);
11615 handlerUpdateVector = OnUpdatePrimGroupPosition;
11616 11975
11617 if (handlerUpdateVector != null) 11976 break;
11618 {
11619 handlerUpdateVector(localId, pos5, this);
11620 }
11621 11977
11622 part.IgnoreUndoUpdate = false; 11978 case 0x0D: //(8 + 4 + 1) group scale and position
11623 } 11979 // exception as above
11624 11980
11625 break; 11981 udata.position = new Vector3(block.Data, 0);
11982 udata.scale = new Vector3(block.Data, 12);
11626 11983
11627 case 21: 11984 udata.change = ObjectChangeType.groupPS;
11628 Vector3 scale6 = new Vector3(block.Data, 12); 11985 updatehandler(localId, udata, this);
11629 Vector3 pos6 = new Vector3(block.Data, 0); 11986 break;
11630 11987
11631 handlerUpdatePrimScale = OnUpdatePrimScale; 11988 case 0x1C: // (0x10 + 8 + 4 ) group scale UNIFORM
11632 if (handlerUpdatePrimScale != null) 11989 udata.scale = new Vector3(block.Data, 0);
11633 {
11634 part.StoreUndoState(false);
11635 part.IgnoreUndoUpdate = true;
11636 11990
11637 // m_log.Debug("new scale is " + scale.X + " , " + scale.Y + " , " + scale.Z); 11991 udata.change = ObjectChangeType.groupUS;
11638 handlerUpdatePrimScale(localId, scale6, this); 11992 updatehandler(localId, udata, this);
11639 handlerUpdatePrimSinglePosition = OnUpdatePrimSinglePosition; 11993 break;
11640 if (handlerUpdatePrimSinglePosition != null)
11641 {
11642 handlerUpdatePrimSinglePosition(localId, pos6, this);
11643 }
11644 11994
11645 part.IgnoreUndoUpdate = false; 11995 case 0x1D: // (UNIFORM + GROUP + SCALE + POS)
11646 } 11996 udata.position = new Vector3(block.Data, 0);
11647 break; 11997 udata.scale = new Vector3(block.Data, 12);
11648 11998
11649 default: 11999 udata.change = ObjectChangeType.groupPUS;
11650 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type)); 12000 updatehandler(localId, udata, this);
11651 break; 12001 break;
12002
12003 default:
12004 m_log.Debug("[CLIENT]: MultipleObjUpdate recieved an unknown packet type: " + (block.Type));
12005 break;
12006 }
11652 } 12007 }
11653 12008
11654// for (int j = 0; j < parts.Length; j++)
11655// parts[j].IgnoreUndoUpdate = false;
11656 } 12009 }
11657 } 12010 }
11658 } 12011 }
11659
11660 return true; 12012 return true;
11661 } 12013 }
11662 12014
@@ -11717,9 +12069,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11717 public void SetChildAgentThrottle(byte[] throttles) 12069 public void SetChildAgentThrottle(byte[] throttles)
11718 { 12070 {
11719 m_udpClient.SetThrottles(throttles); 12071 m_udpClient.SetThrottles(throttles);
12072 GenericCall2 handler = OnUpdateThrottles;
12073 if (handler != null)
12074 {
12075 handler();
12076 }
11720 } 12077 }
11721 12078
11722 /// <summary> 12079 /// <summary>
12080 /// Sets the throttles from values supplied by the client
12081 /// </summary>
12082 /// <param name="throttles"></param>
12083 public void SetAgentThrottleSilent(int throttle, int setting)
12084 {
12085 m_udpClient.ForceThrottleSetting(throttle,setting);
12086 //m_udpClient.SetThrottles(throttles);
12087
12088 }
12089
12090
12091 /// <summary>
11723 /// Get the current throttles for this client as a packed byte array 12092 /// Get the current throttles for this client as a packed byte array
11724 /// </summary> 12093 /// </summary>
11725 /// <param name="multiplier">Unused</param> 12094 /// <param name="multiplier">Unused</param>
@@ -12106,7 +12475,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12106// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", 12475// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
12107// requestID, taskID, (SourceType)sourceType, Name); 12476// requestID, taskID, (SourceType)sourceType, Name);
12108 12477
12478
12479 //Note, the bool returned from the below function is useless since it is always false.
12109 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12480 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12481
12110 } 12482 }
12111 12483
12112 /// <summary> 12484 /// <summary>
@@ -12172,7 +12544,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12172 /// <returns></returns> 12544 /// <returns></returns>
12173 private static int CalculateNumPackets(byte[] data) 12545 private static int CalculateNumPackets(byte[] data)
12174 { 12546 {
12175 const uint m_maxPacketSize = 600; 12547// const uint m_maxPacketSize = 600;
12548 uint m_maxPacketSize = MaxTransferBytesPerPacket;
12176 int numPackets = 1; 12549 int numPackets = 1;
12177 12550
12178 if (data == null) 12551 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 a7628d2..6c72edc 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>
@@ -800,6 +803,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
800 803
801 #region Queue or Send 804 #region Queue or Send
802 805
806 bool highPriority = false;
807
808 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
809 {
810 category = (ThrottleOutPacketType)((int)category & 127);
811 highPriority = true;
812 }
813
803 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 814 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
804 // If we were not provided a method for handling unacked, use the UDPServer default method 815 // If we were not provided a method for handling unacked, use the UDPServer default method
805 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 816 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
@@ -808,7 +819,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
808 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 819 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
809 // packet so that it isn't sent before a queued update packet. 820 // packet so that it isn't sent before a queued update packet.
810 bool requestQueue = type == PacketType.KillObject; 821 bool requestQueue = type == PacketType.KillObject;
811 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) 822 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
812 SendPacketFinal(outgoingPacket); 823 SendPacketFinal(outgoingPacket);
813 824
814 #endregion Queue or Send 825 #endregion Queue or Send
@@ -1093,21 +1104,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1093 1104
1094 #region Packet to Client Mapping 1105 #region Packet to Client Mapping
1095 1106
1096 // UseCircuitCode handling 1107 // If there is already a client for this endpoint, don't process UseCircuitCode
1097 if (packet.Type == PacketType.UseCircuitCode) 1108 IClientAPI client = null;
1109 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1098 { 1110 {
1099 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1111 // UseCircuitCode handling
1100 // buffer. 1112 if (packet.Type == PacketType.UseCircuitCode)
1101 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1113 {
1114 // And if there is a UseCircuitCode pending, also drop it
1115 lock (m_pendingCache)
1116 {
1117 if (m_pendingCache.Contains(endPoint))
1118 return;
1119
1120 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1121 }
1102 1122
1103 Util.FireAndForget(HandleUseCircuitCode, array); 1123 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1124 // buffer.
1125 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1104 1126
1105 return; 1127 Util.FireAndForget(HandleUseCircuitCode, array);
1128
1129 return;
1130 }
1131 }
1132
1133 // If this is a pending connection, enqueue, don't process yet
1134 lock (m_pendingCache)
1135 {
1136 Queue<UDPPacketBuffer> queue;
1137 if (m_pendingCache.TryGetValue(endPoint, out queue))
1138 {
1139 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1140 queue.Enqueue(buffer);
1141 return;
1142 }
1106 } 1143 }
1107 1144
1108 // Determine which agent this packet came from 1145 // Determine which agent this packet came from
1109 IClientAPI client; 1146 if (client == null || !(client is LLClientView))
1110 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1111 { 1147 {
1112 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1148 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1113 return; 1149 return;
@@ -1116,7 +1152,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1116 udpClient = ((LLClientView)client).UDPClient; 1152 udpClient = ((LLClientView)client).UDPClient;
1117 1153
1118 if (!udpClient.IsConnected) 1154 if (!udpClient.IsConnected)
1155 {
1156// m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + m_scene.RegionInfo.RegionName);
1119 return; 1157 return;
1158 }
1120 1159
1121 #endregion Packet to Client Mapping 1160 #endregion Packet to Client Mapping
1122 1161
@@ -1246,7 +1285,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1246 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1285 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1247 } 1286 }
1248 1287
1249 packetInbox.Enqueue(incomingPacket); 1288 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1289 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1290 packetInbox.EnqueueHigh(incomingPacket);
1291 else
1292 packetInbox.EnqueueLow(incomingPacket);
1250 } 1293 }
1251 1294
1252 #region BinaryStats 1295 #region BinaryStats
@@ -1366,6 +1409,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1366 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1409 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1367 if (client != null) 1410 if (client != null)
1368 client.SceneAgent.SendInitialDataToMe(); 1411 client.SceneAgent.SendInitialDataToMe();
1412
1413 // Now we know we can handle more data
1414 Thread.Sleep(200);
1415
1416 // Obtain the queue and remove it from the cache
1417 Queue<UDPPacketBuffer> queue = null;
1418
1419 lock (m_pendingCache)
1420 {
1421 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1422 {
1423 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1424 return;
1425 }
1426 m_pendingCache.Remove(endPoint);
1427 }
1428
1429 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1430
1431 // Reinject queued packets
1432 while(queue.Count > 0)
1433 {
1434 UDPPacketBuffer buf = queue.Dequeue();
1435 PacketReceived(buf);
1436 }
1437 queue = null;
1369 } 1438 }
1370 else 1439 else
1371 { 1440 {
@@ -1373,6 +1442,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1373 m_log.WarnFormat( 1442 m_log.WarnFormat(
1374 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1443 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1375 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1444 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1445 lock (m_pendingCache)
1446 m_pendingCache.Remove(endPoint);
1376 } 1447 }
1377 1448
1378 // m_log.DebugFormat( 1449 // m_log.DebugFormat(
@@ -1491,7 +1562,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1491 if (!client.SceneAgent.IsChildAgent) 1562 if (!client.SceneAgent.IsChildAgent)
1492 client.Kick("Simulator logged you out due to connection timeout"); 1563 client.Kick("Simulator logged you out due to connection timeout");
1493 1564
1494 client.CloseWithoutChecks(); 1565 client.CloseWithoutChecks(true);
1495 } 1566 }
1496 } 1567 }
1497 1568
@@ -1503,6 +1574,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1503 1574
1504 while (IsRunningInbound) 1575 while (IsRunningInbound)
1505 { 1576 {
1577 m_scene.ThreadAlive(1);
1506 try 1578 try
1507 { 1579 {
1508 IncomingPacket incomingPacket = null; 1580 IncomingPacket incomingPacket = null;
@@ -1550,6 +1622,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1550 1622
1551 while (base.IsRunningOutbound) 1623 while (base.IsRunningOutbound)
1552 { 1624 {
1625 m_scene.ThreadAlive(2);
1553 try 1626 try
1554 { 1627 {
1555 m_packetSent = false; 1628 m_packetSent = false;
@@ -1780,8 +1853,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1780 Packet packet = incomingPacket.Packet; 1853 Packet packet = incomingPacket.Packet;
1781 LLClientView client = incomingPacket.Client; 1854 LLClientView client = incomingPacket.Client;
1782 1855
1783 if (client.IsActive) 1856// if (client.IsActive)
1784 { 1857// {
1785 m_currentIncomingClient = client; 1858 m_currentIncomingClient = client;
1786 1859
1787 try 1860 try
@@ -1808,13 +1881,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1808 { 1881 {
1809 m_currentIncomingClient = null; 1882 m_currentIncomingClient = null;
1810 } 1883 }
1811 } 1884// }
1812 else 1885// else
1813 { 1886// {
1814 m_log.DebugFormat( 1887// m_log.DebugFormat(
1815 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1888// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1816 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1889// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1817 } 1890// }
1818 1891
1819 IncomingPacketsProcessed++; 1892 IncomingPacketsProcessed++;
1820 } 1893 }
@@ -1826,8 +1899,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1826 if (!client.IsLoggingOut) 1899 if (!client.IsLoggingOut)
1827 { 1900 {
1828 client.IsLoggingOut = true; 1901 client.IsLoggingOut = true;
1829 client.Close(); 1902 client.Close(false, false);
1903 }
1904 }
1905 }
1906
1907 internal class DoubleQueue<T> where T:class
1908 {
1909 private Queue<T> m_lowQueue = new Queue<T>();
1910 private Queue<T> m_highQueue = new Queue<T>();
1911
1912 private object m_syncRoot = new object();
1913 private Semaphore m_s = new Semaphore(0, 1);
1914
1915 public DoubleQueue()
1916 {
1917 }
1918
1919 public virtual int Count
1920 {
1921 get { return m_highQueue.Count + m_lowQueue.Count; }
1922 }
1923
1924 public virtual void Enqueue(T data)
1925 {
1926 Enqueue(m_lowQueue, data);
1927 }
1928
1929 public virtual void EnqueueLow(T data)
1930 {
1931 Enqueue(m_lowQueue, data);
1932 }
1933
1934 public virtual void EnqueueHigh(T data)
1935 {
1936 Enqueue(m_highQueue, data);
1937 }
1938
1939 private void Enqueue(Queue<T> q, T data)
1940 {
1941 lock (m_syncRoot)
1942 {
1943 m_lowQueue.Enqueue(data);
1944 m_s.WaitOne(0);
1945 m_s.Release();
1946 }
1947 }
1948
1949 public virtual T Dequeue()
1950 {
1951 return Dequeue(Timeout.Infinite);
1952 }
1953
1954 public virtual T Dequeue(int tmo)
1955 {
1956 return Dequeue(TimeSpan.FromMilliseconds(tmo));
1957 }
1958
1959 public virtual T Dequeue(TimeSpan wait)
1960 {
1961 T res = null;
1962
1963 if (!Dequeue(wait, ref res))
1964 return null;
1965
1966 return res;
1967 }
1968
1969 public bool Dequeue(int timeout, ref T res)
1970 {
1971 return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
1972 }
1973
1974 public bool Dequeue(TimeSpan wait, ref T res)
1975 {
1976 if (!m_s.WaitOne(wait))
1977 return false;
1978
1979 lock (m_syncRoot)
1980 {
1981 if (m_highQueue.Count > 0)
1982 res = m_highQueue.Dequeue();
1983 else
1984 res = m_lowQueue.Dequeue();
1985
1986 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
1987 return true;
1988
1989 try
1990 {
1991 m_s.Release();
1992 }
1993 catch
1994 {
1995 }
1996
1997 return true;
1998 }
1999 }
2000
2001 public virtual void Clear()
2002 {
2003
2004 lock (m_syncRoot)
2005 {
2006 // Make sure sem count is 0
2007 m_s.WaitOne(0);
2008
2009 m_lowQueue.Clear();
2010 m_highQueue.Clear();
1830 } 2011 }
1831 } 2012 }
1832 } 2013 }
1833} \ No newline at end of file 2014}
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,